Skip to content

Commit ab5aeed

Browse files
authored
Optimize MN lists cache (#3506)
1 parent 91d9329 commit ab5aeed

File tree

2 files changed

+84
-19
lines changed

2 files changed

+84
-19
lines changed

src/evo/deterministicmns.cpp

Lines changed: 75 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -566,11 +566,15 @@ bool CDeterministicMNManager::ProcessBlock(const CBlock& block, const CBlockInde
566566
diff = oldList.BuildDiff(newList);
567567

568568
evoDb.Write(std::make_pair(DB_LIST_DIFF, newList.GetBlockHash()), diff);
569-
if ((nHeight % SNAPSHOT_LIST_PERIOD) == 0 || oldList.GetHeight() == -1) {
569+
if ((nHeight % DISK_SNAPSHOT_PERIOD) == 0 || oldList.GetHeight() == -1) {
570570
evoDb.Write(std::make_pair(DB_LIST_SNAPSHOT, newList.GetBlockHash()), newList);
571+
mnListsCache.emplace(newList.GetBlockHash(), newList);
571572
LogPrintf("CDeterministicMNManager::%s -- Wrote snapshot. nHeight=%d, mapCurMNs.allMNsCount=%d\n",
572573
__func__, nHeight, newList.GetAllMNsCount());
573574
}
575+
576+
diff.nHeight = pindex->nHeight;
577+
mnListDiffsCache.emplace(pindex->GetBlockHash(), diff);
574578
} catch (const std::exception& e) {
575579
LogPrintf("CDeterministicMNManager::%s -- internal error: %s\n", __func__, e.what());
576580
return _state.DoS(100, false, REJECT_INVALID, "failed-dmn-block");
@@ -616,6 +620,7 @@ bool CDeterministicMNManager::UndoBlock(const CBlock& block, const CBlockIndex*
616620
}
617621

618622
mnListsCache.erase(blockHash);
623+
mnListDiffsCache.erase(blockHash);
619624
}
620625

621626
if (diff.HasChanges()) {
@@ -918,13 +923,13 @@ CDeterministicMNList CDeterministicMNManager::GetListForBlock(const CBlockIndex*
918923
LOCK(cs);
919924

920925
CDeterministicMNList snapshot;
921-
std::list<std::pair<const CBlockIndex*, CDeterministicMNListDiff>> listDiff;
926+
std::list<const CBlockIndex*> listDiffIndexes;
922927

923928
while (true) {
924929
// try using cache before reading from disk
925-
auto it = mnListsCache.find(pindex->GetBlockHash());
926-
if (it != mnListsCache.end()) {
927-
snapshot = it->second;
930+
auto itLists = mnListsCache.find(pindex->GetBlockHash());
931+
if (itLists != mnListsCache.end()) {
932+
snapshot = itLists->second;
928933
break;
929934
}
930935

@@ -933,28 +938,51 @@ CDeterministicMNList CDeterministicMNManager::GetListForBlock(const CBlockIndex*
933938
break;
934939
}
935940

941+
// no snapshot found yet, check diffs
942+
auto itDiffs = mnListDiffsCache.find(pindex->GetBlockHash());
943+
if (itDiffs != mnListDiffsCache.end()) {
944+
listDiffIndexes.emplace_front(pindex);
945+
pindex = pindex->pprev;
946+
continue;
947+
}
948+
936949
CDeterministicMNListDiff diff;
937950
if (!evoDb.Read(std::make_pair(DB_LIST_DIFF, pindex->GetBlockHash()), diff)) {
951+
// no snapshot and no diff on disk means that it's the initial snapshot
938952
snapshot = CDeterministicMNList(pindex->GetBlockHash(), -1, 0);
939953
mnListsCache.emplace(pindex->GetBlockHash(), snapshot);
940954
break;
941955
}
942956

943-
listDiff.emplace_front(pindex, std::move(diff));
957+
diff.nHeight = pindex->nHeight;
958+
mnListDiffsCache.emplace(pindex->GetBlockHash(), std::move(diff));
959+
listDiffIndexes.emplace_front(pindex);
944960
pindex = pindex->pprev;
945961
}
946962

947-
for (const auto& p : listDiff) {
948-
auto diffIndex = p.first;
949-
auto& diff = p.second;
963+
for (const auto& diffIndex : listDiffIndexes) {
964+
const auto& diff = mnListDiffsCache.at(diffIndex->GetBlockHash());
950965
if (diff.HasChanges()) {
951966
snapshot = snapshot.ApplyDiff(diffIndex, diff);
952967
} else {
953968
snapshot.SetBlockHash(diffIndex->GetBlockHash());
954969
snapshot.SetHeight(diffIndex->nHeight);
955970
}
971+
}
956972

957-
mnListsCache.emplace(diffIndex->GetBlockHash(), snapshot);
973+
if (tipIndex) {
974+
// always keep a snapshot for the tip
975+
if (snapshot.GetBlockHash() == tipIndex->GetBlockHash()) {
976+
mnListsCache.emplace(snapshot.GetBlockHash(), snapshot);
977+
} else {
978+
// keep snapshots for yet alive quorums
979+
for (auto& p_llmq : Params().GetConsensus().llmqs) {
980+
if ((snapshot.GetHeight() % p_llmq.second.dkgInterval == 0) && (snapshot.GetHeight() + p_llmq.second.dkgInterval * (p_llmq.second.keepOldConnections + 1) >= tipIndex->nHeight)) {
981+
mnListsCache.emplace(snapshot.GetBlockHash(), snapshot);
982+
break;
983+
}
984+
}
985+
}
958986
}
959987

960988
return snapshot;
@@ -1006,15 +1034,47 @@ void CDeterministicMNManager::CleanupCache(int nHeight)
10061034
{
10071035
AssertLockHeld(cs);
10081036

1009-
std::vector<uint256> toDelete;
1037+
std::vector<uint256> toDeleteLists;
1038+
std::vector<uint256> toDeleteDiffs;
10101039
for (const auto& p : mnListsCache) {
1011-
if (p.second.GetHeight() + LISTS_CACHE_SIZE < nHeight) {
1012-
toDelete.emplace_back(p.first);
1040+
if (p.second.GetHeight() + LIST_DIFFS_CACHE_SIZE < nHeight) {
1041+
toDeleteLists.emplace_back(p.first);
1042+
continue;
1043+
}
1044+
bool fQuorumCache{false};
1045+
for (auto& p_llmq : Params().GetConsensus().llmqs) {
1046+
if ((p.second.GetHeight() % p_llmq.second.dkgInterval == 0) && (p.second.GetHeight() + p_llmq.second.dkgInterval * (p_llmq.second.keepOldConnections + 1) >= nHeight)) {
1047+
fQuorumCache = true;
1048+
break;
1049+
}
1050+
}
1051+
if (fQuorumCache) {
1052+
// at least one quorum could be using it, keep it
1053+
continue;
1054+
}
1055+
// no alive quorums using it, see if it was a cache for the tip or for a now outdated quorum
1056+
if (tipIndex && tipIndex->pprev && (p.first == tipIndex->pprev->GetBlockHash())) {
1057+
toDeleteLists.emplace_back(p.first);
1058+
} else {
1059+
for (auto& p_llmq : Params().GetConsensus().llmqs) {
1060+
if (p.second.GetHeight() % p_llmq.second.dkgInterval == 0) {
1061+
toDeleteLists.emplace_back(p.first);
1062+
break;
1063+
}
1064+
}
10131065
}
10141066
}
1015-
for (const auto& h : toDelete) {
1067+
for (const auto& h : toDeleteLists) {
10161068
mnListsCache.erase(h);
10171069
}
1070+
for (const auto& p : mnListDiffsCache) {
1071+
if (p.second.nHeight + LIST_DIFFS_CACHE_SIZE < nHeight) {
1072+
toDeleteDiffs.emplace_back(p.first);
1073+
}
1074+
}
1075+
for (const auto& h : toDeleteDiffs) {
1076+
mnListDiffsCache.erase(h);
1077+
}
10181078
}
10191079

10201080
bool CDeterministicMNManager::UpgradeDiff(CDBBatch& batch, const CBlockIndex* pindexNext, const CDeterministicMNList& curMNList, CDeterministicMNList& newMNList)
@@ -1111,7 +1171,7 @@ void CDeterministicMNManager::UpgradeDBIfNeeded()
11111171
CDeterministicMNList newMNList;
11121172
UpgradeDiff(batch, pindex, curMNList, newMNList);
11131173

1114-
if ((nHeight % SNAPSHOT_LIST_PERIOD) == 0) {
1174+
if ((nHeight % DISK_SNAPSHOT_PERIOD) == 0) {
11151175
batch.Write(std::make_pair(DB_LIST_SNAPSHOT, pindex->GetBlockHash()), newMNList);
11161176
evoDb.GetRawDB().WriteBatch(batch);
11171177
batch.Clear();

src/evo/deterministicmns.h

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,13 @@
1111
#include <evo/evodb.h>
1212
#include <evo/providertx.h>
1313
#include <evo/simplifiedmns.h>
14+
#include <saltedhasher.h>
1415
#include <sync.h>
1516

1617
#include <immer/map.hpp>
1718
#include <immer/map_transient.hpp>
1819

19-
#include <map>
20+
#include <unordered_map>
2021

2122
class CBlock;
2223
class CBlockIndex;
@@ -546,6 +547,8 @@ class CDeterministicMNList
546547
class CDeterministicMNListDiff
547548
{
548549
public:
550+
int nHeight{-1}; //memory only
551+
549552
std::vector<CDeterministicMNCPtr> addedMNs;
550553
// keys are all relating to the internalId of MNs
551554
std::map<uint64_t, CDeterministicMNStateDiff> updatedMNs;
@@ -633,16 +636,18 @@ class CDeterministicMNListDiff_OldFormat
633636

634637
class CDeterministicMNManager
635638
{
636-
static const int SNAPSHOT_LIST_PERIOD = 576; // once per day
637-
static const int LISTS_CACHE_SIZE = 576;
639+
static const int DISK_SNAPSHOT_PERIOD = 576; // once per day
640+
static const int DISK_SNAPSHOTS = 3; // keep cache for 3 disk snapshots to have 2 full days covered
641+
static const int LIST_DIFFS_CACHE_SIZE = DISK_SNAPSHOT_PERIOD * DISK_SNAPSHOTS;
638642

639643
public:
640644
CCriticalSection cs;
641645

642646
private:
643647
CEvoDB& evoDb;
644648

645-
std::map<uint256, CDeterministicMNList> mnListsCache;
649+
std::unordered_map<uint256, CDeterministicMNList, StaticSaltedHasher> mnListsCache;
650+
std::unordered_map<uint256, CDeterministicMNListDiff, StaticSaltedHasher> mnListDiffsCache;
646651
const CBlockIndex* tipIndex{nullptr};
647652

648653
public:

0 commit comments

Comments
 (0)