@@ -53,27 +53,44 @@ BucketListSnapshotData<BucketT>::BucketListSnapshotData(
5353{
5454}
5555
56+ //
57+ // BucketSnapshotMetrics
58+ //
59+
60+ template <class BucketT >
61+ BucketSnapshotMetrics<BucketT>::BucketSnapshotMetrics(MetricsRegistry& metrics)
62+ : mPointTimers ([&metrics]() {
63+ UnorderedMap<LedgerEntryType, std::reference_wrapper<SimpleTimer>>
64+ timers;
65+ for (auto t : xdr::xdr_traits<LedgerEntryType>::enum_values ())
66+ {
67+ auto const & label = xdr::xdr_traits<LedgerEntryType>::enum_name (
68+ static_cast <LedgerEntryType>(t));
69+ auto & metric = metrics.NewSimpleTimer (
70+ {BucketT::METRIC_STRING , label}, std::chrono::microseconds{1 });
71+ timers.emplace (static_cast <LedgerEntryType>(t), metric);
72+ }
73+ return timers;
74+ }())
75+ , mBulkLoadMeter (
76+ metrics.NewMeter({BucketT::METRIC_STRING , " query" , " loads" }, " query" ))
77+ {
78+ }
79+
5680//
5781// SearchableBucketListSnapshot
5882//
5983
6084template <class BucketT >
6185SearchableBucketListSnapshot<BucketT>::SearchableBucketListSnapshot(
6286 MetricsRegistry& metrics,
87+ std::shared_ptr<BucketSnapshotMetrics<BucketT> const > snapshotMetrics,
6388 std::shared_ptr<BucketListSnapshotData<BucketT> const > data)
6489 : mData (std::move(data))
6590 , mMetrics (metrics)
66- , mBulkLoadMeter (
67- metrics.NewMeter({BucketT::METRIC_STRING , " query" , " loads" }, " query" ))
91+ , mSnapshotMetrics (std::move(snapshotMetrics))
6892{
69- for (auto t : xdr::xdr_traits<LedgerEntryType>::enum_values ())
70- {
71- auto const & label = xdr::xdr_traits<LedgerEntryType>::enum_name (
72- static_cast <LedgerEntryType>(t));
73- auto & metric = metrics.NewSimpleTimer ({BucketT::METRIC_STRING , label},
74- std::chrono::microseconds{1 });
75- mPointTimers .emplace (static_cast <LedgerEntryType>(t), metric);
76- }
93+ releaseAssert (mSnapshotMetrics );
7794}
7895
7996template <class BucketT >
@@ -82,9 +99,8 @@ SearchableBucketListSnapshot<BucketT>::SearchableBucketListSnapshot(
8299 : mData (other.mData )
83100 // mStreams intentionally left empty — each copy gets its own stream cache
84101 , mMetrics (other.mMetrics )
85- , mPointTimers (other.mPointTimers )
102+ , mSnapshotMetrics (other.mSnapshotMetrics )
86103 , mBulkTimers (other.mBulkTimers )
87- , mBulkLoadMeter (other.mBulkLoadMeter )
88104{
89105}
90106
@@ -98,12 +114,11 @@ SearchableBucketListSnapshot<BucketT>::operator=(
98114 mData = other.mData ;
99115 mStreams .clear ();
100116 mMetrics = other.mMetrics ;
101- mPointTimers = other.mPointTimers ;
117+ mSnapshotMetrics = other.mSnapshotMetrics ;
102118 mBulkTimers = other.mBulkTimers ;
103- mBulkLoadMeter = other.mBulkLoadMeter ;
104119#ifdef BUILD_TESTS
105120 // Reset thread ownership so the copy can be claimed by another thread.
106- mThreadId = std::thread::id{};
121+ mThreadId . store ( std::thread::id{}) ;
107122#endif
108123 }
109124 return *this ;
@@ -119,14 +134,13 @@ void
119134SearchableBucketListSnapshot<BucketT>::threadInvariant() const
120135{
121136#ifdef BUILD_TESTS
122- auto current = std::this_thread::get_id ();
123- if (mThreadId == std::thread::id{})
124- {
125- mThreadId = current;
126- }
127- else
137+ auto const current = std::this_thread::get_id ();
138+ std::thread::id unclaimed{};
139+ // Atomically claim ownership on first use, so any concurrent claimant sees
140+ // the CAS fail with `unclaimed` set to the owner's id and asserts.
141+ if (!mThreadId .compare_exchange_strong (unclaimed, current))
128142 {
129- releaseAssert (mThreadId == current);
143+ releaseAssert (unclaimed == current);
130144 }
131145#endif
132146}
@@ -336,8 +350,8 @@ SearchableBucketListSnapshot<BucketT>::load(LedgerKey const& k) const
336350 releaseAssert (mData );
337351 threadInvariant ();
338352
339- auto timerIter = mPointTimers .find (k.type ());
340- releaseAssert (timerIter != mPointTimers .end ());
353+ auto timerIter = mSnapshotMetrics -> mPointTimers .find (k.type ());
354+ releaseAssert (timerIter != mSnapshotMetrics -> mPointTimers .end ());
341355 auto timer = timerIter->second .get ().TimeScope ();
342356
343357 std::shared_ptr<typename BucketT::LoadT const > result{};
@@ -375,7 +389,7 @@ SearchableBucketListSnapshot<BucketT>::getBulkLoadTimer(
375389 threadInvariant ();
376390 if (numEntries != 0 )
377391 {
378- mBulkLoadMeter .get ().Mark (numEntries);
392+ mSnapshotMetrics -> mBulkLoadMeter .get ().Mark (numEntries);
379393 }
380394
381395 auto iter = mBulkTimers .find (label);
@@ -402,8 +416,10 @@ SearchableBucketListSnapshot<BucketT>::getSnapshotData() const
402416
403417SearchableLiveBucketListSnapshot::SearchableLiveBucketListSnapshot (
404418 MetricsRegistry& metrics,
419+ std::shared_ptr<BucketSnapshotMetrics<LiveBucket> const > snapshotMetrics,
405420 std::shared_ptr<BucketListSnapshotData<LiveBucket> const > data)
406- : SearchableBucketListSnapshot<LiveBucket>(metrics, std::move(data))
421+ : SearchableBucketListSnapshot<LiveBucket>(
422+ metrics, std::move(snapshotMetrics), std::move(data))
407423{
408424}
409425
@@ -843,8 +859,11 @@ SearchableLiveBucketListSnapshot::scanForEvictionInBucket(
843859
844860SearchableHotArchiveBucketListSnapshot::SearchableHotArchiveBucketListSnapshot (
845861 MetricsRegistry& metrics,
862+ std::shared_ptr<BucketSnapshotMetrics<HotArchiveBucket> const >
863+ snapshotMetrics,
846864 std::shared_ptr<BucketListSnapshotData<HotArchiveBucket> const > data)
847- : SearchableBucketListSnapshot<HotArchiveBucket>(metrics, std::move(data))
865+ : SearchableBucketListSnapshot<HotArchiveBucket>(
866+ metrics, std::move(snapshotMetrics), std::move(data))
848867{
849868}
850869
@@ -879,6 +898,8 @@ SearchableHotArchiveBucketListSnapshot::scanAllEntries(
879898// Explicit template instantiations
880899template struct BucketListSnapshotData <LiveBucket>;
881900template struct BucketListSnapshotData <HotArchiveBucket>;
901+ template struct BucketSnapshotMetrics <LiveBucket>;
902+ template struct BucketSnapshotMetrics <HotArchiveBucket>;
882903template class SearchableBucketListSnapshot <LiveBucket>;
883904template class SearchableBucketListSnapshot <HotArchiveBucket>;
884905
0 commit comments