perf(trie): box subtries in parallel sparse trie (#16938)

This commit is contained in:
Alexey Shekhirin
2025-06-19 12:23:32 +01:00
committed by GitHub
parent 2ebb519287
commit 55dd16ac20

View File

@@ -1,6 +1,7 @@
use crate::{blinded::BlindedProvider, SparseNode, SparseTrieUpdates, TrieMasks};
use alloc::vec::Vec;
use alloc::{boxed::Box, vec::Vec};
use alloy_primitives::{map::HashMap, B256};
use alloy_trie::TrieMask;
use reth_execution_errors::SparseTrieResult;
use reth_trie_common::{
prefix_set::{PrefixSet, PrefixSetMut},
@@ -20,7 +21,7 @@ pub struct ParallelSparseTrie {
/// This contains the trie nodes for the upper part of the trie.
upper_subtrie: SparseSubtrie,
/// An array containing the subtries at the second level of the trie.
subtries: [Option<SparseSubtrie>; 256],
lower_subtries: Box<[Option<SparseSubtrie>; 256]>,
/// Optional tracking of trie updates for later use.
updates: Option<SparseTrieUpdates>,
}
@@ -29,7 +30,7 @@ impl Default for ParallelSparseTrie {
fn default() -> Self {
Self {
upper_subtrie: SparseSubtrie::default(),
subtries: [const { None }; 256],
lower_subtries: Box::new([const { None }; 256]),
updates: None,
}
}
@@ -171,7 +172,7 @@ impl ParallelSparseTrie {
let mut prefix_set_iter = prefix_set_clone.into_iter();
let mut subtries = Vec::new();
for subtrie in &mut self.subtries {
for subtrie in self.lower_subtries.iter_mut() {
if let Some(subtrie) = subtrie.take_if(|subtrie| prefix_set.contains(&subtrie.path)) {
let prefix_set = if prefix_set.all() {
PrefixSetMut::all()
@@ -208,6 +209,10 @@ pub struct SparseSubtrie {
path: Nibbles,
/// The map from paths to sparse trie nodes within this subtrie.
nodes: HashMap<Nibbles, SparseNode>,
/// When a branch is set, the corresponding child subtree is stored in the database.
branch_node_tree_masks: HashMap<Nibbles, TrieMask>,
/// When a bit is set, the corresponding child is stored as a hash in the database.
branch_node_hash_masks: HashMap<Nibbles, TrieMask>,
/// Map from leaf key paths to their values.
/// All values are stored here instead of directly in leaf nodes.
values: HashMap<Nibbles, Vec<u8>>,
@@ -295,9 +300,9 @@ mod tests {
let subtrie_3_index = path_subtrie_index_unchecked(&subtrie_3.path);
// Add subtries at specific positions
trie.subtries[subtrie_1_index] = Some(subtrie_1.clone());
trie.subtries[subtrie_2_index] = Some(subtrie_2.clone());
trie.subtries[subtrie_3_index] = Some(subtrie_3);
trie.lower_subtries[subtrie_1_index] = Some(subtrie_1.clone());
trie.lower_subtries[subtrie_2_index] = Some(subtrie_2.clone());
trie.lower_subtries[subtrie_3_index] = Some(subtrie_3);
// Create a prefix set with the keys that match only the second subtrie
let mut prefix_set = PrefixSetMut::from([
@@ -328,10 +333,10 @@ mod tests {
]
)]
);
assert!(trie.subtries[subtrie_2_index].is_none());
assert!(trie.lower_subtries[subtrie_2_index].is_none());
// First subtrie should remain unchanged
assert_eq!(trie.subtries[subtrie_1_index], Some(subtrie_1));
assert_eq!(trie.lower_subtries[subtrie_1_index], Some(subtrie_1));
}
#[test]
@@ -346,9 +351,9 @@ mod tests {
let subtrie_3_index = path_subtrie_index_unchecked(&subtrie_3.path);
// Add subtries at specific positions
trie.subtries[subtrie_1_index] = Some(subtrie_1.clone());
trie.subtries[subtrie_2_index] = Some(subtrie_2.clone());
trie.subtries[subtrie_3_index] = Some(subtrie_3.clone());
trie.lower_subtries[subtrie_1_index] = Some(subtrie_1.clone());
trie.lower_subtries[subtrie_2_index] = Some(subtrie_2.clone());
trie.lower_subtries[subtrie_3_index] = Some(subtrie_3.clone());
// Create a prefix set that matches any key
let mut prefix_set = PrefixSetMut::all().freeze();
@@ -362,7 +367,7 @@ mod tests {
.collect::<Vec<_>>(),
vec![(subtrie_1, true), (subtrie_2, true), (subtrie_3, true)]
);
assert!(trie.subtries.iter().all(Option::is_none));
assert!(trie.lower_subtries.iter().all(Option::is_none));
}
#[test]