Skip to content

Commit 40a247d

Browse files
codablockpanleone
authored andcommitted
Implement caching in CRecoveredSigsDb
To avoid repeated calls into LevelDB
1 parent 6c63a77 commit 40a247d

File tree

2 files changed

+114
-17
lines changed

2 files changed

+114
-17
lines changed

src/llmq/quorums_signing.cpp

Lines changed: 94 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -35,14 +35,46 @@ bool CRecoveredSigsDb::HasRecoveredSig(Consensus::LLMQType llmqType, const uint2
3535

3636
bool CRecoveredSigsDb::HasRecoveredSigForId(Consensus::LLMQType llmqType, const uint256& id)
3737
{
38+
int64_t t = GetTimeMillis();
39+
40+
auto cacheKey = std::make_pair(llmqType, id);
41+
{
42+
LOCK(cs);
43+
auto it = hasSigForIdCache.find(cacheKey);
44+
if (it != hasSigForIdCache.end()) {
45+
it->second.second = t;
46+
return it->second.first;
47+
}
48+
}
49+
50+
3851
auto k = std::make_tuple('r', (uint8_t)llmqType, id);
39-
return db.Exists(k);
52+
bool ret = db.Exists(k);
53+
54+
LOCK(cs);
55+
hasSigForIdCache.emplace(cacheKey, std::make_pair(ret, t));
56+
return ret;
4057
}
4158

4259
bool CRecoveredSigsDb::HasRecoveredSigForSession(const uint256& signHash)
4360
{
61+
int64_t t = GetTimeMillis();
62+
63+
{
64+
LOCK(cs);
65+
auto it = hasSigForSessionCache.find(signHash);
66+
if (it != hasSigForSessionCache.end()) {
67+
it->second.second = t;
68+
return it->second.first;
69+
}
70+
}
71+
4472
auto k = std::make_tuple('s', signHash);
45-
return db.Exists(k);
73+
bool ret = db.Exists(k);
74+
75+
LOCK(cs);
76+
hasSigForSessionCache.emplace(signHash, std::make_pair(ret, t));
77+
return ret;
4678
}
4779

4880
bool CRecoveredSigsDb::HasRecoveredSigForHash(const uint256& hash)
@@ -100,7 +132,8 @@ void CRecoveredSigsDb::WriteRecoveredSig(const llmq::CRecoveredSig& recSig)
100132
batch.Write(k3, std::make_pair(recSig.llmqType, recSig.id));
101133

102134
// store by signHash
103-
auto k4 = std::make_tuple('s', llmq::utils::BuildSignHash(recSig));
135+
auto signHash = llmq::utils::BuildSignHash(recSig);
136+
auto k4 = std::make_tuple('s', signHash);
104137
batch.Write(k4, (uint8_t)1);
105138

106139
// remove the votedForId entry as we won't need it anymore
@@ -112,6 +145,39 @@ void CRecoveredSigsDb::WriteRecoveredSig(const llmq::CRecoveredSig& recSig)
112145
batch.Write(k6, (uint8_t)1);
113146

114147
db.WriteBatch(batch);
148+
149+
{
150+
int64_t t = GetTimeMillis();
151+
152+
LOCK(cs);
153+
hasSigForIdCache[std::make_pair((Consensus::LLMQType)recSig.llmqType, recSig.id)] = std::make_pair(true, t);
154+
hasSigForSessionCache[signHash] = std::make_pair(true, t);
155+
}
156+
}
157+
158+
template<typename K>
159+
static void TruncateCacheMap(std::unordered_map<K, std::pair<bool, int64_t>>& m, size_t maxSize, size_t truncateThreshold)
160+
{
161+
typedef typename std::unordered_map<K, std::pair<bool, int64_t>> Map;
162+
typedef typename Map::iterator Iterator;
163+
164+
if (m.size() <= truncateThreshold) {
165+
return;
166+
}
167+
168+
std::vector<Iterator> vec;
169+
vec.reserve(m.size());
170+
for (auto it = m.begin(); it != m.end(); ++it) {
171+
vec.emplace_back(it);
172+
}
173+
// sort by last access time (descending order)
174+
std::sort(vec.begin(), vec.end(), [](const Iterator& it1, const Iterator& it2) {
175+
return it1->second.second > it2->second.second;
176+
});
177+
178+
for (size_t i = maxSize; i < vec.size(); i++) {
179+
m.erase(vec[i]);
180+
}
115181
}
116182

117183
void CRecoveredSigsDb::CleanupOldRecoveredSigs(int64_t maxAge)
@@ -148,22 +214,33 @@ void CRecoveredSigsDb::CleanupOldRecoveredSigs(int64_t maxAge)
148214
}
149215

150216
CDBBatch batch(CLIENT_VERSION | ADDRV2_FORMAT);
151-
for (auto& e : toDelete) {
152-
CRecoveredSig recSig;
153-
if (!ReadRecoveredSig(e.first, e.second, recSig)) {
154-
continue;
217+
{
218+
LOCK(cs);
219+
for (auto& e : toDelete) {
220+
CRecoveredSig recSig;
221+
if (!ReadRecoveredSig(e.first, e.second, recSig)) {
222+
continue;
223+
}
224+
225+
auto signHash = llmq::utils::BuildSignHash(recSig);
226+
227+
auto k1 = std::make_tuple('r', recSig.llmqType, recSig.id);
228+
auto k2 = std::make_tuple('r', recSig.llmqType, recSig.id, recSig.msgHash);
229+
auto k3 = std::make_tuple('h', recSig.GetHash());
230+
auto k4 = std::make_tuple('s', signHash);
231+
auto k5 = std::make_tuple('v', recSig.llmqType, recSig.id);
232+
batch.Erase(k1);
233+
batch.Erase(k2);
234+
batch.Erase(k3);
235+
batch.Erase(k4);
236+
batch.Erase(k5);
237+
238+
hasSigForIdCache.erase(std::make_pair((Consensus::LLMQType)recSig.llmqType, recSig.id));
239+
hasSigForSessionCache.erase(signHash);
155240
}
156241

157-
auto k1 = std::make_tuple('r', recSig.llmqType, recSig.id);
158-
auto k2 = std::make_tuple('r', recSig.llmqType, recSig.id, recSig.msgHash);
159-
auto k3 = std::make_tuple('h', recSig.GetHash());
160-
auto k4 = std::make_tuple('s', llmq::utils::BuildSignHash(recSig));
161-
auto k5 = std::make_tuple('v', recSig.llmqType, recSig.id);
162-
batch.Erase(k1);
163-
batch.Erase(k2);
164-
batch.Erase(k3);
165-
batch.Erase(k4);
166-
batch.Erase(k5);
242+
TruncateCacheMap(hasSigForIdCache, MAX_CACHE_SIZE, MAX_CACHE_TRUNCATE_THRESHOLD);
243+
TruncateCacheMap(hasSigForSessionCache, MAX_CACHE_SIZE, MAX_CACHE_TRUNCATE_THRESHOLD);
167244
}
168245

169246
for (auto& e : toDelete2) {

src/llmq/quorums_signing.h

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,19 @@
1212
#include "net.h"
1313
#include "sync.h"
1414

15+
#include <unordered_map>
16+
17+
namespace std {
18+
template <>
19+
struct hash<std::pair<Consensus::LLMQType, uint256>>
20+
{
21+
std::size_t operator()(const std::pair<Consensus::LLMQType, uint256>& k) const
22+
{
23+
return (std::size_t)((k.first + 1) * k.second.GetCheapHash());
24+
}
25+
};
26+
}
27+
1528
namespace llmq
1629
{
1730

@@ -67,9 +80,16 @@ class CRecoveredSig
6780
// TODO implement caching to speed things up
6881
class CRecoveredSigsDb
6982
{
83+
static const size_t MAX_CACHE_SIZE = 30000;
84+
static const size_t MAX_CACHE_TRUNCATE_THRESHOLD = 50000;
85+
7086
private:
7187
CDBWrapper db;
7288

89+
RecursiveMutex cs;
90+
std::unordered_map<std::pair<Consensus::LLMQType, uint256>, std::pair<bool, int64_t>> hasSigForIdCache;
91+
std::unordered_map<uint256, std::pair<bool, int64_t>> hasSigForSessionCache;
92+
7393
public:
7494
CRecoveredSigsDb(bool fMemory);
7595

0 commit comments

Comments
 (0)