From b4b39f52dc9f2d5466e0ef3f8932379907331468 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Adrien=20B=C3=A9raud?= <adrien.beraud@savoirfairelinux.com>
Date: Fri, 3 Jun 2016 17:20:52 -0400
Subject: [PATCH] dht: new insertNode algorithm

---
 src/dht.cpp | 85 ++++++++++++++++++++++++++++++++---------------------
 1 file changed, 51 insertions(+), 34 deletions(-)

diff --git a/src/dht.cpp b/src/dht.cpp
index d2cc5376..5fcaf525 100644
--- a/src/dht.cpp
+++ b/src/dht.cpp
@@ -163,6 +163,7 @@ private:
 
 
 struct Dht::SearchNode {
+    SearchNode() : node() {}
     SearchNode(std::shared_ptr<Node> node) : node(node) {}
 
     using AnnounceStatusMap = std::map<Value::Id, std::shared_ptr<Request>>;
@@ -576,31 +577,50 @@ Dht::Search::insertNode(const std::shared_ptr<Node>& snode, time_point now, cons
     auto& node = *snode;
     const auto& nid = node.id;
 
-    if (node.getFamily() != af) {
-        //DHT_LOG.DEBUG("Attempted to insert node in the wrong family.");
-        return false;
-    }
-
-    // Fast track for the case where the node is not relevant for this search
-    if (node.isExpired() && nodes.size() >= SEARCH_NODES && id.xorCmp(nid, nodes.back().node->id) > 0)
+    if (node.getFamily() != af)
         return false;
 
     bool found = false;
-    auto n = std::find_if(nodes.begin(), nodes.end(), [&](const SearchNode& sn) {
-        if (sn.node == snode) {
+    auto n = nodes.end();
+    while (n != nodes.begin()) {
+        --n;
+        if (n->node == snode) {
             found = true;
-            return true;
+            break;
         }
-        return id.xorCmp(nid, sn.node->id) < 0;
-    });
+        if (id.xorCmp(nid, n->node->id) > 0) {
+            ++n;
+            break;
+        }
+    }
 
     bool new_search_node = false;
     if (!found) {
-        // Be more restricitve if there are too many
-        // good or unknown nodes in this search,
-        unsigned num_bad_nodes = getNumberOfBadNodes();
-        if (nodes.size() - num_bad_nodes >= SEARCH_NODES) {
-            if (node.isExpired() or n == nodes.end())
+        // find if and where to trim excessive nodes
+        auto t = nodes.cend();
+        size_t bad = 0;     // number of bad nodes (if search is not expired)
+        bool full {false};  // is the search full (has the maximum nodes)
+        if (expired) {
+            // if the search is expired, trim to SEARCH_NODES nodes
+            if (nodes.size() >= SEARCH_NODES) {
+                full = true;
+                t = nodes.begin() + SEARCH_NODES;
+            }
+        } else {
+            // otherwise, trim to SEARCH_NODES nodes, not counting bad nodes
+            bad = getNumberOfBadNodes();
+            full = nodes.size() - bad >=  SEARCH_NODES;
+            while (std::distance(nodes.cbegin(), t) - bad >  SEARCH_NODES) {
+                --t;
+                if (t->isBad())
+                    bad--;
+            }
+        }
+
+        if (full) {
+            if (t != nodes.cend())
+                nodes.resize(std::distance(nodes.cbegin(), t));
+            if (n >= t)
                 return false;
         }
 
@@ -608,24 +628,22 @@ Dht::Search::insertNode(const std::shared_ptr<Node>& snode, time_point now, cons
         if (nodes.empty()) {
             step_time = TIME_INVALID;
         }
-
         n = nodes.insert(n, SearchNode(snode));
         node.time = now;
         new_search_node = true;
+        if (node.isExpired()) {
+            if (not expired)
+                bad++;
+        } else if (expired) {
+            bad = nodes.size() - 1;
+            expired = false;
+        }
 
-        // trim good nodes
-        while (nodes.size() - num_bad_nodes > SEARCH_NODES) {
-            if (removeExpiredNode(now))
-                num_bad_nodes--;
-
-            auto to_remove = std::find_if(nodes.rbegin(), nodes.rend(),
-                [](const SearchNode& n) { return not n.isBad(); }
-            );
-            if (to_remove != nodes.rend()) {
-                nodes.erase(std::prev(to_remove.base()));
-            } // else, all nodes are expired.
+        while (nodes.size() - bad >  SEARCH_NODES) {
+            if (not expired and nodes.back().isBad())
+                bad--;
+            nodes.pop_back();
         }
-        expired = false;
     }
     if (not token.empty()) {
         n->candidate = false;
@@ -634,6 +652,9 @@ Dht::Search::insertNode(const std::shared_ptr<Node>& snode, time_point now, cons
             n->token = token;
         expired = false;
     }
+    if (new_search_node) {
+        removeExpiredNode(now);
+    }
     return new_search_node;
 }
 
@@ -729,10 +750,6 @@ Dht::searchStep(std::shared_ptr<Search> sr)
     DHT_LOG.DEBUG("[search %s IPv%c] step (%d requests)", sr->id.toString().c_str(), sr->af == AF_INET ? '4' : '6', sr->currentGetRequests());
     sr->step_time = now;
 
-    /*
-     * The accurate delay between two refills has not been strongly determined.
-     * TODO: Emprical analysis over refill timeout.
-     */
     if (sr->refill_time + Node::NODE_EXPIRE_TIME < now and sr->nodes.size()-sr->getNumberOfBadNodes() < SEARCH_NODES) {
         if (auto added = sr->refill(sr->af == AF_INET ? buckets : buckets6, now)) {
             sr->refill_time = now;
-- 
GitLab