From eb59c4ca8e8be07c587f1cbcb252153b97f08dcc Mon Sep 17 00:00:00 2001 From: Matt Corallo Date: Wed, 27 Mar 2013 11:34:23 -0400 Subject: [PATCH 1/3] Revert "Actually use mapAlreadyAskedFor." This reverts commit 643160f6e7e5e8ca84bc7d2c1a0f37d9cf43a6e1. Turns out this commit was useless after a more careful reading of CNode::AskFor --- src/main.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main.cpp b/src/main.cpp index b29091b4f..ee2575298 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -3994,7 +3994,6 @@ bool SendMessages(CNode* pto, bool fSendTrickle) pto->PushMessage("getdata", vGetData); vGetData.clear(); } - mapAlreadyAskedFor[inv] = nNow; } pto->mapAskFor.erase(pto->mapAskFor.begin()); } From 5ffc299404f4bcce3b9b2522096f8ed53d3181d5 Mon Sep 17 00:00:00 2001 From: Matt Corallo Date: Wed, 27 Mar 2013 01:07:20 -0400 Subject: [PATCH 2/3] Add a limitedmap class similar to mruset --- src/limitedmap.h | 100 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 100 insertions(+) create mode 100644 src/limitedmap.h diff --git a/src/limitedmap.h b/src/limitedmap.h new file mode 100644 index 000000000..7049d68e5 --- /dev/null +++ b/src/limitedmap.h @@ -0,0 +1,100 @@ +// Copyright (c) 2012 The Bitcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. +#ifndef BITCOIN_LIMITEDMAP_H +#define BITCOIN_LIMITEDMAP_H + +#include +#include + +/** STL-like map container that only keeps the N elements with the highest value. */ +template class limitedmap +{ +public: + typedef K key_type; + typedef V mapped_type; + typedef std::pair value_type; + typedef typename std::map::const_iterator const_iterator; + typedef typename std::map::size_type size_type; + +protected: + std::map map; + typedef typename std::map::iterator iterator; + std::multimap rmap; + typedef typename std::multimap::iterator rmap_iterator; + size_type nMaxSize; + +public: + limitedmap(size_type nMaxSizeIn = 0) { nMaxSize = nMaxSizeIn; } + const_iterator begin() const { return map.begin(); } + const_iterator end() const { return map.end(); } + size_type size() const { return map.size(); } + bool empty() const { return map.empty(); } + const_iterator find(const key_type& k) const { return map.find(k); } + size_type count(const key_type& k) const { return map.count(k); } + void insert(const value_type& x) + { + std::pair ret = map.insert(x); + if (ret.second) + { + if (nMaxSize && map.size() == nMaxSize) + { + map.erase(rmap.begin()->second); + rmap.erase(rmap.begin()); + } + rmap.insert(make_pair(x.second, ret.first)); + } + return; + } + void erase(const key_type& k) + { + iterator itTarget = map.find(k); + if (itTarget == map.end()) + return; + std::pair itPair = rmap.equal_range(itTarget->second); + for (rmap_iterator it = itPair.first; it != itPair.second; ++it) + if (it->second == itTarget) + { + rmap.erase(it); + map.erase(itTarget); + return; + } + // Shouldn't ever get here + assert(0); //TODO remove me + map.erase(itTarget); + } + void update(const_iterator itIn, const mapped_type& v) + { + //TODO: When we switch to C++11, use map.erase(itIn, itIn) to get the non-const iterator + iterator itTarget = map.find(itIn->first); + if (itTarget == map.end()) + return; + std::pair itPair = rmap.equal_range(itTarget->second); + for (rmap_iterator it = itPair.first; it != itPair.second; ++it) + if (it->second == itTarget) + { + rmap.erase(it); + itTarget->second = v; + rmap.insert(make_pair(v, itTarget)); + return; + } + // Shouldn't ever get here + assert(0); //TODO remove me + itTarget->second = v; + rmap.insert(make_pair(v, itTarget)); + } + size_type max_size() const { return nMaxSize; } + size_type max_size(size_type s) + { + if (s) + while (map.size() > s) + { + map.erase(rmap.begin()->second); + rmap.erase(rmap.begin()); + } + nMaxSize = s; + return nMaxSize; + } +}; + +#endif From b5afda67f2846ddc6554304acc1567796733725b Mon Sep 17 00:00:00 2001 From: Matt Corallo Date: Wed, 27 Mar 2013 19:45:43 -0400 Subject: [PATCH 3/3] Move mapAlreadyAskedFor to limitedmap This will result in re-requesting invs if we are under heavy inv load, however as long as we get no more than 16,000 invs in two minutes, this should have no effect on runtime behavior. --- src/net.cpp | 2 +- src/net.h | 14 ++++++++++++-- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/src/net.cpp b/src/net.cpp index 9ee6cb423..926d57026 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -63,7 +63,7 @@ CCriticalSection cs_vNodes; map mapRelay; deque > vRelayExpiration; CCriticalSection cs_mapRelay; -map mapAlreadyAskedFor; +limitedmap mapAlreadyAskedFor(MAX_INV_SZ); static deque vOneShots; CCriticalSection cs_vOneShots; diff --git a/src/net.h b/src/net.h index 368e4cd4b..9cbb593f5 100644 --- a/src/net.h +++ b/src/net.h @@ -15,6 +15,7 @@ #endif #include "mruset.h" +#include "limitedmap.h" #include "netbase.h" #include "protocol.h" #include "addrman.h" @@ -100,7 +101,7 @@ extern CCriticalSection cs_vNodes; extern std::map mapRelay; extern std::deque > vRelayExpiration; extern CCriticalSection cs_mapRelay; -extern std::map mapAlreadyAskedFor; +extern limitedmap mapAlreadyAskedFor; extern std::vector vAddedNodes; extern CCriticalSection cs_vAddedNodes; @@ -367,7 +368,12 @@ public: { // We're using mapAskFor as a priority queue, // the key is the earliest time the request can be sent - int64& nRequestTime = mapAlreadyAskedFor[inv]; + int64 nRequestTime; + limitedmap::const_iterator it = mapAlreadyAskedFor.find(inv); + if (it != mapAlreadyAskedFor.end()) + nRequestTime = it->second; + else + nRequestTime = 0; if (fDebugNet) printf("askfor %s %"PRI64d" (%s)\n", inv.ToString().c_str(), nRequestTime, DateTimeStrFormat("%H:%M:%S", nRequestTime/1000000).c_str()); @@ -380,6 +386,10 @@ public: // Each retry is 2 minutes after the last nRequestTime = std::max(nRequestTime + 2 * 60 * 1000000, nNow); + if (it != mapAlreadyAskedFor.end()) + mapAlreadyAskedFor.update(it, nRequestTime); + else + mapAlreadyAskedFor.insert(std::make_pair(inv, nRequestTime)); mapAskFor.insert(std::make_pair(nRequestTime, inv)); }