From eec6f3b9019f50e113d44dd24196f995ec5be4a1 Mon Sep 17 00:00:00 2001 From: Svyatoslav Nikolsky Date: Wed, 3 Apr 2019 13:35:12 +0300 Subject: [PATCH] Cache changes trie config in db storage (#2170) * cache changes trie config in db storage * Update core/client/db/src/lib.rs Co-Authored-By: svyatonik * Update core/client/db/src/lib.rs Co-Authored-By: svyatonik --- substrate/core/client/db/src/lib.rs | 57 ++++++++++++++++++----------- 1 file changed, 36 insertions(+), 21 deletions(-) diff --git a/substrate/core/client/db/src/lib.rs b/substrate/core/client/db/src/lib.rs index 7657bfd396..ac22bcbb01 100644 --- a/substrate/core/client/db/src/lib.rs +++ b/substrate/core/client/db/src/lib.rs @@ -42,7 +42,7 @@ use parity_codec::{Decode, Encode}; use hash_db::Hasher; use kvdb::{KeyValueDB, DBTransaction}; use trie::{MemoryDB, PrefixedMemoryDB, prefixed_key}; -use parking_lot::RwLock; +use parking_lot::{Mutex, RwLock}; use primitives::{H256, Blake2Hasher, ChangesTrieConfiguration, convert_hash}; use primitives::storage::well_known_keys; use runtime_primitives::{generic::BlockId, Justification, StorageOverlay, ChildrenStorageOverlay}; @@ -435,22 +435,15 @@ impl DbChangesTrieStorage { } /// Prune obsolete changes tries. - pub fn prune(&self, config: Option, tx: &mut DBTransaction, block_hash: Block::Hash, block_num: NumberFor) { + pub fn prune(&self, config: &ChangesTrieConfiguration, tx: &mut DBTransaction, block_hash: Block::Hash, block_num: NumberFor) { // never prune on archive nodes let min_blocks_to_keep = match self.min_blocks_to_keep { Some(min_blocks_to_keep) => min_blocks_to_keep, None => return, }; - // read configuration from the database. it is OK to do it here (without checking tx for - // modifications), since config can't change - let config = match config { - Some(config) => config, - None => return, - }; - state_machine::prune_changes_tries( - &config, + config, &*self, min_blocks_to_keep, &state_machine::ChangesTrieAnchorBlockId { @@ -535,6 +528,9 @@ impl state_machine::ChangesTrieStorage for DbChange pub struct Backend { storage: Arc>, changes_tries_storage: DbChangesTrieStorage, + /// None<*> means that the value hasn't been cached yet. Some(*) means that the value (either None or + /// Some(*)) has been cached and is valid. + changes_trie_config: Mutex>>, blockchain: BlockchainDb, canonicalization_delay: u64, shared_cache: SharedCache, @@ -583,6 +579,7 @@ impl> Backend { Ok(Backend { storage: Arc::new(storage_db), changes_tries_storage, + changes_trie_config: Mutex::new(None), blockchain, canonicalization_delay, shared_cache: new_shared_cache(STATE_CACHE_SIZE_BYTES), @@ -637,6 +634,26 @@ impl> Backend { inmem } + /// Read (from storage or cache) changes trie config. + /// + /// Currently changes tries configuration is set up once (at genesis) and could not + /// be changed. Thus, we'll actually read value once and then just use cached value. + fn changes_trie_config(&self, block: Block::Hash) -> Result, client::error::Error> { + let mut cached_changes_trie_config = self.changes_trie_config.lock(); + match cached_changes_trie_config.clone() { + Some(cached_changes_trie_config) => Ok(cached_changes_trie_config), + None => { + use client::backend::Backend; + let changes_trie_config = self + .state_at(BlockId::Hash(block))? + .storage(well_known_keys::CHANGES_TRIE_CONFIG)? + .and_then(|v| Decode::decode(&mut &*v)); + *cached_changes_trie_config = Some(changes_trie_config.clone()); + Ok(changes_trie_config) + }, + } + } + /// Handle setting head within a transaction. `route_to` should be the last /// block that existed in the database. `best_to` should be the best block /// to be set. @@ -972,12 +989,10 @@ impl> Backend { .map_err(|e: state_db::Error| client::error::Error::from(format!("State database error: {:?}", e)))?; apply_state_commit(transaction, commit); - // read config from genesis, since it is readonly atm - use client::backend::Backend; - let changes_trie_config: Option = self.state_at(BlockId::Hash(parent_hash))? - .storage(well_known_keys::CHANGES_TRIE_CONFIG)? - .and_then(|v| Decode::decode(&mut &*v)); - self.changes_tries_storage.prune(changes_trie_config, transaction, f_hash, f_num); + let changes_trie_config = self.changes_trie_config(parent_hash)?; + if let Some(changes_trie_config) = changes_trie_config { + self.changes_tries_storage.prune(&changes_trie_config, transaction, f_hash, f_num); + } } let new_displaced = self.blockchain.leaves.write().finalize_height(f_num); @@ -1682,7 +1697,7 @@ mod tests { // now simulate finalization of block#12, causing prune of tries at #1..#4 let mut tx = DBTransaction::new(); - backend.changes_tries_storage.prune(Some(config.clone()), &mut tx, Default::default(), 12); + backend.changes_tries_storage.prune(&config, &mut tx, Default::default(), 12); backend.storage.db.write(tx).unwrap(); assert!(backend.changes_tries_storage.get(&root1, &[]).unwrap().is_none()); assert!(backend.changes_tries_storage.get(&root2, &[]).unwrap().is_none()); @@ -1695,7 +1710,7 @@ mod tests { // now simulate finalization of block#16, causing prune of tries at #5..#8 let mut tx = DBTransaction::new(); - backend.changes_tries_storage.prune(Some(config.clone()), &mut tx, Default::default(), 16); + backend.changes_tries_storage.prune(&config, &mut tx, Default::default(), 16); backend.storage.db.write(tx).unwrap(); assert!(backend.changes_tries_storage.get(&root5, &[]).unwrap().is_none()); assert!(backend.changes_tries_storage.get(&root6, &[]).unwrap().is_none()); @@ -1706,7 +1721,7 @@ mod tests { // => no changes tries are pruned, because we never prune in archive mode backend.changes_tries_storage.min_blocks_to_keep = None; let mut tx = DBTransaction::new(); - backend.changes_tries_storage.prune(Some(config), &mut tx, Default::default(), 20); + backend.changes_tries_storage.prune(&config, &mut tx, Default::default(), 20); backend.storage.db.write(tx).unwrap(); assert!(backend.changes_tries_storage.get(&root9, &[]).unwrap().is_some()); assert!(backend.changes_tries_storage.get(&root10, &[]).unwrap().is_some()); @@ -1748,14 +1763,14 @@ mod tests { // now simulate finalization of block#5, causing prune of trie at #1 let mut tx = DBTransaction::new(); - backend.changes_tries_storage.prune(Some(config.clone()), &mut tx, block5, 5); + backend.changes_tries_storage.prune(&config, &mut tx, block5, 5); backend.storage.db.write(tx).unwrap(); assert!(backend.changes_tries_storage.get(&root1, &[]).unwrap().is_none()); assert!(backend.changes_tries_storage.get(&root2, &[]).unwrap().is_some()); // now simulate finalization of block#6, causing prune of tries at #2 let mut tx = DBTransaction::new(); - backend.changes_tries_storage.prune(Some(config.clone()), &mut tx, block6, 6); + backend.changes_tries_storage.prune(&config, &mut tx, block6, 6); backend.storage.db.write(tx).unwrap(); assert!(backend.changes_tries_storage.get(&root2, &[]).unwrap().is_none()); assert!(backend.changes_tries_storage.get(&root3, &[]).unwrap().is_some());