Skip to content

Commit

Permalink
Optimize MN lists cache (dashpay#3506)
Browse files Browse the repository at this point in the history
  • Loading branch information
UdjinM6 committed Jun 9, 2020
1 parent 91d9329 commit ab5aeed
Show file tree
Hide file tree
Showing 2 changed files with 84 additions and 19 deletions.
90 changes: 75 additions & 15 deletions src/evo/deterministicmns.cpp
Expand Up @@ -566,11 +566,15 @@ bool CDeterministicMNManager::ProcessBlock(const CBlock& block, const CBlockInde
diff = oldList.BuildDiff(newList);

evoDb.Write(std::make_pair(DB_LIST_DIFF, newList.GetBlockHash()), diff);
if ((nHeight % SNAPSHOT_LIST_PERIOD) == 0 || oldList.GetHeight() == -1) {
if ((nHeight % DISK_SNAPSHOT_PERIOD) == 0 || oldList.GetHeight() == -1) {
evoDb.Write(std::make_pair(DB_LIST_SNAPSHOT, newList.GetBlockHash()), newList);
mnListsCache.emplace(newList.GetBlockHash(), newList);
LogPrintf("CDeterministicMNManager::%s -- Wrote snapshot. nHeight=%d, mapCurMNs.allMNsCount=%d\n",
__func__, nHeight, newList.GetAllMNsCount());
}

diff.nHeight = pindex->nHeight;
mnListDiffsCache.emplace(pindex->GetBlockHash(), diff);
} catch (const std::exception& e) {
LogPrintf("CDeterministicMNManager::%s -- internal error: %s\n", __func__, e.what());
return _state.DoS(100, false, REJECT_INVALID, "failed-dmn-block");
Expand Down Expand Up @@ -616,6 +620,7 @@ bool CDeterministicMNManager::UndoBlock(const CBlock& block, const CBlockIndex*
}

mnListsCache.erase(blockHash);
mnListDiffsCache.erase(blockHash);
}

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

CDeterministicMNList snapshot;
std::list<std::pair<const CBlockIndex*, CDeterministicMNListDiff>> listDiff;
std::list<const CBlockIndex*> listDiffIndexes;

while (true) {
// try using cache before reading from disk
auto it = mnListsCache.find(pindex->GetBlockHash());
if (it != mnListsCache.end()) {
snapshot = it->second;
auto itLists = mnListsCache.find(pindex->GetBlockHash());
if (itLists != mnListsCache.end()) {
snapshot = itLists->second;
break;
}

Expand All @@ -933,28 +938,51 @@ CDeterministicMNList CDeterministicMNManager::GetListForBlock(const CBlockIndex*
break;
}

// no snapshot found yet, check diffs
auto itDiffs = mnListDiffsCache.find(pindex->GetBlockHash());
if (itDiffs != mnListDiffsCache.end()) {
listDiffIndexes.emplace_front(pindex);
pindex = pindex->pprev;
continue;
}

CDeterministicMNListDiff diff;
if (!evoDb.Read(std::make_pair(DB_LIST_DIFF, pindex->GetBlockHash()), diff)) {
// no snapshot and no diff on disk means that it's the initial snapshot
snapshot = CDeterministicMNList(pindex->GetBlockHash(), -1, 0);
mnListsCache.emplace(pindex->GetBlockHash(), snapshot);
break;
}

listDiff.emplace_front(pindex, std::move(diff));
diff.nHeight = pindex->nHeight;
mnListDiffsCache.emplace(pindex->GetBlockHash(), std::move(diff));
listDiffIndexes.emplace_front(pindex);
pindex = pindex->pprev;
}

for (const auto& p : listDiff) {
auto diffIndex = p.first;
auto& diff = p.second;
for (const auto& diffIndex : listDiffIndexes) {
const auto& diff = mnListDiffsCache.at(diffIndex->GetBlockHash());
if (diff.HasChanges()) {
snapshot = snapshot.ApplyDiff(diffIndex, diff);
} else {
snapshot.SetBlockHash(diffIndex->GetBlockHash());
snapshot.SetHeight(diffIndex->nHeight);
}
}

mnListsCache.emplace(diffIndex->GetBlockHash(), snapshot);
if (tipIndex) {
// always keep a snapshot for the tip
if (snapshot.GetBlockHash() == tipIndex->GetBlockHash()) {
mnListsCache.emplace(snapshot.GetBlockHash(), snapshot);
} else {
// keep snapshots for yet alive quorums
for (auto& p_llmq : Params().GetConsensus().llmqs) {
if ((snapshot.GetHeight() % p_llmq.second.dkgInterval == 0) && (snapshot.GetHeight() + p_llmq.second.dkgInterval * (p_llmq.second.keepOldConnections + 1) >= tipIndex->nHeight)) {
mnListsCache.emplace(snapshot.GetBlockHash(), snapshot);
break;
}
}
}
}

return snapshot;
Expand Down Expand Up @@ -1006,15 +1034,47 @@ void CDeterministicMNManager::CleanupCache(int nHeight)
{
AssertLockHeld(cs);

std::vector<uint256> toDelete;
std::vector<uint256> toDeleteLists;
std::vector<uint256> toDeleteDiffs;
for (const auto& p : mnListsCache) {
if (p.second.GetHeight() + LISTS_CACHE_SIZE < nHeight) {
toDelete.emplace_back(p.first);
if (p.second.GetHeight() + LIST_DIFFS_CACHE_SIZE < nHeight) {
toDeleteLists.emplace_back(p.first);
continue;
}
bool fQuorumCache{false};
for (auto& p_llmq : Params().GetConsensus().llmqs) {
if ((p.second.GetHeight() % p_llmq.second.dkgInterval == 0) && (p.second.GetHeight() + p_llmq.second.dkgInterval * (p_llmq.second.keepOldConnections + 1) >= nHeight)) {
fQuorumCache = true;
break;
}
}
if (fQuorumCache) {
// at least one quorum could be using it, keep it
continue;
}
// no alive quorums using it, see if it was a cache for the tip or for a now outdated quorum
if (tipIndex && tipIndex->pprev && (p.first == tipIndex->pprev->GetBlockHash())) {
toDeleteLists.emplace_back(p.first);
} else {
for (auto& p_llmq : Params().GetConsensus().llmqs) {
if (p.second.GetHeight() % p_llmq.second.dkgInterval == 0) {
toDeleteLists.emplace_back(p.first);
break;
}
}
}
}
for (const auto& h : toDelete) {
for (const auto& h : toDeleteLists) {
mnListsCache.erase(h);
}
for (const auto& p : mnListDiffsCache) {
if (p.second.nHeight + LIST_DIFFS_CACHE_SIZE < nHeight) {
toDeleteDiffs.emplace_back(p.first);
}
}
for (const auto& h : toDeleteDiffs) {
mnListDiffsCache.erase(h);
}
}

bool CDeterministicMNManager::UpgradeDiff(CDBBatch& batch, const CBlockIndex* pindexNext, const CDeterministicMNList& curMNList, CDeterministicMNList& newMNList)
Expand Down Expand Up @@ -1111,7 +1171,7 @@ void CDeterministicMNManager::UpgradeDBIfNeeded()
CDeterministicMNList newMNList;
UpgradeDiff(batch, pindex, curMNList, newMNList);

if ((nHeight % SNAPSHOT_LIST_PERIOD) == 0) {
if ((nHeight % DISK_SNAPSHOT_PERIOD) == 0) {
batch.Write(std::make_pair(DB_LIST_SNAPSHOT, pindex->GetBlockHash()), newMNList);
evoDb.GetRawDB().WriteBatch(batch);
batch.Clear();
Expand Down
13 changes: 9 additions & 4 deletions src/evo/deterministicmns.h
Expand Up @@ -11,12 +11,13 @@
#include <evo/evodb.h>
#include <evo/providertx.h>
#include <evo/simplifiedmns.h>
#include <saltedhasher.h>
#include <sync.h>

#include <immer/map.hpp>
#include <immer/map_transient.hpp>

#include <map>
#include <unordered_map>

class CBlock;
class CBlockIndex;
Expand Down Expand Up @@ -546,6 +547,8 @@ class CDeterministicMNList
class CDeterministicMNListDiff
{
public:
int nHeight{-1}; //memory only

std::vector<CDeterministicMNCPtr> addedMNs;
// keys are all relating to the internalId of MNs
std::map<uint64_t, CDeterministicMNStateDiff> updatedMNs;
Expand Down Expand Up @@ -633,16 +636,18 @@ class CDeterministicMNListDiff_OldFormat

class CDeterministicMNManager
{
static const int SNAPSHOT_LIST_PERIOD = 576; // once per day
static const int LISTS_CACHE_SIZE = 576;
static const int DISK_SNAPSHOT_PERIOD = 576; // once per day
static const int DISK_SNAPSHOTS = 3; // keep cache for 3 disk snapshots to have 2 full days covered
static const int LIST_DIFFS_CACHE_SIZE = DISK_SNAPSHOT_PERIOD * DISK_SNAPSHOTS;

public:
CCriticalSection cs;

private:
CEvoDB& evoDb;

std::map<uint256, CDeterministicMNList> mnListsCache;
std::unordered_map<uint256, CDeterministicMNList, StaticSaltedHasher> mnListsCache;
std::unordered_map<uint256, CDeterministicMNListDiff, StaticSaltedHasher> mnListDiffsCache;
const CBlockIndex* tipIndex{nullptr};

public:
Expand Down

0 comments on commit ab5aeed

Please sign in to comment.