Skip to content

Commit 500405a

Browse files
authored
feat(trie): node iter metrics (#15438)
1 parent 4109b26 commit 500405a

File tree

11 files changed

+167
-43
lines changed

11 files changed

+167
-43
lines changed

Diff for: crates/trie/db/src/storage.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use reth_trie::{
99
};
1010

1111
#[cfg(feature = "metrics")]
12-
use reth_trie::metrics::{TrieRootMetrics, TrieType};
12+
use reth_trie::metrics::TrieRootMetrics;
1313

1414
/// Extends [`StorageRoot`] with operations specific for working with a database transaction.
1515
pub trait DatabaseStorageRoot<'a, TX> {
@@ -44,7 +44,7 @@ impl<'a, TX: DbTx> DatabaseStorageRoot<'a, TX>
4444
address,
4545
Default::default(),
4646
#[cfg(feature = "metrics")]
47-
TrieRootMetrics::new(TrieType::Storage),
47+
TrieRootMetrics::new(reth_trie::TrieType::Storage),
4848
)
4949
}
5050

@@ -55,7 +55,7 @@ impl<'a, TX: DbTx> DatabaseStorageRoot<'a, TX>
5555
hashed_address,
5656
Default::default(),
5757
#[cfg(feature = "metrics")]
58-
TrieRootMetrics::new(TrieType::Storage),
58+
TrieRootMetrics::new(reth_trie::TrieType::Storage),
5959
)
6060
}
6161

@@ -73,7 +73,7 @@ impl<'a, TX: DbTx> DatabaseStorageRoot<'a, TX>
7373
address,
7474
prefix_set,
7575
#[cfg(feature = "metrics")]
76-
TrieRootMetrics::new(TrieType::Storage),
76+
TrieRootMetrics::new(reth_trie::TrieType::Storage),
7777
)
7878
.root()
7979
}

Diff for: crates/trie/parallel/src/metrics.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use crate::stats::ParallelTrieStats;
22
use metrics::Histogram;
33
use reth_metrics::Metrics;
4-
use reth_trie::metrics::{TrieRootMetrics, TrieType};
4+
use reth_trie::{metrics::TrieRootMetrics, TrieType};
55

66
/// Parallel state root metrics.
77
#[derive(Debug)]

Diff for: crates/trie/parallel/src/proof.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ use reth_trie::{
2626
updates::TrieUpdatesSorted,
2727
walker::TrieWalker,
2828
HashBuilder, HashedPostStateSorted, MultiProof, MultiProofTargets, Nibbles, StorageMultiProof,
29-
TRIE_ACCOUNT_RLP_MAX_SIZE,
29+
TrieType, TRIE_ACCOUNT_RLP_MAX_SIZE,
3030
};
3131
use reth_trie_common::proof::ProofRetainer;
3232
use reth_trie_db::{DatabaseHashedCursorFactory, DatabaseTrieCursorFactory};
@@ -229,6 +229,7 @@ where
229229
let mut account_node_iter = TrieNodeIter::new(
230230
walker,
231231
hashed_cursor_factory.hashed_account_cursor().map_err(ProviderError::Database)?,
232+
TrieType::State,
232233
);
233234
while let Some(account_node) =
234235
account_node_iter.try_next().map_err(ProviderError::Database)?

Diff for: crates/trie/parallel/src/root.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ use reth_trie::{
1616
trie_cursor::{InMemoryTrieCursorFactory, TrieCursorFactory},
1717
updates::TrieUpdates,
1818
walker::TrieWalker,
19-
HashBuilder, Nibbles, StorageRoot, TrieInput, TRIE_ACCOUNT_RLP_MAX_SIZE,
19+
HashBuilder, Nibbles, StorageRoot, TrieInput, TrieType, TRIE_ACCOUNT_RLP_MAX_SIZE,
2020
};
2121
use reth_trie_db::{DatabaseHashedCursorFactory, DatabaseTrieCursorFactory};
2222
use std::{collections::HashMap, sync::Arc};
@@ -153,6 +153,7 @@ where
153153
let mut account_node_iter = TrieNodeIter::new(
154154
walker,
155155
hashed_cursor_factory.hashed_account_cursor().map_err(ProviderError::Database)?,
156+
TrieType::State,
156157
);
157158

158159
let mut hash_builder = HashBuilder::default().with_updates(retain_updates);

Diff for: crates/trie/sparse/benches/root.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ use reth_trie::{
1010
trie_cursor::{noop::NoopStorageTrieCursor, InMemoryStorageTrieCursor},
1111
updates::StorageTrieUpdates,
1212
walker::TrieWalker,
13-
HashedStorage,
13+
HashedStorage, TrieType,
1414
};
1515
use reth_trie_common::{HashBuilder, Nibbles};
1616
use reth_trie_sparse::SparseTrie;
@@ -143,6 +143,7 @@ fn calculate_root_from_leaves_repeated(c: &mut Criterion) {
143143
NoopHashedStorageCursor::default(),
144144
Some(&storage_sorted),
145145
),
146+
TrieType::Storage,
146147
);
147148

148149
let mut hb = HashBuilder::default().with_updates(true);

Diff for: crates/trie/sparse/src/trie.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -1591,7 +1591,7 @@ mod tests {
15911591
node_iter::{TrieElement, TrieNodeIter},
15921592
trie_cursor::{noop::NoopAccountTrieCursor, TrieCursor, TrieCursorFactory},
15931593
walker::TrieWalker,
1594-
BranchNode, ExtensionNode, HashedPostState, LeafNode,
1594+
BranchNode, ExtensionNode, HashedPostState, LeafNode, TrieType,
15951595
};
15961596
use reth_trie_common::{
15971597
proof::{ProofNodes, ProofRetainer},
@@ -1648,6 +1648,7 @@ mod tests {
16481648
NoopHashedAccountCursor::default(),
16491649
hashed_post_state.accounts(),
16501650
),
1651+
TrieType::State,
16511652
);
16521653

16531654
while let Some(node) = node_iter.try_next().unwrap() {

Diff for: crates/trie/trie/src/lib.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ pub mod witness;
3737

3838
/// The implementation of the Merkle Patricia Trie.
3939
mod trie;
40-
pub use trie::{StateRoot, StorageRoot};
40+
pub use trie::{StateRoot, StorageRoot, TrieType};
4141

4242
/// Utilities for state root checkpoint progress.
4343
mod progress;

Diff for: crates/trie/trie/src/metrics.rs

+57-20
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use crate::stats::TrieStats;
1+
use crate::{stats::TrieStats, trie::TrieType};
22
use metrics::{Counter, Histogram};
33
use reth_metrics::Metrics;
44

@@ -46,25 +46,7 @@ impl TrieRootMetrics {
4646
}
4747
}
4848

49-
/// Trie type for differentiating between various trie calculations.
50-
#[derive(Clone, Copy, Debug)]
51-
pub enum TrieType {
52-
/// State trie type.
53-
State,
54-
/// Storage trie type.
55-
Storage,
56-
}
57-
58-
impl TrieType {
59-
pub(crate) const fn as_str(&self) -> &'static str {
60-
match self {
61-
Self::State => "state",
62-
Self::Storage => "storage",
63-
}
64-
}
65-
}
66-
67-
/// Metrics for trie walker
49+
/// Metrics for [`crate::walker::TrieWalker`].
6850
#[derive(Clone, Metrics)]
6951
#[metrics(scope = "trie.walker")]
7052
pub struct WalkerMetrics {
@@ -83,3 +65,58 @@ impl WalkerMetrics {
8365
self.out_of_order_subnode.increment(amount);
8466
}
8567
}
68+
69+
/// Metrics for [`crate::node_iter::TrieNodeIter`].
70+
#[derive(Clone, Metrics)]
71+
#[metrics(scope = "trie.node_iter")]
72+
pub struct TrieNodeIterMetrics {
73+
/// The number of branch nodes returned by the iterator.
74+
branch_nodes_returned_total: Counter,
75+
/// The number of times same leaf node was seeked multiple times in a row by the iterator.
76+
leaf_nodes_same_seeked_total: Counter,
77+
/// The number of times the same leaf node as we just advanced to was seeked by the iterator.
78+
leaf_nodes_same_seeked_as_advanced_total: Counter,
79+
/// The number of leaf nodes seeked by the iterator.
80+
leaf_nodes_seeked_total: Counter,
81+
/// The number of leaf nodes advanced by the iterator.
82+
leaf_nodes_advanced_total: Counter,
83+
/// The number of leaf nodes returned by the iterator.
84+
leaf_nodes_returned_total: Counter,
85+
}
86+
87+
impl TrieNodeIterMetrics {
88+
/// Create new metrics for the given trie type.
89+
pub fn new(ty: TrieType) -> Self {
90+
Self::new_with_labels(&[("type", ty.as_str())])
91+
}
92+
93+
/// Increment `branch_nodes_returned_total`.
94+
pub fn inc_branch_nodes_returned(&self) {
95+
self.branch_nodes_returned_total.increment(1);
96+
}
97+
98+
/// Increment `leaf_nodes_same_seeked_total`.
99+
pub fn inc_leaf_nodes_same_seeked(&self) {
100+
self.leaf_nodes_same_seeked_total.increment(1);
101+
}
102+
103+
/// Increment `leaf_nodes_same_seeked_as_advanced_total`.
104+
pub fn inc_leaf_nodes_same_seeked_as_advanced(&self) {
105+
self.leaf_nodes_same_seeked_as_advanced_total.increment(1);
106+
}
107+
108+
/// Increment `leaf_nodes_seeked_total`.
109+
pub fn inc_leaf_nodes_seeked(&self) {
110+
self.leaf_nodes_seeked_total.increment(1);
111+
}
112+
113+
/// Increment `leaf_nodes_advanced_total`.
114+
pub fn inc_leaf_nodes_advanced(&self) {
115+
self.leaf_nodes_advanced_total.increment(1);
116+
}
117+
118+
/// Increment `leaf_nodes_returned_total`.
119+
pub fn inc_leaf_nodes_returned(&self) {
120+
self.leaf_nodes_returned_total.increment(1);
121+
}
122+
}

Diff for: crates/trie/trie/src/node_iter.rs

+69-8
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1-
use crate::{hashed_cursor::HashedCursor, trie_cursor::TrieCursor, walker::TrieWalker, Nibbles};
1+
use crate::{
2+
hashed_cursor::HashedCursor, trie::TrieType, trie_cursor::TrieCursor, walker::TrieWalker,
3+
Nibbles,
4+
};
25
use alloy_primitives::B256;
36
use reth_storage_errors::db::DatabaseError;
47
use tracing::trace;
@@ -45,17 +48,30 @@ pub struct TrieNodeIter<C, H: HashedCursor> {
4548
current_hashed_entry: Option<(B256, <H as HashedCursor>::Value)>,
4649
/// Flag indicating whether we should check the current walker key.
4750
should_check_walker_key: bool,
51+
52+
#[cfg(feature = "metrics")]
53+
metrics: crate::metrics::TrieNodeIterMetrics,
54+
#[cfg(feature = "metrics")]
55+
previously_seeked_key: Option<B256>,
56+
#[cfg(feature = "metrics")]
57+
previously_advanced_to_key: Option<B256>,
4858
}
4959

5060
impl<C, H: HashedCursor> TrieNodeIter<C, H> {
5161
/// Creates a new [`TrieNodeIter`].
52-
pub const fn new(walker: TrieWalker<C>, hashed_cursor: H) -> Self {
62+
pub fn new(walker: TrieWalker<C>, hashed_cursor: H, trie_type: TrieType) -> Self {
5363
Self {
5464
walker,
5565
hashed_cursor,
5666
previous_hashed_key: None,
5767
current_hashed_entry: None,
5868
should_check_walker_key: false,
69+
#[cfg(feature = "metrics")]
70+
metrics: crate::metrics::TrieNodeIterMetrics::new(trie_type),
71+
#[cfg(feature = "metrics")]
72+
previously_seeked_key: None,
73+
#[cfg(feature = "metrics")]
74+
previously_advanced_to_key: None,
5975
}
6076
}
6177

@@ -65,6 +81,41 @@ impl<C, H: HashedCursor> TrieNodeIter<C, H> {
6581
self.previous_hashed_key = Some(previous_hashed_key);
6682
self
6783
}
84+
85+
/// Seeks the hashed cursor to the given key.
86+
///
87+
/// If `metrics` feature is enabled, also updates the metrics.
88+
fn hashed_cursor_seek(&mut self, key: B256) -> Result<Option<(B256, H::Value)>, DatabaseError> {
89+
#[cfg(feature = "metrics")]
90+
{
91+
self.metrics.inc_leaf_nodes_seeked();
92+
93+
if Some(key) == self.previously_seeked_key {
94+
self.metrics.inc_leaf_nodes_same_seeked();
95+
}
96+
self.previously_seeked_key = Some(key);
97+
98+
if Some(key) == self.previously_advanced_to_key {
99+
self.metrics.inc_leaf_nodes_same_seeked_as_advanced();
100+
}
101+
}
102+
self.hashed_cursor.seek(key)
103+
}
104+
105+
/// Advances the hashed cursor to the next entry.
106+
///
107+
/// If `metrics` feature is enabled, also updates the metrics.
108+
fn hashed_cursor_next(&mut self) -> Result<Option<(B256, H::Value)>, DatabaseError> {
109+
let result = self.hashed_cursor.next();
110+
#[cfg(feature = "metrics")]
111+
{
112+
self.metrics.inc_leaf_nodes_advanced();
113+
114+
self.previously_advanced_to_key =
115+
result.as_ref().ok().and_then(|result| result.as_ref().map(|(k, _)| *k));
116+
}
117+
result
118+
}
68119
}
69120

70121
impl<C, H> TrieNodeIter<C, H>
@@ -97,6 +148,8 @@ where
97148
self.should_check_walker_key = true;
98149
// If it's possible to skip the current node in the walker, return a branch node
99150
if self.walker.can_skip_current_node {
151+
#[cfg(feature = "metrics")]
152+
self.metrics.inc_branch_nodes_returned();
100153
return Ok(Some(TrieElement::Branch(TrieBranchNode::new(
101154
key.clone(),
102155
self.walker.hash().unwrap(),
@@ -116,7 +169,10 @@ where
116169

117170
// Set the next hashed entry as a leaf node and return
118171
trace!(target: "trie::node_iter", ?hashed_key, "next hashed entry");
119-
self.current_hashed_entry = self.hashed_cursor.next()?;
172+
self.current_hashed_entry = self.hashed_cursor_next()?;
173+
174+
#[cfg(feature = "metrics")]
175+
self.metrics.inc_leaf_nodes_returned();
120176
return Ok(Some(TrieElement::Leaf(hashed_key, value)))
121177
}
122178

@@ -125,8 +181,8 @@ where
125181
Some(hashed_key) => {
126182
trace!(target: "trie::node_iter", ?hashed_key, "seeking to the previous hashed entry");
127183
// Seek to the previous hashed key and get the next hashed entry
128-
self.hashed_cursor.seek(hashed_key)?;
129-
self.current_hashed_entry = self.hashed_cursor.next()?;
184+
self.hashed_cursor_seek(hashed_key)?;
185+
self.current_hashed_entry = self.hashed_cursor_next()?;
130186
}
131187
None => {
132188
// Get the seek key and set the current hashed entry based on walker's next
@@ -176,7 +232,7 @@ where
176232
continue
177233
}
178234

179-
self.current_hashed_entry = self.hashed_cursor.seek(seek_key)?;
235+
self.current_hashed_entry = self.hashed_cursor_seek(seek_key)?;
180236
}
181237
}
182238
}
@@ -209,6 +265,7 @@ mod tests {
209265
HashedPostStateAccountCursor,
210266
},
211267
mock::{KeyVisit, KeyVisitType},
268+
trie::TrieType,
212269
trie_cursor::{
213270
mock::MockTrieCursorFactory, noop::NoopAccountTrieCursor, TrieCursorFactory,
214271
},
@@ -240,6 +297,7 @@ mod tests {
240297
NoopHashedAccountCursor::default(),
241298
hashed_post_state.accounts(),
242299
),
300+
TrieType::State,
243301
);
244302

245303
while let Some(node) = node_iter.try_next().unwrap() {
@@ -369,8 +427,11 @@ mod tests {
369427
B256Map::default(),
370428
);
371429

372-
let mut iter =
373-
TrieNodeIter::new(walker, hashed_cursor_factory.hashed_account_cursor().unwrap());
430+
let mut iter = TrieNodeIter::new(
431+
walker,
432+
hashed_cursor_factory.hashed_account_cursor().unwrap(),
433+
TrieType::State,
434+
);
374435

375436
// Walk the iterator until it's exhausted.
376437
while iter.try_next().unwrap().is_some() {}

Diff for: crates/trie/trie/src/proof/mod.rs

+5-2
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ use crate::{
22
hashed_cursor::{HashedCursorFactory, HashedStorageCursor},
33
node_iter::{TrieElement, TrieNodeIter},
44
prefix_set::{PrefixSetMut, TriePrefixSetsMut},
5+
trie::TrieType,
56
trie_cursor::TrieCursorFactory,
67
walker::TrieWalker,
78
HashBuilder, Nibbles, TRIE_ACCOUNT_RLP_MAX_SIZE,
@@ -124,7 +125,8 @@ where
124125
let mut storages: B256Map<_> =
125126
targets.keys().map(|key| (*key, StorageMultiProof::empty())).collect();
126127
let mut account_rlp = Vec::with_capacity(TRIE_ACCOUNT_RLP_MAX_SIZE);
127-
let mut account_node_iter = TrieNodeIter::new(walker, hashed_account_cursor);
128+
let mut account_node_iter =
129+
TrieNodeIter::new(walker, hashed_account_cursor, TrieType::State);
128130
while let Some(account_node) = account_node_iter.try_next()? {
129131
match account_node {
130132
TrieElement::Branch(node) => {
@@ -288,7 +290,8 @@ where
288290
let mut hash_builder = HashBuilder::default()
289291
.with_proof_retainer(retainer)
290292
.with_updates(self.collect_branch_node_masks);
291-
let mut storage_node_iter = TrieNodeIter::new(walker, hashed_storage_cursor);
293+
let mut storage_node_iter =
294+
TrieNodeIter::new(walker, hashed_storage_cursor, TrieType::Storage);
292295
while let Some(node) = storage_node_iter.try_next()? {
293296
match node {
294297
TrieElement::Branch(node) => {

0 commit comments

Comments
 (0)