net: Drop CNodeRef for AttemptToEvictConnection

Locking for each operation here is unnecessary, and solves the wrong problem.
Additionally, it introduces a problem when cs_vNodes is held in an owning
class, to which invididual CNodeRefs won't have access.

These should be weak pointers anyway, once vNodes contain shared pointers.

Rather than using a refcounting class, use a 3-step process instead.

1. Lock vNodes long enough to snapshot the fields necessary for comparing
2. Unlock and do the comparison
3. Re-lock and mark the resulting node for disconnection if it still exists

Zcash: add nVersion to NodeEvictionCandidate
This commit is contained in:
Cory Fields 2016-04-18 15:58:19 -04:00 committed by Kris Nuttycombe
parent c81adc3718
commit 686cdafa02
1 changed files with 41 additions and 56 deletions

View File

@ -713,51 +713,23 @@ void SocketSendData(CNode *pnode)
static list<CNode*> vNodesDisconnected; static list<CNode*> vNodesDisconnected;
class CNodeRef { struct NodeEvictionCandidate
public: {
CNodeRef(CNode *pnode) : _pnode(pnode) { NodeId id;
LOCK(cs_vNodes); int64_t nTimeConnected;
_pnode->AddRef(); int64_t nMinPingUsecTime;
} CAddress addr;
int nVersion;
~CNodeRef() {
LOCK(cs_vNodes);
_pnode->Release();
}
CNode& operator *() const {return *_pnode;};
CNode* operator ->() const {return _pnode;};
CNodeRef& operator =(const CNodeRef& other)
{
if (this != &other) {
LOCK(cs_vNodes);
_pnode->Release();
_pnode = other._pnode;
_pnode->AddRef();
}
return *this;
}
CNodeRef(const CNodeRef& other):
_pnode(other._pnode)
{
LOCK(cs_vNodes);
_pnode->AddRef();
}
private:
CNode *_pnode;
}; };
static bool ReverseCompareNodeMinPingTime(const CNodeRef &a, const CNodeRef &b) static bool ReverseCompareNodeMinPingTime(const NodeEvictionCandidate &a, const NodeEvictionCandidate &b)
{ {
return a->nMinPingUsecTime > b->nMinPingUsecTime; return a.nMinPingUsecTime > b.nMinPingUsecTime;
} }
static bool ReverseCompareNodeTimeConnected(const CNodeRef &a, const CNodeRef &b) static bool ReverseCompareNodeTimeConnected(const NodeEvictionCandidate &a, const NodeEvictionCandidate &b)
{ {
return a->nTimeConnected > b->nTimeConnected; return a.nTimeConnected > b.nTimeConnected;
} }
class CompareNetGroupKeyed class CompareNetGroupKeyed
@ -770,14 +742,14 @@ public:
GetRandBytes(vchSecretKey.data(), vchSecretKey.size()); GetRandBytes(vchSecretKey.data(), vchSecretKey.size());
} }
bool operator()(const CNodeRef &a, const CNodeRef &b) bool operator()(const NodeEvictionCandidate &a, const NodeEvictionCandidate &b)
{ {
std::vector<unsigned char> vchGroupA, vchGroupB; std::vector<unsigned char> vchGroupA, vchGroupB;
CSHA256 hashA, hashB; CSHA256 hashA, hashB;
std::vector<unsigned char> vchA(32), vchB(32); std::vector<unsigned char> vchA(32), vchB(32);
vchGroupA = a->addr.GetGroup(); vchGroupA = a.addr.GetGroup();
vchGroupB = b->addr.GetGroup(); vchGroupB = b.addr.GetGroup();
hashA.Write(begin_ptr(vchGroupA), vchGroupA.size()); hashA.Write(begin_ptr(vchGroupA), vchGroupA.size());
hashB.Write(begin_ptr(vchGroupB), vchGroupB.size()); hashB.Write(begin_ptr(vchGroupB), vchGroupB.size());
@ -793,7 +765,7 @@ public:
}; };
static bool AttemptToEvictConnection(bool fPreferNewConnection) { static bool AttemptToEvictConnection(bool fPreferNewConnection) {
std::vector<CNodeRef> vEvictionCandidates; std::vector<NodeEvictionCandidate> vEvictionCandidates;
{ {
LOCK(cs_vNodes); LOCK(cs_vNodes);
@ -804,7 +776,14 @@ static bool AttemptToEvictConnection(bool fPreferNewConnection) {
continue; continue;
if (node->fDisconnect) if (node->fDisconnect)
continue; continue;
vEvictionCandidates.push_back(CNodeRef(node)); NodeEvictionCandidate candidate = {
.id = node->id,
.nTimeConnected = node->nTimeConnected,
.nMinPingUsecTime = node->nMinPingUsecTime,
.addr = node->addr,
.nVersion = node -> nVersion
};
vEvictionCandidates.push_back(candidate);
} }
} }
@ -813,7 +792,7 @@ static bool AttemptToEvictConnection(bool fPreferNewConnection) {
// Protect connections with certain characteristics // Protect connections with certain characteristics
// Check version of eviction candidates and prioritize nodes which do not support network upgrade. // Check version of eviction candidates and prioritize nodes which do not support network upgrade.
std::vector<CNodeRef> vTmpEvictionCandidates; std::vector<NodeEvictionCandidate> vTmpEvictionCandidates;
int height; int height;
{ {
LOCK(cs_main); LOCK(cs_main);
@ -831,8 +810,8 @@ static bool AttemptToEvictConnection(bool fPreferNewConnection) {
height >= nActivationHeight - NETWORK_UPGRADE_PEER_PREFERENCE_BLOCK_PERIOD) height >= nActivationHeight - NETWORK_UPGRADE_PEER_PREFERENCE_BLOCK_PERIOD)
{ {
// Find any nodes which don't support the protocol version for the next upgrade // Find any nodes which don't support the protocol version for the next upgrade
for (const CNodeRef &node : vEvictionCandidates) { for (const NodeEvictionCandidate &node : vEvictionCandidates) {
if (node->nVersion < params.vUpgrades[idx].nProtocolVersion && if (node.nVersion < params.vUpgrades[idx].nProtocolVersion &&
!( !(
Params().NetworkIDString() == "regtest" && Params().NetworkIDString() == "regtest" &&
!GetBoolArg("-nurejectoldversions", DEFAULT_NU_REJECT_OLD_VERSIONS) !GetBoolArg("-nurejectoldversions", DEFAULT_NU_REJECT_OLD_VERSIONS)
@ -876,16 +855,16 @@ static bool AttemptToEvictConnection(bool fPreferNewConnection) {
std::vector<unsigned char> naMostConnections; std::vector<unsigned char> naMostConnections;
unsigned int nMostConnections = 0; unsigned int nMostConnections = 0;
int64_t nMostConnectionsTime = 0; int64_t nMostConnectionsTime = 0;
std::map<std::vector<unsigned char>, std::vector<CNodeRef> > mapAddrCounts; std::map<std::vector<unsigned char>, std::vector<NodeEvictionCandidate> > mapAddrCounts;
for (const CNodeRef &node : vEvictionCandidates) { for(const NodeEvictionCandidate &node : vEvictionCandidates) {
mapAddrCounts[node->addr.GetGroup()].push_back(node); mapAddrCounts[node.addr.GetGroup()].push_back(node);
int64_t grouptime = mapAddrCounts[node->addr.GetGroup()][0]->nTimeConnected; int64_t grouptime = mapAddrCounts[node.addr.GetGroup()][0].nTimeConnected;
size_t groupsize = mapAddrCounts[node->addr.GetGroup()].size(); size_t groupsize = mapAddrCounts[node.addr.GetGroup()].size();
if (groupsize > nMostConnections || (groupsize == nMostConnections && grouptime > nMostConnectionsTime)) { if (groupsize > nMostConnections || (groupsize == nMostConnections && grouptime > nMostConnectionsTime)) {
nMostConnections = groupsize; nMostConnections = groupsize;
nMostConnectionsTime = grouptime; nMostConnectionsTime = grouptime;
naMostConnections = node->addr.GetGroup(); naMostConnections = node.addr.GetGroup();
} }
} }
@ -899,9 +878,15 @@ static bool AttemptToEvictConnection(bool fPreferNewConnection) {
return false; return false;
// Disconnect from the network group with the most connections // Disconnect from the network group with the most connections
vEvictionCandidates[0]->fDisconnect = true; NodeId evicted = vEvictionCandidates.front().id;
LOCK(cs_vNodes);
return true; for(std::vector<CNode*>::const_iterator it(vNodes.begin()); it != vNodes.end(); ++it) {
if ((*it)->GetId() == evicted) {
(*it)->fDisconnect = true;
return true;
}
}
return false;
} }
static void AcceptConnection(const ListenSocket& hListenSocket) { static void AcceptConnection(const ListenSocket& hListenSocket) {