Skip to content

Commit d4fe89a

Browse files
arkpardarkfriend77
authored andcommitted
Add small header cache (paritytech#7516)
* Remove header query * Header cache * Fix potential race issue * Simplify status query
1 parent 0999496 commit d4fe89a

File tree

3 files changed

+46
-19
lines changed

3 files changed

+46
-19
lines changed

client/db/src/lib.rs

Lines changed: 43 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,9 @@ use std::sync::Arc;
4949
use std::path::{Path, PathBuf};
5050
use std::io;
5151
use std::collections::{HashMap, HashSet};
52+
use parking_lot::{Mutex, RwLock};
53+
use linked_hash_map::LinkedHashMap;
54+
use log::{trace, debug, warn};
5255

5356
use sc_client_api::{
5457
UsageInfo, MemoryInfo, IoInfo, MemorySize,
@@ -63,7 +66,6 @@ use codec::{Decode, Encode};
6366
use hash_db::Prefix;
6467
use sp_trie::{MemoryDB, PrefixedMemoryDB, prefixed_key};
6568
use sp_database::Transaction;
66-
use parking_lot::RwLock;
6769
use sp_core::ChangesTrieConfiguration;
6870
use sp_core::offchain::storage::{OffchainOverlayedChange, OffchainOverlayedChanges};
6971
use sp_core::storage::{well_known_keys, ChildInfo};
@@ -83,7 +85,6 @@ use sc_state_db::StateDb;
8385
use sp_blockchain::{CachedHeaderMetadata, HeaderMetadata, HeaderMetadataCache};
8486
use crate::storage_cache::{CachingState, SyncingCachingState, SharedCache, new_shared_cache};
8587
use crate::stats::StateUsageStats;
86-
use log::{trace, debug, warn};
8788

8889
// Re-export the Database trait so that one can pass an implementation of it.
8990
pub use sp_database::Database;
@@ -93,6 +94,7 @@ pub use sc_state_db::PruningMode;
9394
pub use bench::BenchmarkingState;
9495

9596
const MIN_BLOCKS_TO_KEEP_CHANGES_TRIES_FOR: u32 = 32768;
97+
const CACHE_HEADERS: usize = 8;
9698

9799
/// Default value for storage cache child ratio.
98100
const DEFAULT_CHILD_RATIO: (usize, usize) = (1, 10);
@@ -352,12 +354,24 @@ impl<'a> sc_state_db::MetaDb for StateMetaDb<'a> {
352354
}
353355
}
354356

357+
fn cache_header<Hash: std::cmp::Eq + std::hash::Hash, Header>(
358+
cache: &mut LinkedHashMap<Hash, Option<Header>>,
359+
hash: Hash,
360+
header: Option<Header>,
361+
) {
362+
cache.insert(hash, header);
363+
while cache.len() > CACHE_HEADERS {
364+
cache.pop_front();
365+
}
366+
}
367+
355368
/// Block database
356369
pub struct BlockchainDb<Block: BlockT> {
357370
db: Arc<dyn Database<DbHash>>,
358371
meta: Arc<RwLock<Meta<NumberFor<Block>, Block::Hash>>>,
359372
leaves: RwLock<LeafSet<Block::Hash, NumberFor<Block>>>,
360373
header_metadata_cache: Arc<HeaderMetadataCache<Block>>,
374+
header_cache: Mutex<LinkedHashMap<Block::Hash, Option<Block::Header>>>,
361375
}
362376

363377
impl<Block: BlockT> BlockchainDb<Block> {
@@ -369,6 +383,7 @@ impl<Block: BlockT> BlockchainDb<Block> {
369383
leaves: RwLock::new(leaves),
370384
meta: Arc::new(RwLock::new(meta)),
371385
header_metadata_cache: Arc::new(HeaderMetadataCache::default()),
386+
header_cache: Default::default(),
372387
})
373388
}
374389

@@ -407,7 +422,20 @@ impl<Block: BlockT> BlockchainDb<Block> {
407422

408423
impl<Block: BlockT> sc_client_api::blockchain::HeaderBackend<Block> for BlockchainDb<Block> {
409424
fn header(&self, id: BlockId<Block>) -> ClientResult<Option<Block::Header>> {
410-
utils::read_header(&*self.db, columns::KEY_LOOKUP, columns::HEADER, id)
425+
match &id {
426+
BlockId::Hash(h) => {
427+
let mut cache = self.header_cache.lock();
428+
if let Some(result) = cache.get_refresh(h) {
429+
return Ok(result.clone());
430+
}
431+
let header = utils::read_header(&*self.db, columns::KEY_LOOKUP, columns::HEADER, id)?;
432+
cache_header(&mut cache, h.clone(), header.clone());
433+
Ok(header)
434+
}
435+
BlockId::Number(_) => {
436+
utils::read_header(&*self.db, columns::KEY_LOOKUP, columns::HEADER, id)
437+
}
438+
}
411439
}
412440

413441
fn info(&self) -> sc_client_api::blockchain::Info<Block> {
@@ -424,12 +452,7 @@ impl<Block: BlockT> sc_client_api::blockchain::HeaderBackend<Block> for Blockcha
424452

425453
fn status(&self, id: BlockId<Block>) -> ClientResult<sc_client_api::blockchain::BlockStatus> {
426454
let exists = match id {
427-
BlockId::Hash(_) => read_db(
428-
&*self.db,
429-
columns::KEY_LOOKUP,
430-
columns::HEADER,
431-
id
432-
)?.is_some(),
455+
BlockId::Hash(_) => self.header(id)?.is_some(),
433456
BlockId::Number(n) => n <= self.meta.read().best_number,
434457
};
435458
match exists {
@@ -1117,12 +1140,6 @@ impl<Block: BlockT> Backend<Block> {
11171140
hash,
11181141
)?;
11191142

1120-
let header_metadata = CachedHeaderMetadata::from(&pending_block.header);
1121-
self.blockchain.insert_header_metadata(
1122-
header_metadata.hash,
1123-
header_metadata,
1124-
);
1125-
11261143
transaction.set_from_vec(columns::HEADER, &lookup_key, pending_block.header.encode());
11271144
if let Some(body) = &pending_block.body {
11281145
transaction.set_from_vec(columns::BODY, &lookup_key, body.encode());
@@ -1271,7 +1288,7 @@ impl<Block: BlockT> Backend<Block> {
12711288

12721289
meta_updates.push((hash, number, pending_block.leaf_state.is_best(), finalized));
12731290

1274-
Some((number, hash, enacted, retracted, displaced_leaf, is_best, cache))
1291+
Some((pending_block.header, number, hash, enacted, retracted, displaced_leaf, is_best, cache))
12751292
} else {
12761293
None
12771294
};
@@ -1297,7 +1314,11 @@ impl<Block: BlockT> Backend<Block> {
12971314

12981315
self.storage.db.commit(transaction)?;
12991316

1317+
// Apply all in-memory state shanges.
1318+
// Code beyond this point can't fail.
1319+
13001320
if let Some((
1321+
header,
13011322
number,
13021323
hash,
13031324
enacted,
@@ -1306,6 +1327,12 @@ impl<Block: BlockT> Backend<Block> {
13061327
is_best,
13071328
mut cache,
13081329
)) = imported {
1330+
let header_metadata = CachedHeaderMetadata::from(&header);
1331+
self.blockchain.insert_header_metadata(
1332+
header_metadata.hash,
1333+
header_metadata,
1334+
);
1335+
cache_header(&mut self.blockchain.header_cache.lock(), hash, Some(header));
13091336
cache.sync_cache(
13101337
&enacted,
13111338
&retracted,

client/service/src/client/client.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1159,12 +1159,12 @@ impl<B, E, Block, RA> Client<B, E, Block, RA> where
11591159

11601160
/// Prepare in-memory header that is used in execution environment.
11611161
fn prepare_environment_block(&self, parent: &BlockId<Block>) -> sp_blockchain::Result<Block::Header> {
1162-
let parent_header = self.backend.blockchain().expect_header(*parent)?;
1162+
let parent_hash = self.backend.blockchain().expect_block_hash_from_id(parent)?;
11631163
Ok(<<Block as BlockT>::Header as HeaderT>::new(
11641164
self.backend.blockchain().expect_block_number_from_id(parent)? + One::one(),
11651165
Default::default(),
11661166
Default::default(),
1167-
parent_header.hash(),
1167+
parent_hash,
11681168
Default::default(),
11691169
))
11701170
}

primitives/blockchain/src/backend.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ pub trait HeaderBackend<Block: BlockT>: Send + Sync {
5353
/// Convert an arbitrary block ID into a block hash.
5454
fn block_number_from_id(&self, id: &BlockId<Block>) -> Result<Option<NumberFor<Block>>> {
5555
match *id {
56-
BlockId::Hash(_) => Ok(self.header(*id)?.map(|h| h.number().clone())),
56+
BlockId::Hash(h) => self.number(h),
5757
BlockId::Number(n) => Ok(Some(n)),
5858
}
5959
}

0 commit comments

Comments
 (0)