Browse Source

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)
0.13
Gavin Andresen 10 years ago committed by Pieter Wuille
parent
commit
d81cff32e5
  1. 10
      src/main.cpp
  2. 2
      src/net.cpp
  3. 6
      src/net.h

10
src/main.cpp

@ -3995,7 +3995,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
{ {
LOCK(cs_vNodes); LOCK(cs_vNodes);
// Use deterministic randomness to send to the same nodes for 24 hours // 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; static uint256 hashSalt;
if (hashSalt.IsNull()) if (hashSalt.IsNull())
hashSalt = GetRandHash(); hashSalt = GetRandHash();
@ -4779,9 +4779,9 @@ bool SendMessages(CNode* pto, bool fSendTrickle)
LOCK(cs_vNodes); LOCK(cs_vNodes);
BOOST_FOREACH(CNode* pnode, vNodes) BOOST_FOREACH(CNode* pnode, vNodes)
{ {
// Periodically clear setAddrKnown to allow refresh broadcasts // Periodically clear addrKnown to allow refresh broadcasts
if (nLastRebroadcast) if (nLastRebroadcast)
pnode->setAddrKnown.clear(); pnode->addrKnown.clear();
// Rebroadcast our address // Rebroadcast our address
AdvertizeLocal(pnode); AdvertizeLocal(pnode);
@ -4799,9 +4799,9 @@ bool SendMessages(CNode* pto, bool fSendTrickle)
vAddr.reserve(pto->vAddrToSend.size()); vAddr.reserve(pto->vAddrToSend.size());
BOOST_FOREACH(const CAddress& addr, pto->vAddrToSend) BOOST_FOREACH(const CAddress& addr, pto->vAddrToSend)
{ {
// returns true if wasn't already contained in the set if (!pto->addrKnown.contains(addr.GetKey()))
if (pto->setAddrKnown.insert(addr).second)
{ {
pto->addrKnown.insert(addr.GetKey());
vAddr.push_back(addr); vAddr.push_back(addr);
// receiver rejects addr messages larger than 1000 // receiver rejects addr messages larger than 1000
if (vAddr.size() >= 1000) if (vAddr.size() >= 1000)

2
src/net.cpp

@ -1905,7 +1905,7 @@ bool CAddrDB::Read(CAddrMan& addr)
unsigned int ReceiveFloodSize() { return 1000*GetArg("-maxreceivebuffer", 5*1000); } unsigned int ReceiveFloodSize() { return 1000*GetArg("-maxreceivebuffer", 5*1000); }
unsigned int SendBufferSize() { return 1000*GetArg("-maxsendbuffer", 1*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; nServices = 0;
hSocket = hSocketIn; hSocket = hSocketIn;

6
src/net.h

@ -300,7 +300,7 @@ public:
// flood relay // flood relay
std::vector<CAddress> vAddrToSend; std::vector<CAddress> vAddrToSend;
mruset<CAddress> setAddrKnown; CRollingBloomFilter addrKnown;
bool fGetAddr; bool fGetAddr;
std::set<uint256> setKnown; std::set<uint256> setKnown;
@ -380,7 +380,7 @@ public:
void AddAddressKnown(const CAddress& addr) void AddAddressKnown(const CAddress& addr)
{ {
setAddrKnown.insert(addr); addrKnown.insert(addr.GetKey());
} }
void PushAddress(const CAddress& addr) void PushAddress(const CAddress& addr)
@ -388,7 +388,7 @@ public:
// Known checking here is only to save space from duplicates. // Known checking here is only to save space from duplicates.
// SendMessages will filter it again for knowns that were added // SendMessages will filter it again for knowns that were added
// after addresses were pushed. // after addresses were pushed.
if (addr.IsValid() && !setAddrKnown.count(addr)) { if (addr.IsValid() && !addrKnown.contains(addr.GetKey())) {
if (vAddrToSend.size() >= MAX_ADDR_TO_SEND) { if (vAddrToSend.size() >= MAX_ADDR_TO_SEND) {
vAddrToSend[insecure_rand() % vAddrToSend.size()] = addr; vAddrToSend[insecure_rand() % vAddrToSend.size()] = addr;
} else { } else {

Loading…
Cancel
Save