Skip to content

Commit bdc97ad

Browse files
committed
Tightened entry count estimation for Bucket cache
1 parent fc6843e commit bdc97ad

12 files changed

+261
-81
lines changed

src/bucket/BucketManager.cpp

+1-2
Original file line numberDiff line numberDiff line change
@@ -1291,8 +1291,7 @@ BucketManager::assumeState(HistoryArchiveState const& has,
12911291
mLiveBucketList->getLevel(i).setNext(nextFuture);
12921292
}
12931293

1294-
mLiveBucketList->maybeInitializeCaches(
1295-
mConfig.maxAccountsInBucketListCache());
1294+
mLiveBucketList->maybeInitializeCaches(mConfig);
12961295

12971296
if (restartMerges)
12981297
{

src/bucket/LiveBucket.cpp

+14-4
Original file line numberDiff line numberDiff line change
@@ -308,6 +308,17 @@ LiveBucket::apply(Application& app) const
308308
}
309309
counters.logInfo("direct", 0, app.getClock().now());
310310
}
311+
312+
size_t
313+
LiveBucket::getMaxCacheSize() const
314+
{
315+
if (!isEmpty())
316+
{
317+
return getIndex().getMaxCacheSize();
318+
}
319+
320+
return 0;
321+
}
311322
#endif // BUILD_TESTS
312323

313324
std::optional<std::pair<std::streamoff, std::streamoff>>
@@ -432,12 +443,11 @@ LiveBucket::getBucketVersion() const
432443
}
433444

434445
void
435-
LiveBucket::maybeInitializeCache(size_t bucketListTotalAccounts,
436-
size_t maxBucketListAccountsToCache) const
446+
LiveBucket::maybeInitializeCache(size_t totalBucketListAccountsSizeBytes,
447+
Config const& cfg) const
437448
{
438449
releaseAssert(mIndex);
439-
mIndex->maybeInitializeCache(bucketListTotalAccounts,
440-
maxBucketListAccountsToCache);
450+
mIndex->maybeInitializeCache(totalBucketListAccountsSizeBytes, cfg);
441451
}
442452

443453
BucketEntryCounters const&

src/bucket/LiveBucket.h

+7-2
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ class LiveBucket : public BucketBase<LiveBucket, LiveBucketIndex>,
8383
// entry in the database (respectively; if the entry is dead (a
8484
// tombstone), deletes the corresponding entry in the database.
8585
void apply(Application& app) const;
86+
size_t getMaxCacheSize() const;
8687
#endif
8788

8889
// Returns [lowerBound, upperBound) of file offsets for all offers in the
@@ -120,8 +121,12 @@ class LiveBucket : public BucketBase<LiveBucket, LiveBucketIndex>,
120121

121122
uint32_t getBucketVersion() const;
122123

123-
void maybeInitializeCache(size_t bucketListTotalAccounts,
124-
size_t maxBucketListAccountsToCache) const;
124+
// Initializes the random eviction cache if it has not already been
125+
// initialized. totalBucketListAccountsSizeBytes is the total size, in
126+
// bytes, of all BucketEntries in the BucketList that hold ACCOUNT entries,
127+
// including INIT, LIVE and DEAD entries.
128+
void maybeInitializeCache(size_t totalBucketListAccountsSizeBytes,
129+
Config const& cfg) const;
125130

126131
BucketEntryCounters const& getBucketEntryCounters() const;
127132

src/bucket/LiveBucketIndex.cpp

+48-9
Original file line numberDiff line numberDiff line change
@@ -82,8 +82,8 @@ LiveBucketIndex::LiveBucketIndex(BucketManager const& bm, Archive& ar,
8282
}
8383

8484
void
85-
LiveBucketIndex::maybeInitializeCache(size_t bucketListTotalAccounts,
86-
size_t maxBucketListAccountsToCache) const
85+
LiveBucketIndex::maybeInitializeCache(size_t totalBucketListAccountsSizeBytes,
86+
Config const& cfg) const
8787
{
8888
// Everything is already in memory, no need for a redundant cache.
8989
if (mInMemoryIndex)
@@ -109,19 +109,46 @@ LiveBucketIndex::maybeInitializeCache(size_t bucketListTotalAccounts,
109109
return;
110110
}
111111

112+
// Convert from MB to bytes, max size for entire BucketList cache
113+
auto maxBucketListBytesToCache =
114+
cfg.BUCKETLIST_DB_MEMORY_FOR_CACHING * 1024 * 1024;
115+
112116
std::unique_lock<std::shared_mutex> lock(mCacheMutex);
113-
if (bucketListTotalAccounts < maxBucketListAccountsToCache)
117+
if (totalBucketListAccountsSizeBytes < maxBucketListBytesToCache)
114118
{
115119
// We can cache the entire bucket
116-
mCache = std::make_unique<CacheT>(bucketListTotalAccounts);
120+
mCache = std::make_unique<CacheT>(accountsInThisBucket);
117121
}
118122
else
119123
{
120-
double percentAccountsInBucket =
121-
static_cast<double>(accountsInThisBucket) / bucketListTotalAccounts;
122-
auto cacheSize = static_cast<size_t>(bucketListTotalAccounts *
123-
percentAccountsInBucket);
124-
mCache = std::make_unique<CacheT>(cacheSize);
124+
// The random eviction cache has an entry limit, but we expose a memory
125+
// limit in the validator config. We can't do an exact 1 to 1 mapping
126+
// because account entries have different sizes.
127+
//
128+
// First we take the fraction of the total BucketList size that this
129+
// bucket occupies to figure out how much memory to allocate. Then we
130+
// use the average account size to convert that to an entry count for
131+
// the cache.
132+
133+
auto accountBytesInThisBucket =
134+
mDiskIndex->getBucketEntryCounters().entryTypeSizes.at(
135+
LedgerEntryTypeAndDurability::ACCOUNT);
136+
137+
double fractionOfTotalBucketListBytes =
138+
static_cast<double>(accountBytesInThisBucket) /
139+
totalBucketListAccountsSizeBytes;
140+
141+
size_t bytesAvailableForBucketCache = static_cast<size_t>(
142+
maxBucketListBytesToCache * fractionOfTotalBucketListBytes);
143+
144+
double averageAccountSize =
145+
static_cast<double>(accountBytesInThisBucket) /
146+
accountsInThisBucket;
147+
148+
auto accountsToCache = static_cast<size_t>(
149+
bytesAvailableForBucketCache / averageAccountSize);
150+
151+
mCache = std::make_unique<CacheT>(accountsToCache);
125152
}
126153
}
127154

@@ -360,6 +387,18 @@ LiveBucketIndex::operator==(LiveBucketIndex const& in) const
360387

361388
return true;
362389
}
390+
391+
size_t
392+
LiveBucketIndex::getMaxCacheSize() const
393+
{
394+
if (shouldUseCache())
395+
{
396+
std::shared_lock<std::shared_mutex> lock(mCacheMutex);
397+
return mCache->maxSize();
398+
}
399+
400+
return 0;
401+
}
363402
#endif
364403

365404
template LiveBucketIndex::LiveBucketIndex(BucketManager const& bm,

src/bucket/LiveBucketIndex.h

+7-4
Original file line numberDiff line numberDiff line change
@@ -113,8 +113,12 @@ class LiveBucketIndex : public NonMovableOrCopyable
113113
// expose a memory limit in the validator config. To account for this, we
114114
// check what percentage of the total number of accounts are in this bucket
115115
// and allocate space accordingly.
116-
void maybeInitializeCache(size_t bucketListTotalAccounts,
117-
size_t maxBucketListAccountsToCache) const;
116+
//
117+
// bucketListTotalAccountSizeBytes is the total size, in bytes, of all
118+
// BucketEntries in the BucketList that hold ACCOUNT entries, including
119+
// INIT, LIVE and DEAD entries.
120+
void maybeInitializeCache(size_t bucketListTotalAccountSizeBytes,
121+
Config const& cfg) const;
118122

119123
// Returns true if LedgerEntryType not supported by BucketListDB
120124
static bool typeNotSupported(LedgerEntryType t);
@@ -142,8 +146,7 @@ class LiveBucketIndex : public NonMovableOrCopyable
142146
void markBloomMiss() const;
143147
#ifdef BUILD_TESTS
144148
bool operator==(LiveBucketIndex const& in) const;
145-
146-
void clearCache() const;
149+
size_t getMaxCacheSize() const;
147150
#endif
148151
};
149152
}

src/bucket/LiveBucketList.cpp

+8-9
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ LiveBucketList::addBatch(Application& app, uint32_t currLedger,
2323
liveEntries, deadEntries);
2424

2525
// Initialize caches for any new buckets we might have added
26-
maybeInitializeCaches(app.getConfig().maxAccountsInBucketListCache());
26+
maybeInitializeCaches(app.getConfig());
2727
}
2828

2929
BucketEntryCounters
@@ -34,7 +34,7 @@ LiveBucketList::sumBucketEntryCounters() const
3434
{
3535
for (auto const& b : {lev.getCurr(), lev.getSnap()})
3636
{
37-
if (b->isIndexed())
37+
if (!b->isEmpty())
3838
{
3939
auto c = b->getBucketEntryCounters();
4040
counters += c;
@@ -45,25 +45,24 @@ LiveBucketList::sumBucketEntryCounters() const
4545
}
4646

4747
void
48-
LiveBucketList::maybeInitializeCaches(size_t maxBucketListAccountsToCache) const
48+
LiveBucketList::maybeInitializeCaches(Config const& cfg) const
4949
{
5050
auto blCounters = sumBucketEntryCounters();
51-
size_t totalAccounts =
52-
blCounters.entryTypeCounts.at(LedgerEntryTypeAndDurability::ACCOUNT);
51+
size_t totalAccountsSize =
52+
blCounters.entryTypeSizes.at(LedgerEntryTypeAndDurability::ACCOUNT);
53+
5354
for (uint32_t i = 0; i < kNumLevels; ++i)
5455
{
5556
auto curr = mLevels[i].getCurr();
5657
if (!curr->isEmpty())
5758
{
58-
curr->maybeInitializeCache(totalAccounts,
59-
maxBucketListAccountsToCache);
59+
curr->maybeInitializeCache(totalAccountsSize, cfg);
6060
}
6161

6262
auto snap = mLevels[i].getSnap();
6363
if (!snap->isEmpty())
6464
{
65-
snap->maybeInitializeCache(totalAccounts,
66-
maxBucketListAccountsToCache);
65+
snap->maybeInitializeCache(totalAccountsSize, cfg);
6766
}
6867
}
6968
}

src/bucket/LiveBucketList.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ class LiveBucketList : public BucketListBase<LiveBucket>
5353

5454
// Initializes any uninitialized caches in the BucketIndex. Should be called
5555
// after every time buckets may have changed in the LiveBucketList.
56-
void maybeInitializeCaches(size_t maxBucketListAccountsToCache) const;
56+
void maybeInitializeCaches(Config const& cfg) const;
5757
};
5858

5959
}

0 commit comments

Comments
 (0)