From d81cff32e50fe5f686f985d0af2e74219f328ed0 Mon Sep 17 00:00:00 2001 From: Gavin Andresen Date: Sat, 25 Apr 2015 16:25:44 -0400 Subject: [PATCH] Replace mruset setAddrKnown with CRollingBloomFilter addrKnown Use a probabilistic bloom filter to keep track of which addresses we think we have given our peers, instead of a list. This uses much less memory, at the cost of sometimes failing to relay an address to a peer-- worst case if the bloom filter happens to be as full as it gets, 1-in-1,000. Measured memory usage of a full mruset setAddrKnown: 650Kbytes Constant memory usage of CRollingBloomFilter addrKnown: 37Kbytes. This will also help heap fragmentation, because the 37K of storage is allocated when a CNode is created (when a connection to a peer is established) and then there is no per-item-remembered memory allocation. I plan on testing by restarting a full node with an empty peers.dat, running a while with -debug=addrman and -debug=net, and making sure that the 'addr' message traffic out is reasonable. (suggestions for better tests welcome) --- src/main.cpp | 10 +++++----- src/net.cpp | 2 +- src/net.h | 6 +++--- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index e6248c661..a6b717d57 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -3995,7 +3995,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, { LOCK(cs_vNodes); // Use deterministic randomness to send to the same nodes for 24 hours - // at a time so the setAddrKnowns of the chosen nodes prevent repeats + // at a time so the addrKnowns of the chosen nodes prevent repeats static uint256 hashSalt; if (hashSalt.IsNull()) hashSalt = GetRandHash(); @@ -4779,9 +4779,9 @@ bool SendMessages(CNode* pto, bool fSendTrickle) LOCK(cs_vNodes); BOOST_FOREACH(CNode* pnode, vNodes) { - // Periodically clear setAddrKnown to allow refresh broadcasts + // Periodically clear addrKnown to allow refresh broadcasts if (nLastRebroadcast) - pnode->setAddrKnown.clear(); + pnode->addrKnown.clear(); // Rebroadcast our address AdvertizeLocal(pnode); @@ -4799,9 +4799,9 @@ bool SendMessages(CNode* pto, bool fSendTrickle) vAddr.reserve(pto->vAddrToSend.size()); BOOST_FOREACH(const CAddress& addr, pto->vAddrToSend) { - // returns true if wasn't already contained in the set - if (pto->setAddrKnown.insert(addr).second) + if (!pto->addrKnown.contains(addr.GetKey())) { + pto->addrKnown.insert(addr.GetKey()); vAddr.push_back(addr); // receiver rejects addr messages larger than 1000 if (vAddr.size() >= 1000) diff --git a/src/net.cpp b/src/net.cpp index 731c81093..4648dae11 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -1905,7 +1905,7 @@ bool CAddrDB::Read(CAddrMan& addr) unsigned int ReceiveFloodSize() { return 1000*GetArg("-maxreceivebuffer", 5*1000); } unsigned int SendBufferSize() { return 1000*GetArg("-maxsendbuffer", 1*1000); } -CNode::CNode(SOCKET hSocketIn, CAddress addrIn, std::string addrNameIn, bool fInboundIn) : ssSend(SER_NETWORK, INIT_PROTO_VERSION), setAddrKnown(5000) +CNode::CNode(SOCKET hSocketIn, CAddress addrIn, std::string addrNameIn, bool fInboundIn) : ssSend(SER_NETWORK, INIT_PROTO_VERSION), addrKnown(5000, 0.001, insecure_rand()) { nServices = 0; hSocket = hSocketIn; diff --git a/src/net.h b/src/net.h index 9fc6ce68d..24e927c9f 100644 --- a/src/net.h +++ b/src/net.h @@ -300,7 +300,7 @@ public: // flood relay std::vector vAddrToSend; - mruset setAddrKnown; + CRollingBloomFilter addrKnown; bool fGetAddr; std::set setKnown; @@ -380,7 +380,7 @@ public: void AddAddressKnown(const CAddress& addr) { - setAddrKnown.insert(addr); + addrKnown.insert(addr.GetKey()); } void PushAddress(const CAddress& addr) @@ -388,7 +388,7 @@ public: // Known checking here is only to save space from duplicates. // SendMessages will filter it again for knowns that were added // after addresses were pushed. - if (addr.IsValid() && !setAddrKnown.count(addr)) { + if (addr.IsValid() && !addrKnown.contains(addr.GetKey())) { if (vAddrToSend.size() >= MAX_ADDR_TO_SEND) { vAddrToSend[insecure_rand() % vAddrToSend.size()] = addr; } else {