Skip to content
Snippets Groups Projects
Commit 769f1981 authored by Arkadiy Paronyan's avatar Arkadiy Paronyan Committed by GitHub
Browse files

Add small header cache (#7516)

* Remove header query

* Header cache

* Fix potential race issue

* Simplify status query
parent f590b06f
Branches
No related merge requests found
......@@ -49,6 +49,9 @@ use std::sync::Arc;
use std::path::{Path, PathBuf};
use std::io;
use std::collections::{HashMap, HashSet};
use parking_lot::{Mutex, RwLock};
use linked_hash_map::LinkedHashMap;
use log::{trace, debug, warn};
use sc_client_api::{
UsageInfo, MemoryInfo, IoInfo, MemorySize,
......@@ -63,7 +66,6 @@ use codec::{Decode, Encode};
use hash_db::Prefix;
use sp_trie::{MemoryDB, PrefixedMemoryDB, prefixed_key};
use sp_database::Transaction;
use parking_lot::RwLock;
use sp_core::ChangesTrieConfiguration;
use sp_core::offchain::storage::{OffchainOverlayedChange, OffchainOverlayedChanges};
use sp_core::storage::{well_known_keys, ChildInfo};
......@@ -83,7 +85,6 @@ use sc_state_db::StateDb;
use sp_blockchain::{CachedHeaderMetadata, HeaderMetadata, HeaderMetadataCache};
use crate::storage_cache::{CachingState, SyncingCachingState, SharedCache, new_shared_cache};
use crate::stats::StateUsageStats;
use log::{trace, debug, warn};
// Re-export the Database trait so that one can pass an implementation of it.
pub use sp_database::Database;
......@@ -93,6 +94,7 @@ pub use sc_state_db::PruningMode;
pub use bench::BenchmarkingState;
const MIN_BLOCKS_TO_KEEP_CHANGES_TRIES_FOR: u32 = 32768;
const CACHE_HEADERS: usize = 8;
/// Default value for storage cache child ratio.
const DEFAULT_CHILD_RATIO: (usize, usize) = (1, 10);
......@@ -352,12 +354,24 @@ impl<'a> sc_state_db::MetaDb for StateMetaDb<'a> {
}
}
fn cache_header<Hash: std::cmp::Eq + std::hash::Hash, Header>(
cache: &mut LinkedHashMap<Hash, Option<Header>>,
hash: Hash,
header: Option<Header>,
) {
cache.insert(hash, header);
while cache.len() > CACHE_HEADERS {
cache.pop_front();
}
}
/// Block database
pub struct BlockchainDb<Block: BlockT> {
db: Arc<dyn Database<DbHash>>,
meta: Arc<RwLock<Meta<NumberFor<Block>, Block::Hash>>>,
leaves: RwLock<LeafSet<Block::Hash, NumberFor<Block>>>,
header_metadata_cache: Arc<HeaderMetadataCache<Block>>,
header_cache: Mutex<LinkedHashMap<Block::Hash, Option<Block::Header>>>,
}
impl<Block: BlockT> BlockchainDb<Block> {
......@@ -369,6 +383,7 @@ impl<Block: BlockT> BlockchainDb<Block> {
leaves: RwLock::new(leaves),
meta: Arc::new(RwLock::new(meta)),
header_metadata_cache: Arc::new(HeaderMetadataCache::default()),
header_cache: Default::default(),
})
}
......@@ -407,7 +422,20 @@ impl<Block: BlockT> BlockchainDb<Block> {
impl<Block: BlockT> sc_client_api::blockchain::HeaderBackend<Block> for BlockchainDb<Block> {
fn header(&self, id: BlockId<Block>) -> ClientResult<Option<Block::Header>> {
utils::read_header(&*self.db, columns::KEY_LOOKUP, columns::HEADER, id)
match &id {
BlockId::Hash(h) => {
let mut cache = self.header_cache.lock();
if let Some(result) = cache.get_refresh(h) {
return Ok(result.clone());
}
let header = utils::read_header(&*self.db, columns::KEY_LOOKUP, columns::HEADER, id)?;
cache_header(&mut cache, h.clone(), header.clone());
Ok(header)
}
BlockId::Number(_) => {
utils::read_header(&*self.db, columns::KEY_LOOKUP, columns::HEADER, id)
}
}
}
fn info(&self) -> sc_client_api::blockchain::Info<Block> {
......@@ -424,12 +452,7 @@ impl<Block: BlockT> sc_client_api::blockchain::HeaderBackend<Block> for Blockcha
fn status(&self, id: BlockId<Block>) -> ClientResult<sc_client_api::blockchain::BlockStatus> {
let exists = match id {
BlockId::Hash(_) => read_db(
&*self.db,
columns::KEY_LOOKUP,
columns::HEADER,
id
)?.is_some(),
BlockId::Hash(_) => self.header(id)?.is_some(),
BlockId::Number(n) => n <= self.meta.read().best_number,
};
match exists {
......@@ -1117,12 +1140,6 @@ impl<Block: BlockT> Backend<Block> {
hash,
)?;
let header_metadata = CachedHeaderMetadata::from(&pending_block.header);
self.blockchain.insert_header_metadata(
header_metadata.hash,
header_metadata,
);
transaction.set_from_vec(columns::HEADER, &lookup_key, pending_block.header.encode());
if let Some(body) = &pending_block.body {
transaction.set_from_vec(columns::BODY, &lookup_key, body.encode());
......@@ -1271,7 +1288,7 @@ impl<Block: BlockT> Backend<Block> {
meta_updates.push((hash, number, pending_block.leaf_state.is_best(), finalized));
Some((number, hash, enacted, retracted, displaced_leaf, is_best, cache))
Some((pending_block.header, number, hash, enacted, retracted, displaced_leaf, is_best, cache))
} else {
None
};
......@@ -1297,7 +1314,11 @@ impl<Block: BlockT> Backend<Block> {
self.storage.db.commit(transaction)?;
// Apply all in-memory state shanges.
// Code beyond this point can't fail.
if let Some((
header,
number,
hash,
enacted,
......@@ -1306,6 +1327,12 @@ impl<Block: BlockT> Backend<Block> {
is_best,
mut cache,
)) = imported {
let header_metadata = CachedHeaderMetadata::from(&header);
self.blockchain.insert_header_metadata(
header_metadata.hash,
header_metadata,
);
cache_header(&mut self.blockchain.header_cache.lock(), hash, Some(header));
cache.sync_cache(
&enacted,
&retracted,
......
......@@ -1159,12 +1159,12 @@ impl<B, E, Block, RA> Client<B, E, Block, RA> where
/// Prepare in-memory header that is used in execution environment.
fn prepare_environment_block(&self, parent: &BlockId<Block>) -> sp_blockchain::Result<Block::Header> {
let parent_header = self.backend.blockchain().expect_header(*parent)?;
let parent_hash = self.backend.blockchain().expect_block_hash_from_id(parent)?;
Ok(<<Block as BlockT>::Header as HeaderT>::new(
self.backend.blockchain().expect_block_number_from_id(parent)? + One::one(),
Default::default(),
Default::default(),
parent_header.hash(),
parent_hash,
Default::default(),
))
}
......
......@@ -53,7 +53,7 @@ pub trait HeaderBackend<Block: BlockT>: Send + Sync {
/// Convert an arbitrary block ID into a block hash.
fn block_number_from_id(&self, id: &BlockId<Block>) -> Result<Option<NumberFor<Block>>> {
match *id {
BlockId::Hash(_) => Ok(self.header(*id)?.map(|h| h.number().clone())),
BlockId::Hash(h) => self.number(h),
BlockId::Number(n) => Ok(Some(n)),
}
}
......
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment