]> git.ipfire.org Git - thirdparty/pdns.git/commitdiff
dnsdist: consistent hash - get rid of intermediate map construction
authorCharles-Henri Bruyand <charles-henri.bruyand@open-xchange.com>
Tue, 19 Jun 2018 14:05:46 +0000 (16:05 +0200)
committerCharles-Henri Bruyand <charles-henri.bruyand@open-xchange.com>
Tue, 19 Jun 2018 14:05:46 +0000 (16:05 +0200)
pdns/dnsdist.cc

index a319d01f3782e9bce0d3a713f5b88d5c1d3a9b7a..f7500f8f4b9fb300a22b3c250a8d0bbb87bfb339 100644 (file)
@@ -754,44 +754,48 @@ shared_ptr<DownstreamState> whashed(const NumberedServerVector& servers, const D
   return valrandom(dq->qname->hash(g_hashperturb), servers, dq);
 }
 
-/*
- * @todo
- * - test/benchmark other hashing methods
- * - test/benchmark adding an avalanche algorithm on hashes
- * @see https://github.com/haproxy/haproxy/blob/master/doc/internals/hashing.txt
- */
-
 shared_ptr<DownstreamState> chashed(const NumberedServerVector& servers, const DNSQuestion* dq)
 {
   std::map<unsigned int, shared_ptr<DownstreamState>> circle = {};
   unsigned int qhash = dq->qname->hash(g_hashperturb);
+  unsigned int sel = 0, max = 0;
+  shared_ptr<DownstreamState> ret = nullptr, last = nullptr;
 
   for (const auto& d: servers) {
     if (d.second->isUp()) {
+      // make sure hashes have been computed
       if (d.second->hashes.empty()) {
         d.second->hash();
       }
       {
         ReadLock rl(&(d.second->d_lock));
-        for (const auto& h: d.second->hashes) {
-          // put server's hashes on the circle
-          circle.insert(std::make_pair(h, d.second));
+        const auto& server = d.second;
+        // we want to keep track of the last hash
+        if (max < *(server->hashes.rbegin())) {
+          max = *(server->hashes.rbegin());
+          last = server;
+        }
+        auto hash_it = server->hashes.begin();
+        while (hash_it != server->hashes.end()
+               && *hash_it < qhash) {
+          if (*hash_it > sel) {
+            sel = *hash_it;
+            ret = server;
+          }
+          ++hash_it;
         }
       }
     }
   }
-  if (circle.empty()) {
-    return shared_ptr<DownstreamState>();
+  if (ret != nullptr) {
+    return ret;
   }
-
-  auto p = circle.upper_bound(qhash);
-  if(p == circle.end()) {
-    return circle.begin()->second;
+  if (last != nullptr) {
+    return last;
   }
-  return p->second;
+  return shared_ptr<DownstreamState>();
 }
 
-
 shared_ptr<DownstreamState> roundrobin(const NumberedServerVector& servers, const DNSQuestion* dq)
 {
   NumberedServerVector poss;