mirror of
https://github.com/dashpay/dash.git
synced 2024-12-24 19:42:46 +01:00
feat/fix: ScanQuorums improvements (#4945)
* feat: Revive quorum scan caching * refactor: split quorumsCacheCs mutex into two * fix: Avoid extra work in quorum scanning Non-rotation quorums do not become rotation ones (anymore), use `useRotation` to pick the right method only. This brings CPU load for `d-isman` thread (while being idle) from ~5% down to ~1% on testnet for me. * apply suggestions
This commit is contained in:
parent
63d9c6abf7
commit
d47af2c4bf
@ -357,7 +357,7 @@ void CQuorumManager::CheckQuorumConnections(const Consensus::LLMQParams& llmqPar
|
||||
|
||||
CQuorumPtr CQuorumManager::BuildQuorumFromCommitment(const Consensus::LLMQType llmqType, const CBlockIndex* pQuorumBaseBlockIndex) const
|
||||
{
|
||||
AssertLockHeld(quorumsCacheCs);
|
||||
AssertLockHeld(cs_map_quorums);
|
||||
assert(pQuorumBaseBlockIndex);
|
||||
|
||||
const uint256& quorumHash{pQuorumBaseBlockIndex->GetBlockHash()};
|
||||
@ -495,21 +495,36 @@ std::vector<CQuorumCPtr> CQuorumManager::ScanQuorums(Consensus::LLMQType llmqTyp
|
||||
size_t nScanCommitments{nCountRequested};
|
||||
std::vector<CQuorumCPtr> vecResultQuorums;
|
||||
|
||||
// TODO implement caching, see [pre-rotation caching](https://github.com/dashpay/dash/blob/e84bf45cefbcf9ee89ca3d706fd8abffdbcc8a84/src/llmq/quorums.cpp#L424-L448)
|
||||
// for inspiration
|
||||
{
|
||||
LOCK(cs_scan_quorums);
|
||||
auto& cache = scanQuorumsCache[llmqType];
|
||||
bool fCacheExists = cache.get(pindexStart->GetBlockHash(), vecResultQuorums);
|
||||
if (fCacheExists) {
|
||||
// We have exactly what requested so just return it
|
||||
if (vecResultQuorums.size() == nCountRequested) {
|
||||
return vecResultQuorums;
|
||||
}
|
||||
// If we have more cached than requested return only a subvector
|
||||
if (vecResultQuorums.size() > nCountRequested) {
|
||||
return {vecResultQuorums.begin(), vecResultQuorums.begin() + nCountRequested};
|
||||
}
|
||||
// If we have cached quorums but not enough, subtract what we have from the count and the set correct index where to start
|
||||
// scanning for the rests
|
||||
if (!vecResultQuorums.empty()) {
|
||||
nScanCommitments -= vecResultQuorums.size();
|
||||
pIndexScanCommitments = vecResultQuorums.back()->m_quorum_base_block_index->pprev;
|
||||
}
|
||||
} else {
|
||||
// If there is nothing in cache request at least cache.max_size() because this gets cached then later
|
||||
nScanCommitments = std::max(nCountRequested, cache.max_size());
|
||||
}
|
||||
}
|
||||
|
||||
// Get the block indexes of the mined commitments to build the required quorums from
|
||||
auto pQuorumBaseBlockIndexes = quorumBlockProcessor->GetMinedCommitmentsIndexedUntilBlock(llmqType, static_cast<const CBlockIndex*>(pIndexScanCommitments), nScanCommitments);
|
||||
if (pQuorumBaseBlockIndexes.size() < nScanCommitments) {
|
||||
if (!pQuorumBaseBlockIndexes.empty()) {
|
||||
nScanCommitments -= pQuorumBaseBlockIndexes.size();
|
||||
if (pQuorumBaseBlockIndexes.back()->pprev) {
|
||||
pIndexScanCommitments = pQuorumBaseBlockIndexes.back()->pprev;
|
||||
}
|
||||
}
|
||||
auto pQuorumBaseBlockIndexesLegacy = quorumBlockProcessor->GetMinedCommitmentsUntilBlock(llmqType, static_cast<const CBlockIndex*>(pIndexScanCommitments), nScanCommitments);
|
||||
pQuorumBaseBlockIndexes.insert(pQuorumBaseBlockIndexes.end(), pQuorumBaseBlockIndexesLegacy.begin(), pQuorumBaseBlockIndexesLegacy.end());
|
||||
}
|
||||
std::vector<const CBlockIndex*> pQuorumBaseBlockIndexes{ GetLLMQParams(llmqType).useRotation ?
|
||||
quorumBlockProcessor->GetMinedCommitmentsIndexedUntilBlock(llmqType, pIndexScanCommitments, nScanCommitments) :
|
||||
quorumBlockProcessor->GetMinedCommitmentsUntilBlock(llmqType, pIndexScanCommitments, nScanCommitments)
|
||||
};
|
||||
vecResultQuorums.reserve(vecResultQuorums.size() + pQuorumBaseBlockIndexes.size());
|
||||
|
||||
for (auto& pQuorumBaseBlockIndex : pQuorumBaseBlockIndexes) {
|
||||
@ -519,18 +534,17 @@ std::vector<CQuorumCPtr> CQuorumManager::ScanQuorums(Consensus::LLMQType llmqTyp
|
||||
vecResultQuorums.emplace_back(quorum);
|
||||
}
|
||||
|
||||
size_t nCountResult{vecResultQuorums.size()};
|
||||
const size_t nCountResult{vecResultQuorums.size()};
|
||||
if (nCountResult > 0) {
|
||||
LOCK(quorumsCacheCs);
|
||||
LOCK(cs_scan_quorums);
|
||||
// Don't cache more than cache.max_size() elements
|
||||
auto& cache = scanQuorumsCache[llmqType];
|
||||
size_t nCacheEndIndex = std::min(nCountResult, cache.max_size());
|
||||
const size_t nCacheEndIndex = std::min(nCountResult, cache.max_size());
|
||||
cache.emplace(pindexStart->GetBlockHash(), {vecResultQuorums.begin(), vecResultQuorums.begin() + nCacheEndIndex});
|
||||
}
|
||||
// Don't return more than nCountRequested elements
|
||||
size_t nResultEndIndex = std::min(nCountResult, nCountRequested);
|
||||
const std::vector<CQuorumCPtr>& ret = {vecResultQuorums.begin(), vecResultQuorums.begin() + nResultEndIndex};
|
||||
return ret;
|
||||
const size_t nResultEndIndex = std::min(nCountResult, nCountRequested);
|
||||
return {vecResultQuorums.begin(), vecResultQuorums.begin() + nResultEndIndex};
|
||||
}
|
||||
|
||||
CQuorumCPtr CQuorumManager::GetQuorum(Consensus::LLMQType llmqType, const uint256& quorumHash) const
|
||||
@ -555,7 +569,7 @@ CQuorumCPtr CQuorumManager::GetQuorum(Consensus::LLMQType llmqType, const CBlock
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
LOCK(quorumsCacheCs);
|
||||
LOCK(cs_map_quorums);
|
||||
CQuorumPtr pQuorum;
|
||||
if (mapQuorumsCache[llmqType].get(quorumHash, pQuorum)) {
|
||||
return pQuorum;
|
||||
@ -722,7 +736,7 @@ void CQuorumManager::ProcessMessage(CNode* pFrom, const std::string& msg_type, C
|
||||
|
||||
CQuorumPtr pQuorum;
|
||||
{
|
||||
LOCK(quorumsCacheCs);
|
||||
LOCK(cs_map_quorums);
|
||||
if (!mapQuorumsCache[request.GetLLMQType()].get(request.GetQuorumHash(), pQuorum)) {
|
||||
errorHandler("Quorum not found", 0); // Don't bump score because we asked for it
|
||||
return;
|
||||
|
@ -210,9 +210,10 @@ private:
|
||||
CBLSWorker& blsWorker;
|
||||
CDKGSessionManager& dkgManager;
|
||||
|
||||
mutable CCriticalSection quorumsCacheCs;
|
||||
mutable std::map<Consensus::LLMQType, unordered_lru_cache<uint256, CQuorumPtr, StaticSaltedHasher>> mapQuorumsCache GUARDED_BY(quorumsCacheCs);
|
||||
mutable std::map<Consensus::LLMQType, unordered_lru_cache<uint256, std::vector<CQuorumCPtr>, StaticSaltedHasher>> scanQuorumsCache GUARDED_BY(quorumsCacheCs);
|
||||
mutable CCriticalSection cs_map_quorums;
|
||||
mutable std::map<Consensus::LLMQType, unordered_lru_cache<uint256, CQuorumPtr, StaticSaltedHasher>> mapQuorumsCache GUARDED_BY(cs_map_quorums);
|
||||
mutable CCriticalSection cs_scan_quorums;
|
||||
mutable std::map<Consensus::LLMQType, unordered_lru_cache<uint256, std::vector<CQuorumCPtr>, StaticSaltedHasher>> scanQuorumsCache GUARDED_BY(cs_scan_quorums);
|
||||
|
||||
mutable ctpl::thread_pool workerPool;
|
||||
mutable CThreadInterrupt quorumThreadInterrupt;
|
||||
@ -245,7 +246,7 @@ private:
|
||||
// all private methods here are cs_main-free
|
||||
void CheckQuorumConnections(const Consensus::LLMQParams& llmqParams, const CBlockIndex *pindexNew) const;
|
||||
|
||||
CQuorumPtr BuildQuorumFromCommitment(Consensus::LLMQType llmqType, const CBlockIndex* pQuorumBaseBlockIndex) const EXCLUSIVE_LOCKS_REQUIRED(quorumsCacheCs);
|
||||
CQuorumPtr BuildQuorumFromCommitment(Consensus::LLMQType llmqType, const CBlockIndex* pQuorumBaseBlockIndex) const EXCLUSIVE_LOCKS_REQUIRED(cs_map_quorums);
|
||||
bool BuildQuorumContributions(const CFinalCommitmentPtr& fqc, const std::shared_ptr<CQuorum>& quorum) const;
|
||||
|
||||
CQuorumCPtr GetQuorum(Consensus::LLMQType llmqType, const CBlockIndex* pindex) const;
|
||||
|
Loading…
Reference in New Issue
Block a user