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)
This commit is contained in:
parent
69a5f8be0a
commit
d81cff32e5
10
src/main.cpp
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)
|
||||||
|
@ -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;
|
||||||
|
@ -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…
Reference in New Issue
Block a user