Skip to content

Commit a9f3f41

Browse files
arkparMTDK1
authored andcommitted
State cache and other performance optimizations (paritytech#1345)
* State caching * Better code caching * Execution optimizaton * More optimizations * Updated wasmi * Caching test * Style * Style * Reverted some minor changes * Style and typos * Style and typos * Removed panics on missing memory
1 parent d811174 commit a9f3f41

File tree

26 files changed

+796
-266
lines changed

26 files changed

+796
-266
lines changed

Cargo.lock

Lines changed: 16 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

core/client/db/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ parking_lot = "0.7.1"
88
log = "0.4"
99
kvdb = { git = "https://github.com/paritytech/parity-common", rev="616b40150ded71f57f650067fcbc5c99d7c343e6" }
1010
kvdb-rocksdb = { git = "https://github.com/paritytech/parity-common", rev="616b40150ded71f57f650067fcbc5c99d7c343e6" }
11+
lru-cache = "0.1"
1112
hash-db = { git = "https://github.com/paritytech/trie" }
1213
substrate-primitives = { path = "../../primitives" }
1314
sr-primitives = { path = "../../sr-primitives" }

core/client/db/src/lib.rs

Lines changed: 63 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ extern crate kvdb_rocksdb;
2929
extern crate kvdb;
3030
extern crate hash_db;
3131
extern crate parking_lot;
32+
extern crate lru_cache;
3233
extern crate substrate_state_machine as state_machine;
3334
extern crate substrate_primitives as primitives;
3435
extern crate sr_primitives as runtime_primitives;
@@ -52,6 +53,7 @@ extern crate kvdb_memorydb;
5253
pub mod light;
5354

5455
mod cache;
56+
mod storage_cache;
5557
mod utils;
5658

5759
use std::sync::Arc;
@@ -75,10 +77,12 @@ use state_machine::{CodeExecutor, DBValue, ExecutionStrategy};
7577
use utils::{Meta, db_err, meta_keys, open_database, read_db, block_id_to_lookup_key, read_meta};
7678
use client::LeafSet;
7779
use state_db::StateDb;
80+
use storage_cache::{CachingState, SharedCache, new_shared_cache};
7881
pub use state_db::PruningMode;
7982

8083
const CANONICALIZATION_DELAY: u64 = 256;
8184
const MIN_BLOCKS_TO_KEEP_CHANGES_TRIES_FOR: u64 = 32768;
85+
const STATE_CACHE_SIZE_BYTES: usize = 16 * 1024 * 1024;
8286

8387
/// DB-backed patricia trie state, transaction type is an overlay of changes to commit.
8488
pub type DbState = state_machine::TrieBackend<Arc<state_machine::Storage<Blake2Hasher>>, Blake2Hasher>;
@@ -270,8 +274,9 @@ impl<Block: BlockT> client::blockchain::Backend<Block> for BlockchainDb<Block> {
270274

271275
/// Database transaction
272276
pub struct BlockImportOperation<Block: BlockT, H: Hasher> {
273-
old_state: DbState,
274-
updates: MemoryDB<H>,
277+
old_state: CachingState<Blake2Hasher, DbState, Block>,
278+
db_updates: MemoryDB<H>,
279+
storage_updates: Vec<(Vec<u8>, Option<Vec<u8>>)>,
275280
changes_trie_updates: MemoryDB<H>,
276281
pending_block: Option<PendingBlock<Block>>,
277282
aux_ops: Vec<(Vec<u8>, Option<Vec<u8>>)>,
@@ -292,7 +297,7 @@ impl<Block> client::backend::BlockImportOperation<Block, Blake2Hasher>
292297
for BlockImportOperation<Block, Blake2Hasher>
293298
where Block: BlockT<Hash=H256>,
294299
{
295-
type State = DbState;
300+
type State = CachingState<Blake2Hasher, DbState, Block>;
296301

297302
fn state(&self) -> Result<Option<&Self::State>, client::error::Error> {
298303
Ok(Some(&self.old_state))
@@ -319,8 +324,8 @@ where Block: BlockT<Hash=H256>,
319324
// currently authorities are not cached on full nodes
320325
}
321326

322-
fn update_storage(&mut self, update: MemoryDB<Blake2Hasher>) -> Result<(), client::error::Error> {
323-
self.updates = update;
327+
fn update_db_storage(&mut self, update: MemoryDB<Blake2Hasher>) -> Result<(), client::error::Error> {
328+
self.db_updates = update;
324329
Ok(())
325330
}
326331

@@ -349,7 +354,7 @@ where Block: BlockT<Hash=H256>,
349354
let (root, update) = self.old_state.storage_root(top.into_iter().map(|(k, v)| (k, Some(v))));
350355
transaction.consolidate(update);
351356

352-
self.updates = transaction;
357+
self.db_updates = transaction;
353358
Ok(root)
354359
}
355360

@@ -364,6 +369,11 @@ where Block: BlockT<Hash=H256>,
364369
self.aux_ops = ops.into_iter().collect();
365370
Ok(())
366371
}
372+
373+
fn update_storage(&mut self, update: Vec<(Vec<u8>, Option<Vec<u8>>)>) -> Result<(), client::error::Error> {
374+
self.storage_updates = update;
375+
Ok(())
376+
}
367377
}
368378

369379
struct StorageDb<Block: BlockT> {
@@ -503,6 +513,7 @@ pub struct Backend<Block: BlockT> {
503513
changes_tries_storage: DbChangesTrieStorage<Block>,
504514
blockchain: BlockchainDb<Block>,
505515
canonicalization_delay: u64,
516+
shared_cache: SharedCache<Block, Blake2Hasher>,
506517
}
507518

508519
impl<Block: BlockT> Backend<Block> {
@@ -550,6 +561,7 @@ impl<Block: BlockT> Backend<Block> {
550561
changes_tries_storage,
551562
blockchain,
552563
canonicalization_delay,
564+
shared_cache: new_shared_cache(STATE_CACHE_SIZE_BYTES),
553565
})
554566
}
555567

@@ -669,15 +681,16 @@ impl<Block> client::backend::AuxStore for Backend<Block> where Block: BlockT<Has
669681
impl<Block> client::backend::Backend<Block, Blake2Hasher> for Backend<Block> where Block: BlockT<Hash=H256> {
670682
type BlockImportOperation = BlockImportOperation<Block, Blake2Hasher>;
671683
type Blockchain = BlockchainDb<Block>;
672-
type State = DbState;
684+
type State = CachingState<Blake2Hasher, DbState, Block>;
673685
type ChangesTrieStorage = DbChangesTrieStorage<Block>;
674686

675687
fn begin_operation(&self, block: BlockId<Block>) -> Result<Self::BlockImportOperation, client::error::Error> {
676688
let state = self.state_at(block)?;
677689
Ok(BlockImportOperation {
678690
pending_block: None,
679691
old_state: state,
680-
updates: MemoryDB::default(),
692+
db_updates: MemoryDB::default(),
693+
storage_updates: Default::default(),
681694
changes_trie_updates: MemoryDB::default(),
682695
aux_ops: Vec::new(),
683696
})
@@ -697,6 +710,9 @@ impl<Block> client::backend::Backend<Block, Blake2Hasher> for Backend<Block> whe
697710
// blocks are keyed by number + hash.
698711
let lookup_key = ::utils::number_and_hash_to_lookup_key(number, hash);
699712

713+
let mut enacted = Vec::default();
714+
let mut retracted = Vec::default();
715+
700716
if pending_block.leaf_state.is_best() {
701717
let meta = self.blockchain.meta.read();
702718

@@ -710,28 +726,30 @@ impl<Block> client::backend::Backend<Block, Blake2Hasher> for Backend<Block> whe
710726

711727
// uncanonicalize: check safety violations and ensure the numbers no longer
712728
// point to these block hashes in the key mapping.
713-
for retracted in tree_route.retracted() {
714-
if retracted.hash == meta.finalized_hash {
729+
for r in tree_route.retracted() {
730+
retracted.push(r.hash.clone());
731+
if r.hash == meta.finalized_hash {
715732
warn!("Potential safety failure: reverting finalized block {:?}",
716-
(&retracted.number, &retracted.hash));
733+
(&r.number, &r.hash));
717734

718735
return Err(::client::error::ErrorKind::NotInFinalizedChain.into());
719736
}
720737

721738
::utils::remove_number_to_key_mapping(
722739
&mut transaction,
723740
columns::KEY_LOOKUP,
724-
retracted.number
741+
r.number
725742
);
726743
}
727744

728745
// canonicalize: set the number lookup to map to this block's hash.
729-
for enacted in tree_route.enacted() {
746+
for e in tree_route.enacted() {
747+
enacted.push(e.hash.clone());
730748
::utils::insert_number_to_key_mapping(
731749
&mut transaction,
732750
columns::KEY_LOOKUP,
733-
enacted.number,
734-
enacted.hash
751+
e.number,
752+
e.hash
735753
);
736754
}
737755
}
@@ -766,7 +784,7 @@ impl<Block> client::backend::Backend<Block, Blake2Hasher> for Backend<Block> whe
766784
}
767785

768786
let mut changeset: state_db::ChangeSet<H256> = state_db::ChangeSet::default();
769-
for (key, (val, rc)) in operation.updates.drain() {
787+
for (key, (val, rc)) in operation.db_updates.drain() {
770788
if rc > 0 {
771789
changeset.inserted.push((key, val.to_vec()));
772790
} else if rc < 0 {
@@ -792,8 +810,8 @@ impl<Block> client::backend::Backend<Block, Blake2Hasher> for Backend<Block> whe
792810
self.force_delayed_canonicalize(&mut transaction, hash, *pending_block.header.number())?
793811
}
794812

795-
debug!(target: "db", "DB Commit {:?} ({}), best = {}", hash, number,
796-
pending_block.leaf_state.is_best());
813+
let is_best = pending_block.leaf_state.is_best();
814+
debug!(target: "db", "DB Commit {:?} ({}), best = {}", hash, number, is_best);
797815

798816
{
799817
let mut leaves = self.blockchain.leaves.write();
@@ -817,6 +835,16 @@ impl<Block> client::backend::Backend<Block, Blake2Hasher> for Backend<Block> whe
817835
pending_block.leaf_state.is_best(),
818836
finalized,
819837
);
838+
839+
// sync canonical state cache
840+
operation.old_state.sync_cache(
841+
&enacted,
842+
&retracted,
843+
operation.storage_updates,
844+
Some(hash),
845+
Some(number),
846+
|| is_best
847+
);
820848
}
821849
Ok(())
822850
}
@@ -898,20 +926,30 @@ impl<Block> client::backend::Backend<Block, Blake2Hasher> for Backend<Block> whe
898926
BlockId::Hash(h) if h == Default::default() => {
899927
let genesis_storage = DbGenesisStorage::new();
900928
let root = genesis_storage.0.clone();
901-
return Ok(DbState::new(Arc::new(genesis_storage), root));
929+
let state = DbState::new(Arc::new(genesis_storage), root);
930+
return Ok(CachingState::new(state, self.shared_cache.clone(), None));
902931
},
903932
_ => {}
904933
}
905934

906935
match self.blockchain.header(block) {
907936
Ok(Some(ref hdr)) if !self.storage.state_db.is_pruned(hdr.number().as_()) => {
908937
let root = H256::from_slice(hdr.state_root().as_ref());
909-
Ok(DbState::new(self.storage.clone(), root))
938+
let state = DbState::new(self.storage.clone(), root);
939+
Ok(CachingState::new(state, self.shared_cache.clone(), Some(hdr.hash())))
910940
},
911941
Err(e) => Err(e),
912942
_ => Err(client::error::ErrorKind::UnknownBlock(format!("{:?}", block)).into()),
913943
}
914944
}
945+
946+
fn destroy_state(&self, mut state: Self::State) -> Result<(), client::error::Error> {
947+
if let Some(hash) = state.parent_hash.clone() {
948+
let is_best = || self.blockchain.meta.read().best_hash == hash;
949+
state.sync_cache(&[], &[], vec![], None, None, is_best);
950+
}
951+
Ok(())
952+
}
915953
}
916954

917955
impl<Block> client::backend::LocalBackend<Block, Blake2Hasher> for Backend<Block>
@@ -1092,7 +1130,7 @@ mod tests {
10921130
];
10931131

10941132
let (root, overlay) = op.old_state.storage_root(storage.iter().cloned());
1095-
op.update_storage(overlay).unwrap();
1133+
op.update_db_storage(overlay).unwrap();
10961134
header.state_root = root.into();
10971135

10981136
op.set_block_data(
@@ -1138,7 +1176,7 @@ mod tests {
11381176

11391177
op.reset_storage(storage.iter().cloned().collect(), Default::default()).unwrap();
11401178

1141-
key = op.updates.insert(b"hello");
1179+
key = op.db_updates.insert(b"hello");
11421180
op.set_block_data(
11431181
header,
11441182
Some(vec![]),
@@ -1171,8 +1209,8 @@ mod tests {
11711209
).0.into();
11721210
let hash = header.hash();
11731211

1174-
op.updates.insert(b"hello");
1175-
op.updates.remove(&key);
1212+
op.db_updates.insert(b"hello");
1213+
op.db_updates.remove(&key);
11761214
op.set_block_data(
11771215
header,
11781216
Some(vec![]),
@@ -1204,7 +1242,7 @@ mod tests {
12041242
.map(|(x, y)| (x, Some(y)))
12051243
).0.into();
12061244

1207-
op.updates.remove(&key);
1245+
op.db_updates.remove(&key);
12081246
op.set_block_data(
12091247
header,
12101248
Some(vec![]),

0 commit comments

Comments
 (0)