11
11
#include " util/Logging.h"
12
12
#include " xdr/Stellar-ledger-entries.h"
13
13
#include < ios>
14
+ #include < medida/meter.h>
15
+ #include < shared_mutex>
14
16
#include < vector>
15
17
16
18
namespace stellar
@@ -38,6 +40,8 @@ LiveBucketIndex::getPageSize(Config const& cfg, size_t bucketSize)
38
40
LiveBucketIndex::LiveBucketIndex (BucketManager& bm,
39
41
std::filesystem::path const & filename,
40
42
Hash const & hash, asio::io_context& ctx)
43
+ : mCacheHitMeter (bm.getCacheHitMeter())
44
+ , mCacheMissMeter (bm.getCacheMissMeter())
41
45
{
42
46
ZoneScoped;
43
47
releaseAssert (!filename.empty ());
@@ -60,6 +64,21 @@ LiveBucketIndex::LiveBucketIndex(BucketManager& bm,
60
64
pageSize, filename);
61
65
mDiskIndex = std::make_unique<DiskIndex<LiveBucket>>(
62
66
bm, filename, pageSize, hash, ctx);
67
+
68
+ auto percentCached = bm.getConfig ().BUCKETLIST_DB_CACHED_PERCENT ;
69
+ if (percentCached > 0 )
70
+ {
71
+ auto const & counters = mDiskIndex ->getBucketEntryCounters ();
72
+ auto cacheSize = (counters.numEntries () * percentCached) / 100 ;
73
+
74
+ // Minimum cache size of 100 if we are going to cache a non-zero
75
+ // number of entries
76
+ // We don't want to reserve here, since caches only live as long as
77
+ // the lifetime of the Bucket and fill relatively slowly
78
+ mCache = std::make_unique<CacheT>(std::max<size_t >(cacheSize, 100 ),
79
+ /* separatePRNG=*/ false ,
80
+ /* reserve=*/ false );
81
+ }
63
82
}
64
83
}
65
84
@@ -68,6 +87,8 @@ LiveBucketIndex::LiveBucketIndex(BucketManager const& bm, Archive& ar,
68
87
std::streamoff pageSize)
69
88
70
89
: mDiskIndex (std::make_unique<DiskIndex<LiveBucket>>(ar, bm, pageSize))
90
+ , mCacheHitMeter (bm.getCacheHitMeter())
91
+ , mCacheMissMeter (bm.getCacheMissMeter())
71
92
{
72
93
// Only disk indexes are serialized
73
94
releaseAssertOrThrow (pageSize != 0 );
@@ -108,11 +129,39 @@ LiveBucketIndex::markBloomMiss() const
108
129
mDiskIndex ->markBloomMiss ();
109
130
}
110
131
132
+ std::shared_ptr<BucketEntry const >
133
+ LiveBucketIndex::getCachedEntry (LedgerKey const & k) const
134
+ {
135
+ if (shouldUseCache ())
136
+ {
137
+ std::shared_lock<std::shared_mutex> lock (mCacheMutex );
138
+ auto cachePtr = mCache ->maybeGet (k);
139
+ if (cachePtr)
140
+ {
141
+ mCacheHitMeter .Mark ();
142
+ return *cachePtr;
143
+ }
144
+
145
+ // In the case of a bloom filter false positive, we might have a cache
146
+ // "miss" because we're searching for something that doesn't exist. We
147
+ // don't cache non-existent entries, so we don't meter misses here.
148
+ // Instead, we track misses when we insert a new entry, since we always
149
+ // insert a new entry into the cache after a miss.
150
+ }
151
+
152
+ return nullptr ;
153
+ }
154
+
111
155
IndexReturnT
112
156
LiveBucketIndex::lookup (LedgerKey const & k) const
113
157
{
114
158
if (mDiskIndex )
115
159
{
160
+ if (auto cached = getCachedEntry (k); cached)
161
+ {
162
+ return IndexReturnT (cached);
163
+ }
164
+
116
165
return mDiskIndex ->scan (mDiskIndex ->begin (), k).first ;
117
166
}
118
167
else
@@ -127,6 +176,11 @@ LiveBucketIndex::scan(IterT start, LedgerKey const& k) const
127
176
{
128
177
if (mDiskIndex )
129
178
{
179
+ if (auto cached = getCachedEntry (k); cached)
180
+ {
181
+ return {IndexReturnT (cached), start};
182
+ }
183
+
130
184
return mDiskIndex ->scan (getDiskIter (start), k);
131
185
}
132
186
@@ -207,6 +261,24 @@ LiveBucketIndex::getBucketEntryCounters() const
207
261
return mInMemoryIndex ->getBucketEntryCounters ();
208
262
}
209
263
264
+ void
265
+ LiveBucketIndex::maybeAddToCache (
266
+ std::shared_ptr<BucketEntry const > const & entry) const
267
+ {
268
+ if (shouldUseCache ())
269
+ {
270
+ releaseAssertOrThrow (entry);
271
+ auto k = getBucketLedgerKey (*entry);
272
+
273
+ // If we are adding an entry to the cache, we must have missed it
274
+ // earlier.
275
+ mCacheMissMeter .Mark ();
276
+
277
+ std::unique_lock<std::shared_mutex> lock (mCacheMutex );
278
+ mCache ->put (k, entry);
279
+ }
280
+ }
281
+
210
282
#ifdef BUILD_TESTS
211
283
bool
212
284
LiveBucketIndex::operator ==(LiveBucketIndex const & in) const
0 commit comments