reth_trie/trie_cursor/
metrics.rs1use super::{TrieCursor, TrieCursorFactory, TrieStorageCursor};
2use crate::{BranchNodeCompact, Nibbles, 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 TrieCursorMetrics {
14 overall_duration_seconds: Histogram,
16 next_histogram: Histogram,
18 seek_histogram: Histogram,
20 seek_exact_histogram: Histogram,
22}
23
24impl TrieCursorMetrics {
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.cursor.overall_duration_seconds",
32 "type" => trie_type_str
33 ),
34 next_histogram: metrics::histogram!(
35 "trie.cursor.operations",
36 "type" => trie_type_str,
37 "operation" => "next"
38 ),
39 seek_histogram: metrics::histogram!(
40 "trie.cursor.operations",
41 "type" => trie_type_str,
42 "operation" => "seek"
43 ),
44 seek_exact_histogram: metrics::histogram!(
45 "trie.cursor.operations",
46 "type" => trie_type_str,
47 "operation" => "seek_exact"
48 ),
49 }
50 }
51
52 pub fn instrument<C>(&self, cursor: C) -> InstrumentedTrieCursor<C> {
54 InstrumentedTrieCursor {
55 cursor,
56 metrics: self.clone(),
57 next_count: 0,
58 seek_count: 0,
59 seek_exact_count: 0,
60 total_duration: Duration::ZERO,
61 }
62 }
63}
64
65#[derive(Debug)]
74pub struct InstrumentedTrieCursor<C> {
75 cursor: C,
77 metrics: TrieCursorMetrics,
79 next_count: usize,
81 seek_count: usize,
83 seek_exact_count: usize,
85 total_duration: Duration,
87}
88
89impl<C: TrieCursor> TrieCursor for InstrumentedTrieCursor<C> {
90 fn seek_exact(
91 &mut self,
92 key: Nibbles,
93 ) -> Result<Option<(Nibbles, BranchNodeCompact)>, DatabaseError> {
94 let start = Instant::now();
95 self.seek_exact_count += 1;
96 let result = self.cursor.seek_exact(key);
97 self.total_duration += start.elapsed();
98 result
99 }
100
101 fn seek(
102 &mut self,
103 key: Nibbles,
104 ) -> Result<Option<(Nibbles, BranchNodeCompact)>, DatabaseError> {
105 let start = Instant::now();
106 self.seek_count += 1;
107 let result = self.cursor.seek(key);
108 self.total_duration += start.elapsed();
109 result
110 }
111
112 fn next(&mut self) -> Result<Option<(Nibbles, BranchNodeCompact)>, DatabaseError> {
113 let start = Instant::now();
114 self.next_count += 1;
115 let result = self.cursor.next();
116 self.total_duration += start.elapsed();
117 result
118 }
119
120 fn current(&mut self) -> Result<Option<Nibbles>, DatabaseError> {
121 self.cursor.current()
122 }
123
124 fn reset(&mut self) {
125 self.cursor.reset()
126 }
127}
128
129impl<C: TrieStorageCursor> TrieStorageCursor for InstrumentedTrieCursor<C> {
130 fn set_hashed_address(&mut self, hashed_address: B256) {
131 self.cursor.set_hashed_address(hashed_address)
132 }
133}
134
135impl<C> Drop for InstrumentedTrieCursor<C> {
136 fn drop(&mut self) {
137 self.metrics.next_histogram.record(self.next_count as f64);
138 self.metrics.seek_histogram.record(self.seek_count as f64);
139 self.metrics.seek_exact_histogram.record(self.seek_exact_count as f64);
140 self.metrics.overall_duration_seconds.record(self.total_duration.as_secs_f64());
141 }
142}
143
144#[derive(Clone, Debug)]
149pub struct InstrumentedTrieCursorFactory<F> {
150 factory: F,
151 account_metrics: TrieCursorMetrics,
152 storage_metrics: TrieCursorMetrics,
153}
154
155impl<F> InstrumentedTrieCursorFactory<F> {
156 pub const fn new(
158 factory: F,
159 account_metrics: TrieCursorMetrics,
160 storage_metrics: TrieCursorMetrics,
161 ) -> Self {
162 Self { factory, account_metrics, storage_metrics }
163 }
164}
165
166impl<F: TrieCursorFactory> TrieCursorFactory for InstrumentedTrieCursorFactory<F> {
167 type AccountTrieCursor<'a>
168 = InstrumentedTrieCursor<F::AccountTrieCursor<'a>>
169 where
170 Self: 'a;
171 type StorageTrieCursor<'a>
172 = InstrumentedTrieCursor<F::StorageTrieCursor<'a>>
173 where
174 Self: 'a;
175
176 fn account_trie_cursor(&self) -> Result<Self::AccountTrieCursor<'_>, DatabaseError> {
177 Ok(self.account_metrics.instrument(self.factory.account_trie_cursor()?))
178 }
179
180 fn storage_trie_cursor(
181 &self,
182 hashed_address: B256,
183 ) -> Result<Self::StorageTrieCursor<'_>, DatabaseError> {
184 Ok(self.storage_metrics.instrument(self.factory.storage_trie_cursor(hashed_address)?))
185 }
186}