Skip to content

Commit e898229

Browse files
committed
Add a new peer state tracking class to reduce cs_main contention.
CNodeState was added for validation-state-tracking, and thus, logically, was protected by cs_main. However, as it has grown to include non-validation state (taking state from CNode), and as we've reduced cs_main usage for other unrelated things, CNodeState is left with lots of cs_main locking in net_processing. In order to ease transition to something new, this adds only a dummy CPeerState which is held as a reference for the duration of message processing. Note that moving things is somewhat tricky pre validation-thread as a consistent lockorder must be kept - we can't take a lock on the new cs_peerstate in anything that's called directly from validation.
1 parent 79e6e44 commit e898229

File tree

1 file changed

+44
-3
lines changed

1 file changed

+44
-3
lines changed

src/net_processing.cpp

Lines changed: 44 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,17 @@ struct CBlockReject {
199199
uint256 hashBlock;
200200
};
201201

202+
/**
203+
* Maintain state about nodes, protected by our own lock. Historically we put all
204+
* peer tracking state in CNodeState, however this results in significant cs_main
205+
* contention. Thus, new state tracking should go here, and we should eventually
206+
* move most (non-validation-specific) state here.
207+
*/
208+
struct CPeerState {
209+
CPeerState() {}
210+
};
211+
212+
202213
/**
203214
* Maintain validation-specific state about nodes, protected by cs_main, instead
204215
* by CNode's own locks. This simplifies asynchronous operation, where
@@ -393,7 +404,20 @@ struct CNodeState {
393404
// Keeps track of the time (in microseconds) when transactions were requested last time
394405
limitedmap<uint256, int64_t> g_already_asked_for GUARDED_BY(cs_main)(MAX_INV_SZ);
395406

407+
/** Note that this must be locked BEFORE cs_main! */
408+
CCriticalSection cs_peerstate;
409+
396410
/** Map maintaining per-node state. */
411+
static std::map<NodeId, CPeerState> mapPeerState GUARDED_BY(cs_peerstate);
412+
413+
static CPeerState *PeerState(NodeId pnode) EXCLUSIVE_LOCKS_REQUIRED(cs_peerstate) LOCKS_EXCLUDED(cs_main) {
414+
std::map<NodeId, CPeerState>::iterator it = mapPeerState.find(pnode);
415+
if (it == mapPeerState.end())
416+
return nullptr;
417+
return &it->second;
418+
}
419+
420+
/** Map maintaining new per-node state. */
397421
static std::map<NodeId, CNodeState> mapNodeState GUARDED_BY(cs_main);
398422

399423
static CNodeState *State(NodeId pnode) EXCLUSIVE_LOCKS_REQUIRED(cs_main) {
@@ -771,12 +795,22 @@ void PeerLogicValidation::InitializeNode(CNode *pnode) {
771795
LOCK(cs_main);
772796
mapNodeState.emplace_hint(mapNodeState.end(), std::piecewise_construct, std::forward_as_tuple(nodeid), std::forward_as_tuple(addr, std::move(addrName), pnode->fInbound, pnode->m_manual_connection));
773797
}
798+
{
799+
LOCK(cs_peerstate);
800+
mapPeerState.emplace_hint(mapPeerState.end(), nodeid, CPeerState{});
801+
}
802+
774803
if(!pnode->fInbound)
775804
PushNodeVersion(pnode, connman, GetTime());
776805
}
777806

778807
void PeerLogicValidation::FinalizeNode(NodeId nodeid, bool& fUpdateConnectionTime) {
779808
fUpdateConnectionTime = false;
809+
810+
LOCK(cs_peerstate);
811+
CPeerState* peerstate = PeerState(nodeid);
812+
assert(peerstate != nullptr);
813+
780814
LOCK(cs_main);
781815
CNodeState *state = State(nodeid);
782816
assert(state != nullptr);
@@ -799,13 +833,15 @@ void PeerLogicValidation::FinalizeNode(NodeId nodeid, bool& fUpdateConnectionTim
799833
assert(g_outbound_peers_with_protect_from_disconnect >= 0);
800834

801835
mapNodeState.erase(nodeid);
836+
mapPeerState.erase(nodeid);
802837

803838
if (mapNodeState.empty()) {
804839
// Do a consistency check after the last peer is removed.
805840
assert(mapBlocksInFlight.empty());
806841
assert(nPreferredDownload == 0);
807842
assert(nPeersWithValidatedDownloads == 0);
808843
assert(g_outbound_peers_with_protect_from_disconnect == 0);
844+
assert(mapPeerState.empty());
809845
}
810846
LogPrint(BCLog::NET, "Cleared nodestate for peer=%d\n", nodeid);
811847
}
@@ -1843,7 +1879,7 @@ void static ProcessOrphanTx(CConnman* connman, std::set<uint256>& orphan_work_se
18431879
}
18441880
}
18451881

1846-
bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStream& vRecv, int64_t nTimeReceived, const CChainParams& chainparams, CConnman* connman, const std::atomic<bool>& interruptMsgProc, bool enable_bip61)
1882+
bool static ProcessMessage(CNode* pfrom, CPeerState* peerstate, const std::string& strCommand, CDataStream& vRecv, int64_t nTimeReceived, const CChainParams& chainparams, CConnman* connman, const std::atomic<bool>& interruptMsgProc, bool enable_bip61) EXCLUSIVE_LOCKS_REQUIRED(cs_peerstate)
18471883
{
18481884
LogPrint(BCLog::NET, "received: %s (%u bytes) peer=%d\n", SanitizeString(strCommand), vRecv.size(), pfrom->GetId());
18491885
if (gArgs.IsArgSet("-dropmessagestest") && GetRand(gArgs.GetArg("-dropmessagestest", 0)) == 0)
@@ -2785,7 +2821,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
27852821
} // cs_main
27862822

27872823
if (fProcessBLOCKTXN)
2788-
return ProcessMessage(pfrom, NetMsgType::BLOCKTXN, blockTxnMsg, nTimeReceived, chainparams, connman, interruptMsgProc, enable_bip61);
2824+
return ProcessMessage(pfrom, peerstate, NetMsgType::BLOCKTXN, blockTxnMsg, nTimeReceived, chainparams, connman, interruptMsgProc, enable_bip61);
27892825

27902826
if (fRevertToHeaderProcessing) {
27912827
// Headers received from HB compact block peers are permitted to be
@@ -3231,6 +3267,8 @@ bool PeerLogicValidation::SendRejectsAndCheckIfBanned(CNode* pnode, bool enable_
32313267
bool PeerLogicValidation::ProcessMessages(CNode* pfrom, std::atomic<bool>& interruptMsgProc)
32323268
{
32333269
const CChainParams& chainparams = Params();
3270+
LOCK(cs_peerstate);
3271+
CPeerState* peerstate = PeerState(pfrom->GetId());
32343272
//
32353273
// Message format
32363274
// (4) message start
@@ -3313,7 +3351,7 @@ bool PeerLogicValidation::ProcessMessages(CNode* pfrom, std::atomic<bool>& inter
33133351
bool fRet = false;
33143352
try
33153353
{
3316-
fRet = ProcessMessage(pfrom, strCommand, vRecv, msg.nTime, chainparams, connman, interruptMsgProc, m_enable_bip61);
3354+
fRet = ProcessMessage(pfrom, peerstate, strCommand, vRecv, msg.nTime, chainparams, connman, interruptMsgProc, m_enable_bip61);
33173355
if (interruptMsgProc)
33183356
return false;
33193357
if (!pfrom->vRecvGetData.empty())
@@ -3522,6 +3560,9 @@ bool PeerLogicValidation::SendMessages(CNode* pto)
35223560
// If we get here, the outgoing message serialization version is set and can't change.
35233561
const CNetMsgMaker msgMaker(pto->GetSendVersion());
35243562

3563+
LOCK(cs_peerstate);
3564+
CPeerState* peerstate = PeerState(pto->GetId());
3565+
35253566
//
35263567
// Message: ping
35273568
//

0 commit comments

Comments
 (0)