diff --git a/client/db/src/cache/mod.rs b/client/db/src/cache/mod.rs index 8d3e1f358b322..f2d357ca9ece8 100644 --- a/client/db/src/cache/mod.rs +++ b/client/db/src/cache/mod.rs @@ -20,7 +20,7 @@ use std::{sync::Arc, collections::{HashMap, hash_map::Entry}}; use parking_lot::RwLock; use sc_client_api::blockchain::{well_known_cache_keys::{self, Id as CacheKeyId}, Cache as BlockchainCache}; -use sp_blockchain::Result as ClientResult; +use sp_blockchain::{Result as ClientResult, HeaderMetadataCache}; use sp_database::{Database, Transaction}; use codec::{Encode, Decode}; use sp_runtime::generic::BlockId; @@ -78,6 +78,7 @@ impl CacheItemT for T where T: Clone + Decode + Encode + PartialEq {} /// Database-backed blockchain data cache. pub struct DbCache { cache_at: HashMap, self::list_storage::DbStorage>>, + header_metadata_cache: Arc>, db: Arc>, key_lookup_column: u32, header_column: u32, @@ -90,6 +91,7 @@ impl DbCache { /// Create new cache. pub fn new( db: Arc>, + header_metadata_cache: Arc>, key_lookup_column: u32, header_column: u32, cache_column: u32, @@ -99,6 +101,7 @@ impl DbCache { Self { cache_at: HashMap::new(), db, + header_metadata_cache, key_lookup_column, header_column, cache_column, @@ -348,18 +351,24 @@ impl BlockchainCache for DbCacheSync { at: &BlockId, ) -> ClientResult, Block::Hash), Option<(NumberFor, Block::Hash)>, Vec)>> { let mut cache = self.0.write(); + let header_metadata_cache = cache.header_metadata_cache.clone(); let cache = cache.get_cache(*key)?; let storage = cache.storage(); let db = storage.db(); let columns = storage.columns(); let at = match *at { BlockId::Hash(hash) => { - let header = utils::require_header::( - &**db, - columns.key_lookup, - columns.header, - BlockId::Hash(hash.clone()))?; - ComplexBlockId::new(hash, *header.number()) + match header_metadata_cache.header_metadata(hash) { + Some(metadata) => ComplexBlockId::new(hash, metadata.number), + None => { + let header = utils::require_header::( + &**db, + columns.key_lookup, + columns.header, + BlockId::Hash(hash.clone()))?; + ComplexBlockId::new(hash, *header.number()) + } + } }, BlockId::Number(number) => { let hash = utils::require_header::( diff --git a/client/db/src/changes_tries_storage.rs b/client/db/src/changes_tries_storage.rs index 985251f403d62..958e6e39f48c8 100644 --- a/client/db/src/changes_tries_storage.rs +++ b/client/db/src/changes_tries_storage.rs @@ -24,7 +24,7 @@ use parking_lot::RwLock; use sp_blockchain::{Error as ClientError, Result as ClientResult}; use sp_trie::MemoryDB; use sc_client_api::backend::PrunableStateChangesTrieStorage; -use sp_blockchain::{well_known_cache_keys, Cache as BlockchainCache}; +use sp_blockchain::{well_known_cache_keys, Cache as BlockchainCache, HeaderMetadataCache}; use sp_core::{ChangesTrieConfiguration, ChangesTrieConfigurationRange, convert_hash}; use sp_core::storage::PrefixedStorageKey; use sp_database::Transaction; @@ -114,6 +114,7 @@ impl DbChangesTrieStorage { /// Create new changes trie storage. pub fn new( db: Arc>, + header_metadata_cache: Arc>, meta_column: u32, changes_tries_column: u32, key_lookup_column: u32, @@ -137,6 +138,7 @@ impl DbChangesTrieStorage { min_blocks_to_keep, cache: DbCacheSync(RwLock::new(DbCache::new( db.clone(), + header_metadata_cache, key_lookup_column, header_column, cache_column, diff --git a/client/db/src/lib.rs b/client/db/src/lib.rs index 5edfcb046f625..d1eb10ea31646 100644 --- a/client/db/src/lib.rs +++ b/client/db/src/lib.rs @@ -368,7 +368,7 @@ pub struct BlockchainDb { db: Arc>, meta: Arc, Block::Hash>>>, leaves: RwLock>>, - header_metadata_cache: HeaderMetadataCache, + header_metadata_cache: Arc>, } impl BlockchainDb { @@ -379,7 +379,7 @@ impl BlockchainDb { db, leaves: RwLock::new(leaves), meta: Arc::new(RwLock::new(meta)), - header_metadata_cache: HeaderMetadataCache::default(), + header_metadata_cache: Arc::new(HeaderMetadataCache::default()), }) } @@ -505,7 +505,7 @@ impl HeaderMetadata for BlockchainDb { type Error = sp_blockchain::Error; fn header_metadata(&self, hash: Block::Hash) -> Result, Self::Error> { - self.header_metadata_cache.header_metadata(hash).or_else(|_| { + self.header_metadata_cache.header_metadata(hash).map_or_else(|| { self.header(BlockId::hash(hash))?.map(|header| { let header_metadata = CachedHeaderMetadata::from(&header); self.header_metadata_cache.insert_header_metadata( @@ -514,7 +514,7 @@ impl HeaderMetadata for BlockchainDb { ); header_metadata }).ok_or(ClientError::UnknownBlock(format!("header not found in db: {}", hash))) - }) + }, Ok) } fn insert_header_metadata(&self, hash: Block::Hash, metadata: CachedHeaderMetadata) { @@ -831,6 +831,7 @@ impl Backend { let offchain_storage = offchain::LocalStorage::new(db.clone()); let changes_tries_storage = DbChangesTrieStorage::new( db, + blockchain.header_metadata_cache.clone(), columns::META, columns::CHANGES_TRIE, columns::KEY_LOOKUP, diff --git a/client/db/src/light.rs b/client/db/src/light.rs index edc7f8fc552dd..849b439424d30 100644 --- a/client/db/src/light.rs +++ b/client/db/src/light.rs @@ -62,7 +62,7 @@ pub struct LightStorage { db: Arc>, meta: RwLock, Block::Hash>>, cache: Arc>, - header_metadata_cache: HeaderMetadataCache, + header_metadata_cache: Arc>, #[cfg(not(target_os = "unknown"))] io_stats: FrozenForDuration, @@ -84,8 +84,10 @@ impl LightStorage { fn from_kvdb(db: Arc>) -> ClientResult { let meta = read_meta::(&*db, columns::HEADER)?; + let header_metadata_cache = Arc::new(HeaderMetadataCache::default()); let cache = DbCache::new( db.clone(), + header_metadata_cache.clone(), columns::KEY_LOOKUP, columns::HEADER, columns::CACHE, @@ -97,7 +99,7 @@ impl LightStorage { db, meta: RwLock::new(meta), cache: Arc::new(DbCacheSync(RwLock::new(cache))), - header_metadata_cache: HeaderMetadataCache::default(), + header_metadata_cache, #[cfg(not(target_os = "unknown"))] io_stats: FrozenForDuration::new(std::time::Duration::from_secs(1)), }) @@ -188,7 +190,7 @@ impl HeaderMetadata for LightStorage { type Error = ClientError; fn header_metadata(&self, hash: Block::Hash) -> Result, Self::Error> { - self.header_metadata_cache.header_metadata(hash).or_else(|_| { + self.header_metadata_cache.header_metadata(hash).map_or_else(|| { self.header(BlockId::hash(hash))?.map(|header| { let header_metadata = CachedHeaderMetadata::from(&header); self.header_metadata_cache.insert_header_metadata( @@ -197,7 +199,7 @@ impl HeaderMetadata for LightStorage { ); header_metadata }).ok_or(ClientError::UnknownBlock(format!("header not found in db: {}", hash))) - }) + }, Ok) } fn insert_header_metadata(&self, hash: Block::Hash, metadata: CachedHeaderMetadata) { diff --git a/primitives/blockchain/src/header_metadata.rs b/primitives/blockchain/src/header_metadata.rs index bdc2b09eea4b4..b7df03187db37 100644 --- a/primitives/blockchain/src/header_metadata.rs +++ b/primitives/blockchain/src/header_metadata.rs @@ -239,19 +239,16 @@ impl Default for HeaderMetadataCache { } } -impl HeaderMetadata for HeaderMetadataCache { - type Error = String; - - fn header_metadata(&self, hash: Block::Hash) -> Result, Self::Error> { +impl HeaderMetadataCache { + pub fn header_metadata(&self, hash: Block::Hash) -> Option> { self.cache.write().get(&hash).cloned() - .ok_or("header metadata not found in cache".to_owned()) } - fn insert_header_metadata(&self, hash: Block::Hash, metadata: CachedHeaderMetadata) { + pub fn insert_header_metadata(&self, hash: Block::Hash, metadata: CachedHeaderMetadata) { self.cache.write().put(hash, metadata); } - fn remove_header_metadata(&self, hash: Block::Hash) { + pub fn remove_header_metadata(&self, hash: Block::Hash) { self.cache.write().pop(&hash); } }