From: bert hubert Date: Wed, 9 Sep 2015 09:17:45 +0000 (+0200) Subject: Port the 0x20 hashing to 3.7.3 X-Git-Tag: rec-3.7.4~12^2 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=ef49a7cc45f3b9bbacfcfc79d329eacbe771e105;p=pdns Port the 0x20 hashing to 3.7.3 This is a combination of the commits: - 6200227b6b3cfd8796d6cc75e8cf29bcec586f0c - af891b3d6d3f6ee6e848411cc9e477c96e955f98 And a port of the testcase --- diff --git a/pdns/dns.cc b/pdns/dns.cc index 1678f7072..41da1ba36 100644 --- a/pdns/dns.cc +++ b/pdns/dns.cc @@ -142,7 +142,7 @@ uint32_t hashQuestion(const char* packet, uint16_t len, uint32_t init) while((labellen=*pos++) && pos < end) { if(pos + labellen + 1 > end) // include length field in hash return 0; - ret=burtle(pos, labellen+1, ret); + ret=burtleCI(pos, labellen+1, ret); pos += labellen; } return ret; diff --git a/pdns/misc.cc b/pdns/misc.cc index 01529cf05..5dc51c39b 100644 --- a/pdns/misc.cc +++ b/pdns/misc.cc @@ -911,6 +911,47 @@ uint32_t burtle(const unsigned char* k, uint32_t length, uint32_t initval) return c; } +uint32_t burtleCI(const unsigned char* k, uint32_t length, uint32_t initval) +{ + uint32_t a,b,c,len; + + /* Set up the internal state */ + len = length; + a = b = 0x9e3779b9; /* the golden ratio; an arbitrary value */ + c = initval; /* the previous hash value */ + + /*---------------------------------------- handle most of the key */ + while (len >= 12) { + a += (dns_tolower(k[0]) +((uint32_t)dns_tolower(k[1])<<8) +((uint32_t)dns_tolower(k[2])<<16) +((uint32_t)dns_tolower(k[3])<<24)); + b += (dns_tolower(k[4]) +((uint32_t)dns_tolower(k[5])<<8) +((uint32_t)dns_tolower(k[6])<<16) +((uint32_t)dns_tolower(k[7])<<24)); + c += (dns_tolower(k[8]) +((uint32_t)dns_tolower(k[9])<<8) +((uint32_t)dns_tolower(k[10])<<16)+((uint32_t)dns_tolower(k[11])<<24)); + burtlemix(a,b,c); + k += 12; len -= 12; + } + + /*------------------------------------- handle the last 11 bytes */ + c += length; + switch(len) { /* all the case statements fall through */ + case 11: c+=((uint32_t)dns_tolower(k[10])<<24); + case 10: c+=((uint32_t)dns_tolower(k[9])<<16); + case 9 : c+=((uint32_t)dns_tolower(k[8])<<8); + /* the first byte of c is reserved for the length */ + case 8 : b+=((uint32_t)dns_tolower(k[7])<<24); + case 7 : b+=((uint32_t)dns_tolower(k[6])<<16); + case 6 : b+=((uint32_t)dns_tolower(k[5])<<8); + case 5 : b+=dns_tolower(k[4]); + case 4 : a+=((uint32_t)dns_tolower(k[3])<<24); + case 3 : a+=((uint32_t)dns_tolower(k[2])<<16); + case 2 : a+=((uint32_t)dns_tolower(k[1])<<8); + case 1 : a+=dns_tolower(k[0]); + /* case 0: nothing left to add */ + } + burtlemix(a,b,c); + /*-------------------------------------------- report the result */ + return c; +} + + void setSocketTimestamps(int fd) { #ifdef SO_TIMESTAMP diff --git a/pdns/misc.hh b/pdns/misc.hh index 515e35fe5..dcf7ba561 100644 --- a/pdns/misc.hh +++ b/pdns/misc.hh @@ -544,5 +544,6 @@ unsigned int getFilenumLimit(bool hardOrSoft=0); void setFilenumLimit(unsigned int lim); bool readFileIfThere(const char* fname, std::string* line); uint32_t burtle(const unsigned char* k, uint32_t lengh, uint32_t init); +uint32_t burtleCI(const unsigned char* k, uint32_t lengh, uint32_t init); void setSocketTimestamps(int fd); #endif diff --git a/pdns/test-misc_hh.cc b/pdns/test-misc_hh.cc index 8732264f3..22739a836 100644 --- a/pdns/test-misc_hh.cc +++ b/pdns/test-misc_hh.cc @@ -5,8 +5,11 @@ #include #include #include +#include #include "misc.hh" #include "dns.hh" +#include "dnswriter.hh" +#include "dnsrecords.hh" #include using std::string; @@ -119,6 +122,40 @@ BOOST_AUTO_TEST_CASE(test_AtomicCounter) { BOOST_CHECK_EQUAL(ac, 2); } +BOOST_AUTO_TEST_CASE(test_QuestionHash) { + vector packet; + reportBasicTypes(); + DNSPacketWriter dpw1(packet, "www.ds9a.nl.", QType::AAAA); + + uint32_t hash1=hashQuestion((char*)&packet[0], packet.size(), 0); + DNSPacketWriter dpw2(packet, "wWw.Ds9A.nL.", QType::AAAA); + uint32_t hash2=hashQuestion((char*)&packet[0], packet.size(), 0); + BOOST_CHECK_EQUAL(hash1, hash2); + + vector counts(1500); + + for(unsigned int n=0; n < 100000; ++n) { + packet.clear(); + DNSPacketWriter dpw1(packet, lexical_cast(n)+"."+lexical_cast(n*2)+".", QType::AAAA); + counts[hashQuestion((char*)&packet[0], packet.size(), 0) % counts.size()]++; + } + + double sum = 0.0; + BOOST_FOREACH(double d, counts){ + sum += d; + } + + double m = sum / counts.size(); + + double accum = 0.0; + BOOST_FOREACH(double d, counts) { + accum += (d - m) * (d - m); + }; + + double stdev = sqrt(accum / (counts.size()-1)); + BOOST_CHECK(stdev < 10); +} + BOOST_AUTO_TEST_CASE(test_endianness) { uint32_t i = 1; #if BYTE_ORDER == BIG_ENDIAN