Skip to content
This repository was archived by the owner on Nov 15, 2023. It is now read-only.

Commit 00cc5f1

Browse files
bkchrchemekoutearkpar
authored
Introduce trie level cache and remove state cache (#11407)
* trie state cache * Also cache missing access on read. * fix comp * bis * fix * use has_lru * remove local storage cache on size 0. * No cache. * local cache only * trie cache and local cache * storage cache (with local) * trie cache no local cache * Add state access benchmark * Remove warnings etc * Add trie cache benchmark * No extra "clone" required * Change benchmark to use multiple blocks * Use patches * Integrate shitty implementation * More stuff * Revert "Merge branch 'master' into trie_state_cache" This reverts commit 2c1886d, reversing changes made to 540b4fd. * Improve benchmark * Adapt to latest changes * Adapt to changes in trie * Add a test that uses iterator * Start fixing it * Remove obsolete file * Make it compile * Start rewriting the trie node cache * More work on the cache * More docs and code etc * Make data cache an optional * Tests * Remove debug stuff * Recorder * Some docs and a simple test for the recorder * Compile fixes * Make it compile * More fixes * More fixes * Fix fix fix * Make sure cache and recorder work together for basic stuff * Test that data caching and recording works * Test `TrieDBMut` with caching * Try something * Fixes, fixes, fixes * Forward the recorder * Make it compile * Use recorder in more places * Switch to new `with_optional_recorder` fn * Refactor and cleanups * Move `ProvingBackend` tests * Simplify * Move over all functionality to the essence * Fix compilation * Implement estimate encoded size for StorageProof * Start using the `cache` everywhere * Use the cache everywhere * Fix compilation * Fix tests * Adds `TrieBackendBuilder` and enhances the tests * Ensure that recorder drain checks that values are found as expected * Switch over to `TrieBackendBuilder` * Start fixing the problem with child tries and recording * Fix recording of child tries * Make it compile * Overwrite `storage_hash` in `TrieBackend` * Add `storage_cache` to the benchmarks * Fix `no_std` build * Speed up cache lookup * Extend the state access benchmark to also hash a runtime * Fix build * Fix compilation * Rewrite value cache * Add lru cache * Ensure that the cache lru works * Value cache should not be optional * Add support for keeping the shared node cache in its bounds * Make the cache configurable * Check that the cache respects the bounds * Adds a new test * Fixes * Docs and some renamings * More docs * Start using the new recorder * Fix more code * Take `self` argument * Remove warnings * Fix benchmark * Fix accounting * Rip off the state cache * Start fixing fallout after removing the state cache * Make it compile after trie changes * Fix test * Add some logging * Some docs * Some fixups and clean ups * Fix benchmark * Remove unneeded file * Use git for patching * Make CI happy * Update primitives/trie/Cargo.toml Co-authored-by: Koute <koute@users.noreply.github.com> * Update primitives/state-machine/src/trie_backend.rs Co-authored-by: cheme <emericchevalier.pro@gmail.com> * Introduce new `AsTrieBackend` trait * Make the LocalTrieCache not clonable * Make it work in no_std and add docs * Remove duplicate dependency * Switch to ahash for better performance * Speedup value cache merge * Output errors on underflow * Ensure the internal LRU map doesn't grow too much * Use const fn to calculate the value cache element size * Remove cache configuration * Fix * Clear the cache in between for more testing * Try to come up with a failing test case * Make the test fail * Fix the child trie recording * Make everything compile after the changes to trie * Adapt to latest trie-db changes * Fix on stable * Update primitives/trie/src/cache.rs Co-authored-by: cheme <emericchevalier.pro@gmail.com> * Fix wrong merge * Docs * Fix warnings * Cargo.lock * Bump pin-project * Fix warnings * Switch to released crate version * More fixes * Make clippy and rustdocs happy * More clippy * Print error when using deprecated `--state-cache-size` * 🤦 * Fixes * Fix storage_hash linkings * Update client/rpc/src/dev/mod.rs Co-authored-by: Arkadiy Paronyan <arkady.paronyan@gmail.com> * Review feedback * encode bound * Rework the shared value cache Instead of using a `u64` to represent the key we now use an `Arc<[u8]>`. This arc is also stored in some extra `HashSet`. We store the key are in an extra `HashSet` to de-duplicate the keys accross different storage roots. When the latest key usage is dropped in the lru, we also remove the key from the `HashSet`. * Improve of the cache by merging the old and new solution * FMT * Please stop coming back all the time :crying: * Update primitives/trie/src/cache/shared_cache.rs Co-authored-by: Arkadiy Paronyan <arkady.paronyan@gmail.com> * Fixes * Make clippy happy * Ensure we don't deadlock * Only use one lock to simplify the code * Do not depend on `Hasher` * Fix tests * FMT * Clippy 🤦 Co-authored-by: cheme <emericchevalier.pro@gmail.com> Co-authored-by: Koute <koute@users.noreply.github.com> Co-authored-by: Arkadiy Paronyan <arkady.paronyan@gmail.com>
1 parent 22b678f commit 00cc5f1

File tree

55 files changed

+3979
-1346
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

55 files changed

+3979
-1346
lines changed

Cargo.lock

+22-10
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

bin/node/bench/src/generator.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ use std::{collections::HashMap, sync::Arc};
2020

2121
use kvdb::KeyValueDB;
2222
use node_primitives::Hash;
23-
use sp_trie::{trie_types::TrieDBMutV1, TrieMut};
23+
use sp_trie::{trie_types::TrieDBMutBuilderV1, TrieMut};
2424

2525
use crate::simple_trie::SimpleTrie;
2626

@@ -43,7 +43,8 @@ pub fn generate_trie(
4343
);
4444
let mut trie = SimpleTrie { db, overlay: &mut overlay };
4545
{
46-
let mut trie_db = TrieDBMutV1::<crate::simple_trie::Hasher>::new(&mut trie, &mut root);
46+
let mut trie_db =
47+
TrieDBMutBuilderV1::<crate::simple_trie::Hasher>::new(&mut trie, &mut root).build();
4748
for (key, value) in key_values {
4849
trie_db.insert(&key, &value).expect("trie insertion failed");
4950
}

bin/node/bench/src/trie.rs

+3-4
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ use kvdb::KeyValueDB;
2323
use lazy_static::lazy_static;
2424
use rand::Rng;
2525
use sp_state_machine::Backend as _;
26-
use sp_trie::{trie_types::TrieDBMutV1, TrieMut as _};
26+
use sp_trie::{trie_types::TrieDBMutBuilderV1, TrieMut as _};
2727
use std::{borrow::Cow, collections::HashMap, sync::Arc};
2828

2929
use node_primitives::Hash;
@@ -180,7 +180,7 @@ impl core::Benchmark for TrieReadBenchmark {
180180
let storage: Arc<dyn sp_state_machine::Storage<sp_core::Blake2Hasher>> =
181181
Arc::new(Storage(db.open(self.database_type)));
182182

183-
let trie_backend = sp_state_machine::TrieBackend::new(storage, self.root);
183+
let trie_backend = sp_state_machine::TrieBackendBuilder::new(storage, self.root).build();
184184
for (warmup_key, warmup_value) in self.warmup_keys.iter() {
185185
let value = trie_backend
186186
.storage(&warmup_key[..])
@@ -286,8 +286,7 @@ impl core::Benchmark for TrieWriteBenchmark {
286286

287287
let mut overlay = HashMap::new();
288288
let mut trie = SimpleTrie { db: kvdb.clone(), overlay: &mut overlay };
289-
let mut trie_db_mut = TrieDBMutV1::from_existing(&mut trie, &mut new_root)
290-
.expect("Failed to create TrieDBMut");
289+
let mut trie_db_mut = TrieDBMutBuilderV1::from_existing(&mut trie, &mut new_root).build();
291290

292291
for (warmup_key, warmup_value) in self.warmup_keys.iter() {
293292
let value = trie_db_mut

bin/node/cli/benches/block_production.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -72,8 +72,7 @@ fn new_node(tokio_handle: Handle) -> node_cli::service::NewFullBase {
7272
keystore: KeystoreConfig::InMemory,
7373
keystore_remote: Default::default(),
7474
database: DatabaseSource::RocksDb { path: root.join("db"), cache_size: 128 },
75-
state_cache_size: 67108864,
76-
state_cache_child_ratio: None,
75+
trie_cache_maximum_size: Some(64 * 1024 * 1024),
7776
state_pruning: Some(PruningMode::ArchiveAll),
7877
blocks_pruning: BlocksPruning::All,
7978
chain_spec: spec,

bin/node/cli/benches/transaction_pool.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -66,8 +66,7 @@ fn new_node(tokio_handle: Handle) -> node_cli::service::NewFullBase {
6666
keystore: KeystoreConfig::InMemory,
6767
keystore_remote: Default::default(),
6868
database: DatabaseSource::RocksDb { path: root.join("db"), cache_size: 128 },
69-
state_cache_size: 67108864,
70-
state_cache_child_ratio: None,
69+
trie_cache_maximum_size: Some(64 * 1024 * 1024),
7170
state_pruning: Some(PruningMode::ArchiveAll),
7271
blocks_pruning: BlocksPruning::All,
7372
chain_spec: spec,

bin/node/testing/src/bench.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -388,8 +388,7 @@ impl BenchDb {
388388
keyring: &BenchKeyring,
389389
) -> (Client, std::sync::Arc<Backend>, TaskExecutor) {
390390
let db_config = sc_client_db::DatabaseSettings {
391-
state_cache_size: 16 * 1024 * 1024,
392-
state_cache_child_ratio: Some((0, 100)),
391+
trie_cache_maximum_size: Some(16 * 1024 * 1024),
393392
state_pruning: Some(PruningMode::ArchiveAll),
394393
source: database_type.into_settings(dir.into()),
395394
blocks_pruning: sc_client_db::BlocksPruning::All,

client/api/src/backend.rs

+8-2
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,8 @@ use sp_runtime::{
3232
Justification, Justifications, StateVersion, Storage,
3333
};
3434
use sp_state_machine::{
35-
ChildStorageCollection, IndexOperation, OffchainChangesCollection, StorageCollection,
35+
backend::AsTrieBackend, ChildStorageCollection, IndexOperation, OffchainChangesCollection,
36+
StorageCollection,
3637
};
3738
use sp_storage::{ChildInfo, StorageData, StorageKey};
3839
use std::collections::{HashMap, HashSet};
@@ -448,7 +449,12 @@ pub trait Backend<Block: BlockT>: AuxStore + Send + Sync {
448449
/// Associated blockchain backend type.
449450
type Blockchain: BlockchainBackend<Block>;
450451
/// Associated state backend type.
451-
type State: StateBackend<HashFor<Block>> + Send;
452+
type State: StateBackend<HashFor<Block>>
453+
+ Send
454+
+ AsTrieBackend<
455+
HashFor<Block>,
456+
TrieBackendStorage = <Self::State as StateBackend<HashFor<Block>>>::TrieBackendStorage,
457+
>;
452458
/// Offchain workers local storage.
453459
type OffchainStorage: OffchainStorage;
454460

client/basic-authorship/src/basic_authorship.rs

+15-6
Original file line numberDiff line numberDiff line change
@@ -855,10 +855,18 @@ mod tests {
855855
.expect("header get error")
856856
.expect("there should be header");
857857

858-
let extrinsics_num = 4;
859-
let extrinsics = (0..extrinsics_num)
860-
.map(|v| Extrinsic::IncludeData(vec![v as u8; 10]))
861-
.collect::<Vec<_>>();
858+
let extrinsics_num = 5;
859+
let extrinsics = std::iter::once(
860+
Transfer {
861+
from: AccountKeyring::Alice.into(),
862+
to: AccountKeyring::Bob.into(),
863+
amount: 100,
864+
nonce: 0,
865+
}
866+
.into_signed_tx(),
867+
)
868+
.chain((0..extrinsics_num - 1).map(|v| Extrinsic::IncludeData(vec![v as u8; 10])))
869+
.collect::<Vec<_>>();
862870

863871
let block_limit = genesis_header.encoded_size() +
864872
extrinsics
@@ -922,8 +930,9 @@ mod tests {
922930
.unwrap();
923931

924932
// The block limit didn't changed, but we now include the proof in the estimation of the
925-
// block size and thus, one less transaction should fit into the limit.
926-
assert_eq!(block.extrinsics().len(), extrinsics_num - 2);
933+
// block size and thus, only the `Transfer` will fit into the block. It reads more data
934+
// than we have reserved in the block limit.
935+
assert_eq!(block.extrinsics().len(), 1);
927936
}
928937

929938
#[test]

client/cli/src/commands/chain_info_cmd.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -73,8 +73,7 @@ impl ChainInfoCmd {
7373
B: BlockT,
7474
{
7575
let db_config = sc_client_db::DatabaseSettings {
76-
state_cache_size: config.state_cache_size,
77-
state_cache_child_ratio: config.state_cache_child_ratio.map(|v| (v, 100)),
76+
trie_cache_maximum_size: config.trie_cache_maximum_size,
7877
state_pruning: config.state_pruning.clone(),
7978
source: config.database.clone(),
8079
blocks_pruning: config.blocks_pruning,

client/cli/src/config.rs

+5-12
Original file line numberDiff line numberDiff line change
@@ -230,18 +230,12 @@ pub trait CliConfiguration<DCV: DefaultConfigurationValues = ()>: Sized {
230230
})
231231
}
232232

233-
/// Get the state cache size.
233+
/// Get the trie cache maximum size.
234234
///
235235
/// By default this is retrieved from `ImportParams` if it is available. Otherwise its `0`.
236-
fn state_cache_size(&self) -> Result<usize> {
237-
Ok(self.import_params().map(|x| x.state_cache_size()).unwrap_or_default())
238-
}
239-
240-
/// Get the state cache child ratio (if any).
241-
///
242-
/// By default this is `None`.
243-
fn state_cache_child_ratio(&self) -> Result<Option<usize>> {
244-
Ok(Default::default())
236+
/// If `None` is returned the trie cache is disabled.
237+
fn trie_cache_maximum_size(&self) -> Result<Option<usize>> {
238+
Ok(self.import_params().map(|x| x.trie_cache_maximum_size()).unwrap_or_default())
245239
}
246240

247241
/// Get the state pruning mode.
@@ -533,8 +527,7 @@ pub trait CliConfiguration<DCV: DefaultConfigurationValues = ()>: Sized {
533527
keystore_remote,
534528
keystore,
535529
database: self.database_config(&config_dir, database_cache_size, database)?,
536-
state_cache_size: self.state_cache_size()?,
537-
state_cache_child_ratio: self.state_cache_child_ratio()?,
530+
trie_cache_maximum_size: self.trie_cache_maximum_size()?,
538531
state_pruning: self.state_pruning()?,
539532
blocks_pruning: self.blocks_pruning()?,
540533
wasm_method: self.wasm_method()?,

client/cli/src/params/import_params.rs

+20-4
Original file line numberDiff line numberDiff line change
@@ -95,14 +95,30 @@ pub struct ImportParams {
9595
pub execution_strategies: ExecutionStrategiesParams,
9696

9797
/// Specify the state cache size.
98+
///
99+
/// Providing `0` will disable the cache.
98100
#[clap(long, value_name = "Bytes", default_value = "67108864")]
99-
pub state_cache_size: usize,
101+
pub trie_cache_size: usize,
102+
103+
/// DEPRECATED
104+
///
105+
/// Switch to `--trie-cache-size`.
106+
#[clap(long)]
107+
state_cache_size: Option<usize>,
100108
}
101109

102110
impl ImportParams {
103-
/// Specify the state cache size.
104-
pub fn state_cache_size(&self) -> usize {
105-
self.state_cache_size
111+
/// Specify the trie cache maximum size.
112+
pub fn trie_cache_maximum_size(&self) -> Option<usize> {
113+
if self.state_cache_size.is_some() {
114+
eprintln!("`--state-cache-size` was deprecated. Please switch to `--trie-cache-size`.");
115+
}
116+
117+
if self.trie_cache_size == 0 {
118+
None
119+
} else {
120+
Some(self.trie_cache_size)
121+
}
106122
}
107123

108124
/// Get the WASM execution method from the parameters

client/db/Cargo.toml

+11-1
Original file line numberDiff line numberDiff line change
@@ -35,9 +35,12 @@ sp-state-machine = { version = "0.12.0", path = "../../primitives/state-machine"
3535
sp-trie = { version = "6.0.0", path = "../../primitives/trie" }
3636

3737
[dev-dependencies]
38+
criterion = "0.3.3"
3839
kvdb-rocksdb = "0.15.1"
40+
rand = "0.8.4"
41+
tempfile = "3.1.0"
3942
quickcheck = { version = "1.0.3", default-features = false }
40-
tempfile = "3"
43+
kitchensink-runtime = { path = "../../bin/node/runtime" }
4144
sp-tracing = { version = "5.0.0", path = "../../primitives/tracing" }
4245
substrate-test-runtime-client = { version = "2.0.0", path = "../../test-utils/runtime/client" }
4346

@@ -46,3 +49,10 @@ default = []
4649
test-helpers = []
4750
runtime-benchmarks = []
4851
rocksdb = ["kvdb-rocksdb"]
52+
53+
[[bench]]
54+
name = "state_access"
55+
harness = false
56+
57+
[lib]
58+
bench = false

0 commit comments

Comments
 (0)