Skip to content

Commit 60263de

Browse files
authored
Merge pull request #4274 from SirTyson/bucketlistdb-better-metrics
Seperate metrics for bloom miss loads Reviewed-by: marta-lokhova
2 parents b6db239 + a0abaa6 commit 60263de

8 files changed

+90
-58
lines changed

Diff for: docs/metrics.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ bucketlistDB.bulk.loads | meter | number of entries Bucket
3838
bucketlistDB.bulk.inflationWinners | timer | time to load inflation winners
3939
bucketlistDB.bulk.poolshareTrustlines | timer | time to load poolshare trustlines by accountID and assetID
4040
bucketlistDB.bulk.prefetch | timer | time to prefetch
41-
bucketlistDB.point.<X> | timer | time to load single entry of type <X>
41+
bucketlistDB.point.<X> | timer | time to load single entry of type <X> (if no bloom miss occurred)
4242
herder.pending[-soroban]-txs.age0 | counter | number of gen0 pending transactions
4343
herder.pending[-soroban]-txs.age1 | counter | number of gen1 pending transactions
4444
herder.pending[-soroban]-txs.age2 | counter | number of gen2 pending transactions

Diff for: src/bucket/BucketListSnapshot.cpp

+12-6
Original file line numberDiff line numberDiff line change
@@ -125,22 +125,28 @@ SearchableBucketListSnapshot::getLedgerEntry(LedgerKey const& k)
125125

126126
if (threadIsMain())
127127
{
128-
auto timer = mSnapshotManager.getPointLoadTimer(k.type()).TimeScope();
129-
return getLedgerEntryInternal(k);
128+
mSnapshotManager.startPointLoadTimer();
129+
auto [result, bloomMiss] = getLedgerEntryInternal(k);
130+
mSnapshotManager.endPointLoadTimer(k.type(), bloomMiss);
131+
return result;
130132
}
131133
else
132134
{
133-
return getLedgerEntryInternal(k);
135+
auto [result, bloomMiss] = getLedgerEntryInternal(k);
136+
return result;
134137
}
135138
}
136139

137-
std::shared_ptr<LedgerEntry>
140+
std::pair<std::shared_ptr<LedgerEntry>, bool>
138141
SearchableBucketListSnapshot::getLedgerEntryInternal(LedgerKey const& k)
139142
{
140143
std::shared_ptr<LedgerEntry> result{};
144+
auto sawBloomMiss = false;
141145

142146
auto f = [&](BucketSnapshot const& b) {
143-
auto be = b.getBucketEntry(k);
147+
auto [be, bloomMiss] = b.getBucketEntry(k);
148+
sawBloomMiss = sawBloomMiss || bloomMiss;
149+
144150
if (be.has_value())
145151
{
146152
result =
@@ -156,7 +162,7 @@ SearchableBucketListSnapshot::getLedgerEntryInternal(LedgerKey const& k)
156162
};
157163

158164
loopAllBuckets(f);
159-
return result;
165+
return {result, sawBloomMiss};
160166
}
161167

162168
std::vector<LedgerEntry>

Diff for: src/bucket/BucketListSnapshot.h

+4-1
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,10 @@ class SearchableBucketListSnapshot : public NonMovableOrCopyable
6868
std::vector<LedgerEntry>
6969
loadKeysInternal(std::set<LedgerKey, LedgerEntryIdCmp> const& inKeys);
7070

71-
std::shared_ptr<LedgerEntry> getLedgerEntryInternal(LedgerKey const& k);
71+
// Loads bucket entry for LedgerKey k. Returns <LedgerEntry, bloomMiss>,
72+
// where bloomMiss is true if a bloom miss occurred during the load.
73+
std::pair<std::shared_ptr<LedgerEntry>, bool>
74+
getLedgerEntryInternal(LedgerKey const& k);
7275

7376
SearchableBucketListSnapshot(BucketSnapshotManager const& snapshotManager);
7477

Diff for: src/bucket/BucketManagerImpl.cpp

+1-2
Original file line numberDiff line numberDiff line change
@@ -126,8 +126,7 @@ BucketManagerImpl::initialize()
126126
if (mApp.getConfig().isUsingBucketListDB())
127127
{
128128
mSnapshotManager = std::make_unique<BucketSnapshotManager>(
129-
mApp.getMetrics(),
130-
std::make_unique<BucketListSnapshot>(*mBucketList, 0));
129+
mApp, std::make_unique<BucketListSnapshot>(*mBucketList, 0));
131130
}
132131
}
133132
}

Diff for: src/bucket/BucketSnapshot.cpp

+10-10
Original file line numberDiff line numberDiff line change
@@ -31,14 +31,14 @@ BucketSnapshot::isEmpty() const
3131
return mBucket->isEmpty();
3232
}
3333

34-
std::optional<BucketEntry>
34+
std::pair<std::optional<BucketEntry>, bool>
3535
BucketSnapshot::getEntryAtOffset(LedgerKey const& k, std::streamoff pos,
3636
size_t pageSize) const
3737
{
3838
ZoneScoped;
3939
if (isEmpty())
4040
{
41-
return std::nullopt;
41+
return {std::nullopt, false};
4242
}
4343

4444
auto& stream = getStream();
@@ -49,26 +49,26 @@ BucketSnapshot::getEntryAtOffset(LedgerKey const& k, std::streamoff pos,
4949
{
5050
if (stream.readOne(be))
5151
{
52-
return std::make_optional(be);
52+
return {std::make_optional(be), false};
5353
}
5454
}
5555
else if (stream.readPage(be, k, pageSize))
5656
{
57-
return std::make_optional(be);
57+
return {std::make_optional(be), false};
5858
}
5959

6060
// Mark entry miss for metrics
6161
mBucket->getIndex().markBloomMiss();
62-
return std::nullopt;
62+
return {std::nullopt, true};
6363
}
6464

65-
std::optional<BucketEntry>
65+
std::pair<std::optional<BucketEntry>, bool>
6666
BucketSnapshot::getBucketEntry(LedgerKey const& k) const
6767
{
6868
ZoneScoped;
6969
if (isEmpty())
7070
{
71-
return std::nullopt;
71+
return {std::nullopt, false};
7272
}
7373

7474
auto pos = mBucket->getIndex().lookup(k);
@@ -78,7 +78,7 @@ BucketSnapshot::getBucketEntry(LedgerKey const& k) const
7878
mBucket->getIndex().getPageSize());
7979
}
8080

81-
return std::nullopt;
81+
return {std::nullopt, false};
8282
}
8383

8484
// When searching for an entry, BucketList calls this function on every bucket.
@@ -105,8 +105,8 @@ BucketSnapshot::loadKeys(std::set<LedgerKey, LedgerEntryIdCmp>& keys,
105105
indexIter = newIndexIter;
106106
if (offOp)
107107
{
108-
auto entryOp = getEntryAtOffset(*currKeyIt, *offOp,
109-
mBucket->getIndex().getPageSize());
108+
auto [entryOp, bloomMiss] = getEntryAtOffset(
109+
*currKeyIt, *offOp, mBucket->getIndex().getPageSize());
110110
if (entryOp)
111111
{
112112
if (entryOp->type() != DEADENTRY)

Diff for: src/bucket/BucketSnapshot.h

+10-6
Original file line numberDiff line numberDiff line change
@@ -33,10 +33,12 @@ class BucketSnapshot : public NonMovable
3333
XDRInputFileStream& getStream() const;
3434

3535
// Loads the bucket entry for LedgerKey k. Starts at file offset pos and
36-
// reads until key is found or the end of the page.
37-
std::optional<BucketEntry> getEntryAtOffset(LedgerKey const& k,
38-
std::streamoff pos,
39-
size_t pageSize) const;
36+
// reads until key is found or the end of the page. Returns <BucketEntry,
37+
// bloomMiss>, where bloomMiss is true if a bloomMiss occurred during the
38+
// load.
39+
std::pair<std::optional<BucketEntry>, bool>
40+
getEntryAtOffset(LedgerKey const& k, std::streamoff pos,
41+
size_t pageSize) const;
4042

4143
BucketSnapshot(std::shared_ptr<Bucket const> const b);
4244

@@ -48,8 +50,10 @@ class BucketSnapshot : public NonMovable
4850
bool isEmpty() const;
4951
std::shared_ptr<Bucket const> getRawBucket() const;
5052

51-
// Loads bucket entry for LedgerKey k.
52-
std::optional<BucketEntry> getBucketEntry(LedgerKey const& k) const;
53+
// Loads bucket entry for LedgerKey k. Returns <BucketEntry, bloomMiss>,
54+
// where bloomMiss is true if a bloomMiss occurred during the load.
55+
std::pair<std::optional<BucketEntry>, bool>
56+
getBucketEntry(LedgerKey const& k) const;
5357

5458
// Loads LedgerEntry's for given keys. When a key is found, the
5559
// entry is added to result and the key is removed from keys.

Diff for: src/bucket/BucketSnapshotManager.cpp

+45-28
Original file line numberDiff line numberDiff line change
@@ -13,16 +13,15 @@ namespace stellar
1313
{
1414

1515
BucketSnapshotManager::BucketSnapshotManager(
16-
medida::MetricsRegistry& metrics,
17-
std::unique_ptr<BucketListSnapshot const>&& snapshot)
18-
: mMetrics(metrics)
16+
Application& app, std::unique_ptr<BucketListSnapshot const>&& snapshot)
17+
: mApp(app)
1918
, mCurrentSnapshot(std::move(snapshot))
20-
, mBulkLoadMeter(
21-
mMetrics.NewMeter({"bucketlistDB", "query", "loads"}, "query"))
22-
, mBloomMisses(
23-
mMetrics.NewMeter({"bucketlistDB", "bloom", "misses"}, "bloom"))
24-
, mBloomLookups(
25-
mMetrics.NewMeter({"bucketlistDB", "bloom", "lookups"}, "bloom"))
19+
, mBulkLoadMeter(app.getMetrics().NewMeter(
20+
{"bucketlistDB", "query", "loads"}, "query"))
21+
, mBloomMisses(app.getMetrics().NewMeter(
22+
{"bucketlistDB", "bloom", "misses"}, "bloom"))
23+
, mBloomLookups(app.getMetrics().NewMeter(
24+
{"bucketlistDB", "bloom", "lookups"}, "bloom"))
2625
{
2726
releaseAssert(threadIsMain());
2827
}
@@ -51,31 +50,14 @@ BucketSnapshotManager::recordBulkLoadMetrics(std::string const& label,
5150
auto iter = mBulkTimers.find(label);
5251
if (iter == mBulkTimers.end())
5352
{
54-
auto& metric = mMetrics.NewTimer({"bucketlistDB", "bulk", label});
53+
auto& metric =
54+
mApp.getMetrics().NewTimer({"bucketlistDB", "bulk", label});
5555
iter = mBulkTimers.emplace(label, metric).first;
5656
}
5757

5858
return iter->second;
5959
}
6060

61-
medida::Timer&
62-
BucketSnapshotManager::getPointLoadTimer(LedgerEntryType t) const
63-
{
64-
// For now, only keep metrics for the main thread. We can decide on what
65-
// metrics make sense when more background services are added later.
66-
releaseAssert(threadIsMain());
67-
68-
auto iter = mPointTimers.find(t);
69-
if (iter == mPointTimers.end())
70-
{
71-
auto const& label = xdr::xdr_traits<LedgerEntryType>::enum_name(t);
72-
auto& metric = mMetrics.NewTimer({"bucketlistDB", "point", label});
73-
iter = mPointTimers.emplace(t, metric).first;
74-
}
75-
76-
return iter->second;
77-
}
78-
7961
void
8062
BucketSnapshotManager::maybeUpdateSnapshot(
8163
std::unique_ptr<BucketListSnapshot const>& snapshot) const
@@ -102,4 +84,39 @@ BucketSnapshotManager::updateCurrentSnapshot(
10284
mCurrentSnapshot->getLedgerSeq());
10385
mCurrentSnapshot.swap(newSnapshot);
10486
}
87+
88+
void
89+
BucketSnapshotManager::startPointLoadTimer() const
90+
{
91+
releaseAssert(threadIsMain());
92+
releaseAssert(!mTimerStart);
93+
mTimerStart = mApp.getClock().now();
94+
}
95+
96+
void
97+
BucketSnapshotManager::endPointLoadTimer(LedgerEntryType t,
98+
bool bloomMiss) const
99+
{
100+
releaseAssert(threadIsMain());
101+
releaseAssert(mTimerStart);
102+
auto duration = mApp.getClock().now() - *mTimerStart;
103+
mTimerStart.reset();
104+
105+
// We expect about 0.1% of lookups to encounter a bloom miss. To avoid noise
106+
// in disk performance metrics, we only track metrics for entries that did
107+
// not encounter a bloom miss.
108+
if (!bloomMiss)
109+
{
110+
auto iter = mPointTimers.find(t);
111+
if (iter == mPointTimers.end())
112+
{
113+
auto const& label = xdr::xdr_traits<LedgerEntryType>::enum_name(t);
114+
auto& metric =
115+
mApp.getMetrics().NewTimer({"bucketlistDB", "point", label});
116+
iter = mPointTimers.emplace(t, metric).first;
117+
}
118+
119+
iter->second.Update(duration);
120+
}
121+
}
105122
}

Diff for: src/bucket/BucketSnapshotManager.h

+7-4
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ class BucketListSnapshot;
3232
class BucketSnapshotManager : NonMovableOrCopyable
3333
{
3434
private:
35-
medida::MetricsRegistry& mMetrics;
35+
Application& mApp;
3636

3737
// Snapshot that is maintained and periodically updated by BucketManager on
3838
// the main thread. When background threads need to generate or refresh a
@@ -49,6 +49,8 @@ class BucketSnapshotManager : NonMovableOrCopyable
4949
medida::Meter& mBloomMisses;
5050
medida::Meter& mBloomLookups;
5151

52+
mutable std::optional<VirtualClock::time_point> mTimerStart;
53+
5254
// Called by main thread to update mCurrentSnapshot whenever the BucketList
5355
// is updated
5456
void updateCurrentSnapshot(
@@ -65,7 +67,7 @@ class BucketSnapshotManager : NonMovableOrCopyable
6567
bool restartMerges);
6668

6769
public:
68-
BucketSnapshotManager(medida::MetricsRegistry& metrics,
70+
BucketSnapshotManager(Application& app,
6971
std::unique_ptr<BucketListSnapshot const>&& snapshot);
7072

7173
std::unique_ptr<SearchableBucketListSnapshot>
@@ -76,9 +78,10 @@ class BucketSnapshotManager : NonMovableOrCopyable
7678
void maybeUpdateSnapshot(
7779
std::unique_ptr<BucketListSnapshot const>& snapshot) const;
7880

81+
// All metric recording functions must only be called by the main thread
82+
void startPointLoadTimer() const;
83+
void endPointLoadTimer(LedgerEntryType t, bool bloomMiss) const;
7984
medida::Timer& recordBulkLoadMetrics(std::string const& label,
8085
size_t numEntries) const;
81-
82-
medida::Timer& getPointLoadTimer(LedgerEntryType t) const;
8386
};
8487
}

0 commit comments

Comments
 (0)