reth_trie/hashed_cursor/
metrics.rs1use super::{HashedCursor, HashedCursorFactory, HashedStorageCursor};
2use crate::TrieType;
3use alloy_primitives::B256;
4use reth_metrics::metrics::{self, Histogram};
5use reth_primitives_traits::FastInstant as Instant;
6use reth_storage_errors::db::DatabaseError;
7use std::time::Duration;
8
9#[derive(Clone, Debug)]
13pub struct HashedCursorMetrics {
14 overall_duration_seconds: Histogram,
16 next_histogram: Histogram,
18 seek_histogram: Histogram,
20 is_storage_empty_histogram: Histogram,
22}
23
24impl HashedCursorMetrics {
25 pub fn new(trie_type: TrieType) -> Self {
27 let trie_type_str = trie_type.as_str();
28
29 Self {
30 overall_duration_seconds: metrics::histogram!(
31 "trie.hashed_cursor.overall_duration_seconds",
32 "type" => trie_type_str
33 ),
34 next_histogram: metrics::histogram!(
35 "trie.hashed_cursor.operations",
36 "type" => trie_type_str,
37 "operation" => "next"
38 ),
39 seek_histogram: metrics::histogram!(
40 "trie.hashed_cursor.operations",
41 "type" => trie_type_str,
42 "operation" => "seek"
43 ),
44 is_storage_empty_histogram: metrics::histogram!(
45 "trie.hashed_cursor.operations",
46 "type" => trie_type_str,
47 "operation" => "is_storage_empty"
48 ),
49 }
50 }
51
52 pub fn instrument<C>(&self, cursor: C) -> InstrumentedHashedCursor<C> {
54 InstrumentedHashedCursor {
55 cursor,
56 metrics: self.clone(),
57 next_count: 0,
58 seek_count: 0,
59 is_storage_empty_count: 0,
60 total_duration: Duration::ZERO,
61 }
62 }
63}
64
65#[derive(Debug)]
73pub struct InstrumentedHashedCursor<C> {
74 cursor: C,
76 metrics: HashedCursorMetrics,
78 next_count: usize,
80 seek_count: usize,
82 is_storage_empty_count: usize,
84 total_duration: Duration,
86}
87
88impl<C> HashedCursor for InstrumentedHashedCursor<C>
89where
90 C: HashedCursor,
91{
92 type Value = C::Value;
93
94 fn seek(&mut self, key: B256) -> Result<Option<(B256, Self::Value)>, DatabaseError> {
95 let start = Instant::now();
96 self.seek_count += 1;
97 let result = self.cursor.seek(key);
98 self.total_duration += start.elapsed();
99 result
100 }
101
102 fn next(&mut self) -> Result<Option<(B256, Self::Value)>, DatabaseError> {
103 let start = Instant::now();
104 self.next_count += 1;
105 let result = self.cursor.next();
106 self.total_duration += start.elapsed();
107 result
108 }
109
110 fn reset(&mut self) {
111 self.cursor.reset()
112 }
113}
114
115impl<C> HashedStorageCursor for InstrumentedHashedCursor<C>
116where
117 C: HashedStorageCursor,
118{
119 fn is_storage_empty(&mut self) -> Result<bool, DatabaseError> {
120 let start = Instant::now();
121 self.is_storage_empty_count += 1;
122 let result = self.cursor.is_storage_empty();
123 self.total_duration += start.elapsed();
124 result
125 }
126
127 fn set_hashed_address(&mut self, hashed_address: B256) {
128 self.cursor.set_hashed_address(hashed_address)
129 }
130}
131
132impl<C> Drop for InstrumentedHashedCursor<C> {
133 fn drop(&mut self) {
134 self.metrics.next_histogram.record(self.next_count as f64);
135 self.metrics.seek_histogram.record(self.seek_count as f64);
136 self.metrics.is_storage_empty_histogram.record(self.is_storage_empty_count as f64);
137 self.metrics.overall_duration_seconds.record(self.total_duration.as_secs_f64());
138 }
139}
140
141#[derive(Clone, Debug)]
146pub struct InstrumentedHashedCursorFactory<F> {
147 factory: F,
148 account_metrics: HashedCursorMetrics,
149 storage_metrics: HashedCursorMetrics,
150}
151
152impl<F> InstrumentedHashedCursorFactory<F> {
153 pub const fn new(
155 factory: F,
156 account_metrics: HashedCursorMetrics,
157 storage_metrics: HashedCursorMetrics,
158 ) -> Self {
159 Self { factory, account_metrics, storage_metrics }
160 }
161}
162
163impl<F: HashedCursorFactory> HashedCursorFactory for InstrumentedHashedCursorFactory<F> {
164 type AccountCursor<'a>
165 = InstrumentedHashedCursor<F::AccountCursor<'a>>
166 where
167 Self: 'a;
168 type StorageCursor<'a>
169 = InstrumentedHashedCursor<F::StorageCursor<'a>>
170 where
171 Self: 'a;
172
173 fn hashed_account_cursor(&self) -> Result<Self::AccountCursor<'_>, DatabaseError> {
174 Ok(self.account_metrics.instrument(self.factory.hashed_account_cursor()?))
175 }
176
177 fn hashed_storage_cursor(
178 &self,
179 hashed_address: B256,
180 ) -> Result<Self::StorageCursor<'_>, DatabaseError> {
181 Ok(self.storage_metrics.instrument(self.factory.hashed_storage_cursor(hashed_address)?))
182 }
183}