Remove Backend::destroy_state (#5068)

* Remove `Backend::destroy_state`

This removes the `destroy_state` function of `Backend` and instead moves
the functionality into the `Drop` implementation of the state. This
makes it much easier to work with the state, as the user no longer needs
to call` destroy_state` manually. However, it requires that we switch
from `RwLock` to `ReentrantMutex` as while importing a block we maybe
need to lock again in `drop`.

* Bring back the `RwLock` and some other clean ups

* Fix compilation
This commit is contained in:
Gavin Wood
2020-03-05 17:01:52 +01:00
committed by GitHub
parent 26fc97f635
commit a8441ff968
7 changed files with 318 additions and 100 deletions
+61 -31
View File
@@ -80,7 +80,7 @@ use crate::changes_tries_storage::{DbChangesTrieStorage, DbChangesTrieStorageTra
use sc_client::leaves::{LeafSet, FinalizationDisplaced};
use sc_state_db::StateDb;
use sp_blockchain::{CachedHeaderMetadata, HeaderMetadata, HeaderMetadataCache};
use crate::storage_cache::{CachingState, SharedCache, new_shared_cache};
use crate::storage_cache::{CachingState, SyncingCachingState, SharedCache, new_shared_cache};
use crate::stats::StateUsageStats;
use log::{trace, debug, warn};
pub use sc_state_db::PruningMode;
@@ -523,7 +523,7 @@ impl<Block: BlockT> HeaderMetadata<Block> for BlockchainDb<Block> {
/// Database transaction
pub struct BlockImportOperation<Block: BlockT> {
old_state: CachingState<RefTrackingState<Block>, Block>,
old_state: SyncingCachingState<RefTrackingState<Block>, Block>,
db_updates: PrefixedMemoryDB<HashFor<Block>>,
storage_updates: StorageCollection,
child_storage_updates: ChildStorageCollection,
@@ -549,7 +549,7 @@ impl<Block: BlockT> BlockImportOperation<Block> {
}
impl<Block: BlockT> sc_client_api::backend::BlockImportOperation<Block> for BlockImportOperation<Block> {
type State = CachingState<RefTrackingState<Block>, Block>;
type State = SyncingCachingState<RefTrackingState<Block>, Block>;
fn state(&self) -> ClientResult<Option<&Self::State>> {
Ok(Some(&self.old_state))
@@ -755,10 +755,10 @@ pub struct Backend<Block: BlockT> {
blockchain: BlockchainDb<Block>,
canonicalization_delay: u64,
shared_cache: SharedCache<Block>,
import_lock: RwLock<()>,
import_lock: Arc<RwLock<()>>,
is_archive: bool,
io_stats: FrozenForDuration<(kvdb::IoStats, StateUsageInfo)>,
state_usage: StateUsageStats,
state_usage: Arc<StateUsageStats>,
}
impl<Block: BlockT> Backend<Block> {
@@ -830,7 +830,7 @@ impl<Block: BlockT> Backend<Block> {
import_lock: Default::default(),
is_archive: is_archive_pruning,
io_stats: FrozenForDuration::new(std::time::Duration::from_secs(1)),
state_usage: StateUsageStats::new(),
state_usage: Arc::new(StateUsageStats::new()),
})
}
@@ -1132,8 +1132,14 @@ impl<Block: BlockT> Backend<Block> {
self.state_usage.tally_writes(ops, bytes);
let number_u64 = number.saturated_into::<u64>();
let commit = self.storage.state_db.insert_block(&hash, number_u64, &pending_block.header.parent_hash(), changeset)
.map_err(|e: sc_state_db::Error<io::Error>| sp_blockchain::Error::from(format!("State database error: {:?}", e)))?;
let commit = self.storage.state_db.insert_block(
&hash,
number_u64,
&pending_block.header.parent_hash(),
changeset,
).map_err(|e: sc_state_db::Error<io::Error>|
sp_blockchain::Error::from(format!("State database error: {:?}", e))
)?;
apply_state_commit(&mut transaction, commit);
// Check if need to finalize. Genesis is always finalized instantly.
@@ -1161,7 +1167,8 @@ impl<Block: BlockT> Backend<Block> {
changes_trie_cache_ops,
)?);
self.state_usage.merge_sm(operation.old_state.usage_info());
let cache = operation.old_state.release(); // release state reference so that it can be finalized
// release state reference so that it can be finalized
let cache = operation.old_state.into_cache_changes();
if finalized {
// TODO: ensure best chain contains this block.
@@ -1189,9 +1196,20 @@ impl<Block: BlockT> Backend<Block> {
displaced_leaf
};
let mut children = children::read_children(&*self.storage.db, columns::META, meta_keys::CHILDREN_PREFIX, parent_hash)?;
let mut children = children::read_children(
&*self.storage.db,
columns::META,
meta_keys::CHILDREN_PREFIX,
parent_hash,
)?;
children.push(hash);
children::write_children(&mut transaction, columns::META, meta_keys::CHILDREN_PREFIX, parent_hash, children);
children::write_children(
&mut transaction,
columns::META,
meta_keys::CHILDREN_PREFIX,
parent_hash,
children,
);
meta_updates.push((hash, number, pending_block.leaf_state.is_best(), finalized));
@@ -1201,7 +1219,7 @@ impl<Block: BlockT> Backend<Block> {
};
let cache_update = if let Some(set_head) = operation.set_head {
if let Some(header) = ::sc_client::blockchain::HeaderBackend::header(&self.blockchain, set_head)? {
if let Some(header) = sc_client::blockchain::HeaderBackend::header(&self.blockchain, set_head)? {
let number = header.number();
let hash = header.hash();
@@ -1271,7 +1289,6 @@ impl<Block: BlockT> Backend<Block> {
Ok(())
}
// write stuff to a transaction after a new block is finalized.
// this canonicalizes finalized blocks. Fails if called with a block which
// was not a child of the last finalized block.
@@ -1359,11 +1376,13 @@ impl<Block> sc_client_api::backend::AuxStore for Backend<Block> where Block: Blo
impl<Block: BlockT> sc_client_api::backend::Backend<Block> for Backend<Block> {
type BlockImportOperation = BlockImportOperation<Block>;
type Blockchain = BlockchainDb<Block>;
type State = CachingState<RefTrackingState<Block>, Block>;
type State = SyncingCachingState<RefTrackingState<Block>, Block>;
type OffchainStorage = offchain::LocalStorage;
fn begin_operation(&self) -> ClientResult<Self::BlockImportOperation> {
let old_state = self.state_at(BlockId::Hash(Default::default()))?;
let mut old_state = self.state_at(BlockId::Hash(Default::default()))?;
old_state.disable_syncing();
Ok(BlockImportOperation {
pending_block: None,
old_state,
@@ -1386,13 +1405,13 @@ impl<Block: BlockT> sc_client_api::backend::Backend<Block> for Backend<Block> {
block: BlockId<Block>,
) -> ClientResult<()> {
operation.old_state = self.state_at(block)?;
operation.old_state.disable_syncing();
operation.commit_state = true;
Ok(())
}
fn commit_operation(&self, operation: Self::BlockImportOperation)
-> ClientResult<()>
{
fn commit_operation(&self, operation: Self::BlockImportOperation) -> ClientResult<()> {
let usage = operation.old_state.usage_info();
self.state_usage.merge_sm(usage);
@@ -1452,7 +1471,6 @@ impl<Block: BlockT> sc_client_api::backend::Backend<Block> for Backend<Block> {
Some(self.offchain_storage.clone())
}
fn usage_info(&self) -> Option<UsageInfo> {
let (io_stats, state_stats) = self.io_stats.take_or_else(||
(
@@ -1577,7 +1595,17 @@ impl<Block: BlockT> sc_client_api::backend::Backend<Block> for Backend<Block> {
let root = genesis_storage.0.clone();
let db_state = DbState::<Block>::new(Arc::new(genesis_storage), root);
let state = RefTrackingState::new(db_state, self.storage.clone(), None);
return Ok(CachingState::new(state, self.shared_cache.clone(), None));
let caching_state = CachingState::new(
state,
self.shared_cache.clone(),
None,
);
return Ok(SyncingCachingState::new(
caching_state,
self.state_usage.clone(),
self.blockchain.meta.clone(),
self.import_lock.clone(),
));
},
_ => {}
}
@@ -1600,7 +1628,17 @@ impl<Block: BlockT> sc_client_api::backend::Backend<Block> for Backend<Block> {
self.storage.clone(),
Some(hash.clone()),
);
Ok(CachingState::new(state, self.shared_cache.clone(), Some(hash)))
let caching_state = CachingState::new(
state,
self.shared_cache.clone(),
Some(hash),
);
Ok(SyncingCachingState::new(
caching_state,
self.state_usage.clone(),
self.blockchain.meta.clone(),
self.import_lock.clone(),
))
} else {
Err(
sp_blockchain::Error::UnknownBlock(
@@ -1635,17 +1673,8 @@ impl<Block: BlockT> sc_client_api::backend::Backend<Block> for Backend<Block> {
}
}
fn destroy_state(&self, state: Self::State) -> ClientResult<()> {
self.state_usage.merge_sm(state.usage_info());
if let Some(hash) = state.cache.parent_hash.clone() {
let is_best = self.blockchain.meta.read().best_hash == hash;
state.release().sync_cache(&[], &[], vec![], vec![], None, None, is_best);
}
Ok(())
}
fn get_import_lock(&self) -> &RwLock<()> {
&self.import_lock
&*self.import_lock
}
}
@@ -1844,6 +1873,7 @@ pub(crate) mod tests {
op.update_db_storage(overlay).unwrap();
header.state_root = root.into();
op.update_storage(storage, Vec::new()).unwrap();
op.set_block_data(
header,
Some(vec![]),