mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-11 22:21:07 +00:00
Add small header cache (#7516)
* Remove header query * Header cache * Fix potential race issue * Simplify status query
This commit is contained in:
@@ -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)),
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user