reth_trie/hashed_cursor/
metrics.rs1use super::{HashedCursor, HashedStorageCursor};
2use alloy_primitives::B256;
3use reth_primitives_traits::FastInstant as Instant;
4use reth_storage_errors::db::DatabaseError;
5use std::time::Duration;
6use tracing::trace_span;
7
8#[cfg(feature = "metrics")]
9use crate::TrieType;
10#[cfg(feature = "metrics")]
11use reth_metrics::metrics::{self, Histogram};
12
13#[cfg(feature = "metrics")]
17#[derive(Clone, Debug)]
18pub struct HashedCursorMetrics {
19 overall_duration: Histogram,
21 next_histogram: Histogram,
23 seek_histogram: Histogram,
25 is_storage_empty_histogram: Histogram,
27}
28
29#[cfg(feature = "metrics")]
30impl HashedCursorMetrics {
31 pub fn new(trie_type: TrieType) -> Self {
33 let trie_type_str = trie_type.as_str();
34
35 Self {
36 overall_duration: metrics::histogram!(
37 "trie.hashed_cursor.overall_duration",
38 "type" => trie_type_str
39 ),
40 next_histogram: metrics::histogram!(
41 "trie.hashed_cursor.operations",
42 "type" => trie_type_str,
43 "operation" => "next"
44 ),
45 seek_histogram: metrics::histogram!(
46 "trie.hashed_cursor.operations",
47 "type" => trie_type_str,
48 "operation" => "seek"
49 ),
50 is_storage_empty_histogram: metrics::histogram!(
51 "trie.hashed_cursor.operations",
52 "type" => trie_type_str,
53 "operation" => "is_storage_empty"
54 ),
55 }
56 }
57
58 pub fn record(&mut self, cache: &mut HashedCursorMetricsCache) {
63 self.next_histogram.record(cache.next_count as f64);
64 self.seek_histogram.record(cache.seek_count as f64);
65 self.is_storage_empty_histogram.record(cache.is_storage_empty_count as f64);
66 self.overall_duration.record(cache.total_duration.as_secs_f64());
67 cache.reset();
68 }
69}
70
71#[derive(Debug, Copy, Clone)]
73pub struct HashedCursorMetricsCache {
74 pub next_count: usize,
76 pub seek_count: usize,
78 pub is_storage_empty_count: usize,
80 pub total_duration: Duration,
82}
83
84impl Default for HashedCursorMetricsCache {
85 fn default() -> Self {
86 Self {
87 next_count: 0,
88 seek_count: 0,
89 is_storage_empty_count: 0,
90 total_duration: Duration::ZERO,
91 }
92 }
93}
94
95impl HashedCursorMetricsCache {
96 pub const fn reset(&mut self) {
98 self.next_count = 0;
99 self.seek_count = 0;
100 self.is_storage_empty_count = 0;
101 self.total_duration = Duration::ZERO;
102 }
103
104 pub fn extend(&mut self, other: &Self) {
108 self.next_count += other.next_count;
109 self.seek_count += other.seek_count;
110 self.is_storage_empty_count += other.is_storage_empty_count;
111 self.total_duration += other.total_duration;
112 }
113
114 pub fn record_span(&self, name: &'static str) {
116 let _span = trace_span!(
117 target: "trie::trie_cursor",
118 "Hashed cursor metrics",
119 name,
120 next_count = self.next_count,
121 seek_count = self.seek_count,
122 is_storage_empty_count = self.is_storage_empty_count,
123 total_duration = self.total_duration.as_secs_f64(),
124 )
125 .entered();
126 }
127}
128
129#[derive(Debug)]
135pub struct InstrumentedHashedCursor<'metrics, C> {
136 cursor: C,
138 metrics: &'metrics mut HashedCursorMetricsCache,
140}
141
142impl<'metrics, C> InstrumentedHashedCursor<'metrics, C> {
143 pub const fn new(cursor: C, metrics: &'metrics mut HashedCursorMetricsCache) -> Self {
145 Self { cursor, metrics }
146 }
147}
148
149impl<'metrics, C> HashedCursor for InstrumentedHashedCursor<'metrics, C>
150where
151 C: HashedCursor,
152{
153 type Value = C::Value;
154
155 fn seek(&mut self, key: B256) -> Result<Option<(B256, Self::Value)>, DatabaseError> {
156 let start = Instant::now();
157 self.metrics.seek_count += 1;
158 let result = self.cursor.seek(key);
159 self.metrics.total_duration += start.elapsed();
160 result
161 }
162
163 fn next(&mut self) -> Result<Option<(B256, Self::Value)>, DatabaseError> {
164 let start = Instant::now();
165 self.metrics.next_count += 1;
166 let result = self.cursor.next();
167 self.metrics.total_duration += start.elapsed();
168 result
169 }
170
171 fn reset(&mut self) {
172 self.cursor.reset()
173 }
174}
175
176impl<'metrics, C> HashedStorageCursor for InstrumentedHashedCursor<'metrics, C>
177where
178 C: HashedStorageCursor,
179{
180 fn is_storage_empty(&mut self) -> Result<bool, DatabaseError> {
181 let start = Instant::now();
182 self.metrics.is_storage_empty_count += 1;
183 let result = self.cursor.is_storage_empty();
184 self.metrics.total_duration += start.elapsed();
185 result
186 }
187
188 fn set_hashed_address(&mut self, hashed_address: B256) {
189 self.cursor.set_hashed_address(hashed_address)
190 }
191}