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

Commit

Permalink
Changes tries build cache (#2933)
Browse files Browse the repository at this point in the history
* changes tries build cache

added CT build cache test

* fix lines width

* fixed some grumbles

* clear cache when: digests disabled, top-level or skewed digest is built

* cached_changed_keys -> with_cached_changed_keys
  • Loading branch information
svyatonik authored Sep 5, 2019
1 parent f6dc9f9 commit ac6a2a7
Show file tree
Hide file tree
Showing 16 changed files with 620 additions and 66 deletions.
36 changes: 30 additions & 6 deletions core/client/db/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ mod utils;
use std::sync::Arc;
use std::path::PathBuf;
use std::io;
use std::collections::HashMap;
use std::collections::{HashMap, HashSet};

use client::backend::NewBlockState;
use client::blockchain::HeaderBackend;
Expand All @@ -58,7 +58,7 @@ use sr_primitives::traits::{
};
use state_machine::backend::Backend as StateBackend;
use executor::RuntimeInfo;
use state_machine::{CodeExecutor, DBValue};
use state_machine::{CodeExecutor, DBValue, ChangesTrieTransaction, ChangesTrieCacheAction, ChangesTrieBuildCache};
use crate::utils::{Meta, db_err, meta_keys, read_db, block_id_to_lookup_key, read_meta};
use client::leaves::{LeafSet, FinalizationDisplaced};
use client::children;
Expand Down Expand Up @@ -405,6 +405,7 @@ pub struct BlockImportOperation<Block: BlockT, H: Hasher> {
storage_updates: StorageCollection,
child_storage_updates: ChildStorageCollection,
changes_trie_updates: MemoryDB<H>,
changes_trie_cache_update: Option<ChangesTrieCacheAction<H::Out, NumberFor<Block>>>,
pending_block: Option<PendingBlock<Block>>,
aux_ops: Vec<(Vec<u8>, Option<Vec<u8>>)>,
finalized_blocks: Vec<(BlockId<Block>, Option<Justification>)>,
Expand Down Expand Up @@ -487,8 +488,12 @@ where Block: BlockT<Hash=H256>,
Ok(root)
}

fn update_changes_trie(&mut self, update: MemoryDB<Blake2Hasher>) -> Result<(), client::error::Error> {
self.changes_trie_updates = update;
fn update_changes_trie(
&mut self,
update: ChangesTrieTransaction<Blake2Hasher, NumberFor<Block>>,
) -> Result<(), client::error::Error> {
self.changes_trie_updates = update.0;
self.changes_trie_cache_update = Some(update.1);
Ok(())
}

Expand Down Expand Up @@ -565,6 +570,7 @@ pub struct DbChangesTrieStorage<Block: BlockT> {
db: Arc<dyn KeyValueDB>,
meta: Arc<RwLock<Meta<NumberFor<Block>, Block::Hash>>>,
min_blocks_to_keep: Option<u32>,
cache: RwLock<ChangesTrieBuildCache<Block::Hash, NumberFor<Block>>>,
_phantom: ::std::marker::PhantomData<Block>,
}

Expand All @@ -576,6 +582,11 @@ impl<Block: BlockT<Hash=H256>> DbChangesTrieStorage<Block> {
}
}

/// Commit changes into changes trie build cache.
pub fn commit_cache(&self, cache_update: ChangesTrieCacheAction<Block::Hash, NumberFor<Block>>) {
self.cache.write().perform(cache_update);
}

/// Prune obsolete changes tries.
pub fn prune(
&self,
Expand Down Expand Up @@ -699,6 +710,14 @@ where
self
}

fn with_cached_changed_keys(
&self,
root: &H256,
functor: &mut dyn FnMut(&HashMap<Option<Vec<u8>>, HashSet<Vec<u8>>>),
) -> bool {
self.cache.read().with_changed_keys(root, functor)
}

fn get(&self, key: &H256, _prefix: Prefix) -> Result<Option<DBValue>, String> {
self.db.get(columns::CHANGES_TRIE, &key[..])
.map_err(|err| format!("{}", err))
Expand Down Expand Up @@ -783,6 +802,7 @@ impl<Block: BlockT<Hash=H256>> Backend<Block> {
db,
meta,
min_blocks_to_keep: if is_archive_pruning { None } else { Some(MIN_BLOCKS_TO_KEEP_CHANGES_TRIES_FOR) },
cache: RwLock::new(ChangesTrieBuildCache::new()),
_phantom: Default::default(),
};

Expand Down Expand Up @@ -1098,7 +1118,6 @@ impl<Block: BlockT<Hash=H256>> Backend<Block> {
self.changes_tries_storage.commit(&mut transaction, changes_trie_updates);
let cache = operation.old_state.release(); // release state reference so that it can be finalized


if finalized {
// TODO: ensure best chain contains this block.
self.ensure_sequential_finalization(header, Some(last_finalized_hash))?;
Expand Down Expand Up @@ -1155,6 +1174,10 @@ impl<Block: BlockT<Hash=H256>> Backend<Block> {

let write_result = self.storage.db.write(transaction).map_err(db_err);

if let Some(changes_trie_cache_update) = operation.changes_trie_cache_update {
self.changes_tries_storage.commit_cache(changes_trie_cache_update);
}

if let Some((number, hash, enacted, retracted, displaced_leaf, is_best, mut cache)) = imported {
if let Err(e) = write_result {
let mut leaves = self.blockchain.leaves.write();
Expand Down Expand Up @@ -1288,6 +1311,7 @@ impl<Block> client::backend::Backend<Block, Blake2Hasher> for Backend<Block> whe
storage_updates: Default::default(),
child_storage_updates: Default::default(),
changes_trie_updates: MemoryDB::default(),
changes_trie_cache_update: None,
aux_ops: Vec::new(),
finalized_blocks: Vec::new(),
set_head: None,
Expand Down Expand Up @@ -1515,7 +1539,7 @@ mod tests {
let mut op = backend.begin_operation().unwrap();
backend.begin_state_operation(&mut op, block_id).unwrap();
op.set_block_data(header, None, None, NewBlockState::Best).unwrap();
op.update_changes_trie(changes_trie_update).unwrap();
op.update_changes_trie((changes_trie_update, ChangesTrieCacheAction::Clear)).unwrap();
backend.commit_operation(op).unwrap();

header_hash
Expand Down
5 changes: 2 additions & 3 deletions core/client/src/backend.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,9 @@ use primitives::ChangesTrieConfiguration;
use sr_primitives::{generic::BlockId, Justification, StorageOverlay, ChildrenStorageOverlay};
use sr_primitives::traits::{Block as BlockT, NumberFor};
use state_machine::backend::Backend as StateBackend;
use state_machine::ChangesTrieStorage as StateChangesTrieStorage;
use state_machine::{ChangesTrieStorage as StateChangesTrieStorage, ChangesTrieTransaction};
use consensus::{well_known_cache_keys, BlockOrigin};
use hash_db::Hasher;
use trie::MemoryDB;
use parking_lot::Mutex;

/// In memory array of storage values.
Expand Down Expand Up @@ -116,7 +115,7 @@ pub trait BlockImportOperation<Block, H> where
child_update: ChildStorageCollection,
) -> error::Result<()>;
/// Inject changes trie data into the database.
fn update_changes_trie(&mut self, update: MemoryDB<H>) -> error::Result<()>;
fn update_changes_trie(&mut self, update: ChangesTrieTransaction<H, NumberFor<Block>>) -> error::Result<()>;
/// Insert auxiliary keys. Values are `None` if should be deleted.
fn insert_aux<I>(&mut self, ops: I) -> error::Result<()>
where I: IntoIterator<Item=(Vec<u8>, Option<Vec<u8>>)>;
Expand Down
15 changes: 11 additions & 4 deletions core/client/src/call_executor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,15 @@
use std::{sync::Arc, cmp::Ord, panic::UnwindSafe, result, cell::RefCell, rc::Rc};
use codec::{Encode, Decode};
use sr_primitives::{
generic::BlockId, traits::Block as BlockT,
generic::BlockId, traits::Block as BlockT, traits::NumberFor,
};
use state_machine::{
self, OverlayedChanges, Ext, CodeExecutor, ExecutionManager,
ExecutionStrategy, NeverOffchainExt, backend::Backend as _,
ChangesTrieTransaction,
};
use executor::{RuntimeVersion, RuntimeInfo, NativeVersion};
use hash_db::Hasher;
use trie::MemoryDB;
use primitives::{offchain, H256, Blake2Hasher, NativeOrEncoded, NeverNativeValue};

use crate::runtime_api::{ProofRecorder, InitializeBlock};
Expand Down Expand Up @@ -111,7 +111,14 @@ where
manager: ExecutionManager<F>,
native_call: Option<NC>,
side_effects_handler: Option<&mut O>,
) -> Result<(NativeOrEncoded<R>, (S::Transaction, H::Out), Option<MemoryDB<H>>), error::Error>;
) -> Result<
(
NativeOrEncoded<R>,
(S::Transaction, H::Out),
Option<ChangesTrieTransaction<Blake2Hasher, NumberFor<B>>>
),
error::Error,
>;

/// Execute a call to a contract on top of given state, gathering execution proof.
///
Expand Down Expand Up @@ -345,7 +352,7 @@ where
) -> error::Result<(
NativeOrEncoded<R>,
(S::Transaction, <Blake2Hasher as Hasher>::Out),
Option<MemoryDB<Blake2Hasher>>,
Option<ChangesTrieTransaction<Blake2Hasher, NumberFor<Block>>>,
)> {
state_machine::new(
state,
Expand Down
15 changes: 12 additions & 3 deletions core/client/src/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,8 @@ use sr_primitives::{
use state_machine::{
DBValue, Backend as StateBackend, CodeExecutor, ChangesTrieAnchorBlockId,
ExecutionStrategy, ExecutionManager, prove_read, prove_child_read,
ChangesTrieRootsStorage, ChangesTrieStorage, ChangesTrieConfigurationRange,
ChangesTrieRootsStorage, ChangesTrieStorage,
ChangesTrieTransaction, ChangesTrieConfigurationRange,
key_changes, key_changes_proof, OverlayedChanges, NeverOffchainExt,
};
use executor::{RuntimeVersion, RuntimeInfo};
Expand Down Expand Up @@ -86,7 +87,7 @@ type StorageUpdate<B, Block> = <
<B as backend::Backend<Block, Blake2Hasher>>::BlockImportOperation
as BlockImportOperation<Block, Blake2Hasher>
>::State as state_machine::Backend<Blake2Hasher>>::Transaction;
type ChangesUpdate = trie::MemoryDB<Blake2Hasher>;
type ChangesUpdate<Block> = ChangesTrieTransaction<Blake2Hasher, NumberFor<Block>>;

/// Execution strategies settings.
#[derive(Debug, Clone)]
Expand Down Expand Up @@ -635,6 +636,14 @@ impl<B, E, Block, RA> Client<B, E, Block, RA> where
self
}

fn with_cached_changed_keys(
&self,
root: &H256,
functor: &mut dyn FnMut(&HashMap<Option<Vec<u8>>, HashSet<Vec<u8>>>),
) -> bool {
self.storage.with_cached_changed_keys(root, functor)
}

fn get(&self, key: &H256, prefix: Prefix) -> Result<Option<DBValue>, String> {
self.storage.get(key, prefix)
}
Expand Down Expand Up @@ -1001,7 +1010,7 @@ impl<B, E, Block, RA> Client<B, E, Block, RA> where
body: Option<Vec<Block::Extrinsic>>,
) -> error::Result<(
Option<StorageUpdate<B, Block>>,
Option<Option<ChangesUpdate>>,
Option<Option<ChangesUpdate<Block>>>,
Option<(
Vec<(Vec<u8>, Option<Vec<u8>>)>,
Vec<(Vec<u8>, Vec<(Vec<u8>, Option<Vec<u8>>)>)>
Expand Down
16 changes: 12 additions & 4 deletions core/client/src/in_mem.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,15 @@

//! In memory client backend
use std::collections::HashMap;
use std::collections::{HashMap, HashSet};
use std::sync::Arc;
use parking_lot::{RwLock, Mutex};
use primitives::{ChangesTrieConfiguration, storage::well_known_keys};
use sr_primitives::generic::{BlockId, DigestItem};
use sr_primitives::traits::{Block as BlockT, Header as HeaderT, Zero, NumberFor};
use sr_primitives::{Justification, StorageOverlay, ChildrenStorageOverlay};
use state_machine::backend::{Backend as StateBackend, InMemory};
use state_machine::{self, InMemoryChangesTrieStorage, ChangesTrieAnchorBlockId};
use state_machine::{self, InMemoryChangesTrieStorage, ChangesTrieAnchorBlockId, ChangesTrieTransaction};
use hash_db::{Hasher, Prefix};
use trie::MemoryDB;
use consensus::well_known_cache_keys::Id as CacheKeyId;
Expand Down Expand Up @@ -484,8 +484,8 @@ where
Ok(())
}

fn update_changes_trie(&mut self, update: MemoryDB<H>) -> error::Result<()> {
self.changes_trie_update = Some(update);
fn update_changes_trie(&mut self, update: ChangesTrieTransaction<H, NumberFor<Block>>) -> error::Result<()> {
self.changes_trie_update = Some(update.0);
Ok(())
}

Expand Down Expand Up @@ -766,6 +766,14 @@ impl<Block, H> state_machine::ChangesTrieStorage<H, NumberFor<Block>> for Change
self
}

fn with_cached_changed_keys(
&self,
_root: &H::Out,
_functor: &mut dyn FnMut(&HashMap<Option<Vec<u8>>, HashSet<Vec<u8>>>),
) -> bool {
false
}

fn get(&self, key: &H::Out, prefix: Prefix) -> Result<Option<state_machine::DBValue>, String> {
self.0.get(key, prefix)
}
Expand Down
4 changes: 2 additions & 2 deletions core/client/src/light/backend.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ use std::sync::{Arc, Weak};
use parking_lot::{RwLock, Mutex};

use sr_primitives::{generic::BlockId, Justification, StorageOverlay, ChildrenStorageOverlay};
use state_machine::{Backend as StateBackend, TrieBackend, backend::InMemory as InMemoryState};
use state_machine::{Backend as StateBackend, TrieBackend, backend::InMemory as InMemoryState, ChangesTrieTransaction};
use sr_primitives::traits::{Block as BlockT, NumberFor, Zero, Header};
use crate::in_mem::{self, check_genesis_storage};
use crate::backend::{
Expand Down Expand Up @@ -284,7 +284,7 @@ where
Ok(())
}

fn update_changes_trie(&mut self, _update: MemoryDB<H>) -> ClientResult<()> {
fn update_changes_trie(&mut self, _update: ChangesTrieTransaction<H, NumberFor<Block>>) -> ClientResult<()> {
// we're not storing anything locally => ignore changes
Ok(())
}
Expand Down
9 changes: 4 additions & 5 deletions core/client/src/light/call_executor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,10 @@ use std::{
use codec::{Encode, Decode};
use primitives::{offchain, H256, Blake2Hasher, convert_hash, NativeOrEncoded};
use sr_primitives::generic::BlockId;
use sr_primitives::traits::{One, Block as BlockT, Header as HeaderT};
use sr_primitives::traits::{One, Block as BlockT, Header as HeaderT, NumberFor};
use state_machine::{
self, Backend as StateBackend, CodeExecutor, OverlayedChanges,
ExecutionStrategy, create_proof_check_backend,
ExecutionStrategy, ChangesTrieTransaction, create_proof_check_backend,
execution_proof_check_on_trie_backend, ExecutionManager, NeverOffchainExt
};
use hash_db::Hasher;
Expand All @@ -40,7 +40,6 @@ use crate::call_executor::CallExecutor;
use crate::error::{Error as ClientError, Result as ClientResult};
use crate::light::fetcher::{Fetcher, RemoteCallRequest};
use executor::{RuntimeVersion, NativeVersion};
use trie::MemoryDB;

/// Call executor that executes methods on remote node, querying execution proof
/// and checking proof by re-executing locally.
Expand Down Expand Up @@ -185,7 +184,7 @@ where
) -> ClientResult<(
NativeOrEncoded<R>,
(S::Transaction, <Blake2Hasher as Hasher>::Out),
Option<MemoryDB<Blake2Hasher>>,
Option<ChangesTrieTransaction<Blake2Hasher, NumberFor<Block>>>,
)> {
Err(ClientError::NotAvailableOnLightClient.into())
}
Expand Down Expand Up @@ -365,7 +364,7 @@ impl<Block, B, Remote, Local> CallExecutor<Block, Blake2Hasher> for
) -> ClientResult<(
NativeOrEncoded<R>,
(S::Transaction, <Blake2Hasher as Hasher>::Out),
Option<MemoryDB<Blake2Hasher>>,
Option<ChangesTrieTransaction<Blake2Hasher, NumberFor<Block>>>,
)> {
// there's no actual way/need to specify native/wasm execution strategy on light node
// => we can safely ignore passed values
Expand Down
2 changes: 1 addition & 1 deletion core/client/src/light/fetcher.rs
Original file line number Diff line number Diff line change
Expand Up @@ -460,7 +460,7 @@ struct RootsStorage<'a, Number: SimpleArithmetic, Hash: 'a> {
impl<'a, H, Number, Hash> ChangesTrieRootsStorage<H, Number> for RootsStorage<'a, Number, Hash>
where
H: Hasher,
Number: ::std::fmt::Display + Clone + SimpleArithmetic + Encode + Decode + Send + Sync + 'static,
Number: ::std::fmt::Display + ::std::hash::Hash + Clone + SimpleArithmetic + Encode + Decode + Send + Sync + 'static,
Hash: 'a + Send + Sync + Clone + AsRef<[u8]>,
{
fn build_anchor(
Expand Down
Loading

0 comments on commit ac6a2a7

Please sign in to comment.