Support reference-counting state backend. (#5769)

* Optimize pinning

* Ref counting state backend

* Style

Co-Authored-By: Wei Tang <hi@that.world>

* Update Cargo.lock

* Handle empty node

Co-authored-by: Wei Tang <hi@that.world>
This commit is contained in:
Arkadiy Paronyan
2020-04-27 12:24:50 +02:00
committed by GitHub
parent 636ddd95d2
commit 64ed36d093
11 changed files with 281 additions and 189 deletions
@@ -129,11 +129,8 @@ impl<S: TrieBackendStorage<H>, H: Hasher> Backend<H> for TrieBackend<S, H> where
}
fn pairs(&self) -> Vec<(StorageKey, StorageValue)> {
let mut read_overlay = S::Overlay::default();
let eph = Ephemeral::new(self.essence.backend_storage(), &mut read_overlay);
let collect_all = || -> Result<_, Box<TrieError<H::Out>>> {
let trie = TrieDB::<H>::new(&eph, self.essence.root())?;
let trie = TrieDB::<H>::new(self.essence(), self.essence.root())?;
let mut v = Vec::new();
for x in trie.iter()? {
let (key, value) = x?;
@@ -153,11 +150,8 @@ impl<S: TrieBackendStorage<H>, H: Hasher> Backend<H> for TrieBackend<S, H> where
}
fn keys(&self, prefix: &[u8]) -> Vec<StorageKey> {
let mut read_overlay = S::Overlay::default();
let eph = Ephemeral::new(self.essence.backend_storage(), &mut read_overlay);
let collect_all = || -> Result<_, Box<TrieError<H::Out>>> {
let trie = TrieDB::<H>::new(&eph, self.essence.root())?;
let trie = TrieDB::<H>::new(self.essence(), self.essence.root())?;
let mut v = Vec::new();
for x in trie.iter()? {
let (key, _) = x?;
@@ -20,7 +20,7 @@
use std::ops::Deref;
use std::sync::Arc;
use log::{debug, warn};
use hash_db::{self, Hasher, EMPTY_PREFIX, Prefix};
use hash_db::{self, Hasher, Prefix};
use sp_trie::{Trie, MemoryDB, PrefixedMemoryDB, DBValue,
empty_child_trie_root, read_trie_value, read_child_trie_value,
for_keys_in_child_trie, KeySpacedDB, TrieDBIterator};
@@ -39,6 +39,7 @@ pub trait Storage<H: Hasher>: Send + Sync {
pub struct TrieBackendEssence<S: TrieBackendStorage<H>, H: Hasher> {
storage: S,
root: H::Out,
empty: H::Out,
}
impl<S: TrieBackendStorage<H>, H: Hasher> TrieBackendEssence<S, H> where H::Out: Encode {
@@ -47,6 +48,7 @@ impl<S: TrieBackendStorage<H>, H: Hasher> TrieBackendEssence<S, H> where H::Out:
TrieBackendEssence {
storage,
root,
empty: H::hash(&[0u8]),
}
}
@@ -116,18 +118,13 @@ impl<S: TrieBackendStorage<H>, H: Hasher> TrieBackendEssence<S, H> where H::Out:
child_info: Option<&ChildInfo>,
key: &[u8],
) -> Result<Option<StorageKey>, String> {
let mut read_overlay = S::Overlay::default();
let eph = Ephemeral {
storage: &self.storage,
overlay: &mut read_overlay,
};
let dyn_eph: &dyn hash_db::HashDBRef<_, _>;
let keyspace_eph;
if let Some(child_info) = child_info.as_ref() {
keyspace_eph = KeySpacedDB::new(&eph, child_info.keyspace());
keyspace_eph = KeySpacedDB::new(self, child_info.keyspace());
dyn_eph = &keyspace_eph;
} else {
dyn_eph = &eph;
dyn_eph = self;
}
let trie = TrieDB::<H>::new(dyn_eph, root)
@@ -161,15 +158,9 @@ impl<S: TrieBackendStorage<H>, H: Hasher> TrieBackendEssence<S, H> where H::Out:
/// Get the value of storage at given key.
pub fn storage(&self, key: &[u8]) -> Result<Option<StorageValue>, String> {
let mut read_overlay = S::Overlay::default();
let eph = Ephemeral {
storage: &self.storage,
overlay: &mut read_overlay,
};
let map_e = |e| format!("Trie lookup error: {}", e);
read_trie_value::<Layout<H>, _>(&eph, &self.root, key).map_err(map_e)
read_trie_value::<Layout<H>, _>(self, &self.root, key).map_err(map_e)
}
/// Get the value of child storage at given key.
@@ -181,15 +172,9 @@ impl<S: TrieBackendStorage<H>, H: Hasher> TrieBackendEssence<S, H> where H::Out:
let root = self.child_root(child_info)?
.unwrap_or(empty_child_trie_root::<Layout<H>>().encode());
let mut read_overlay = S::Overlay::default();
let eph = Ephemeral {
storage: &self.storage,
overlay: &mut read_overlay,
};
let map_e = |e| format!("Trie lookup error: {}", e);
read_child_trie_value::<Layout<H>, _>(child_info.keyspace(), &eph, &root, key)
read_child_trie_value::<Layout<H>, _>(child_info.keyspace(), self, &root, key)
.map_err(map_e)
}
@@ -207,15 +192,9 @@ impl<S: TrieBackendStorage<H>, H: Hasher> TrieBackendEssence<S, H> where H::Out:
}
};
let mut read_overlay = S::Overlay::default();
let eph = Ephemeral {
storage: &self.storage,
overlay: &mut read_overlay,
};
if let Err(e) = for_keys_in_child_trie::<Layout<H>, _, Ephemeral<S, H>>(
if let Err(e) = for_keys_in_child_trie::<Layout<H>, _, _>(
child_info.keyspace(),
&eph,
self,
&root,
f,
) {
@@ -254,12 +233,6 @@ impl<S: TrieBackendStorage<H>, H: Hasher> TrieBackendEssence<S, H> where H::Out:
mut f: F,
child_info: Option<&ChildInfo>,
) {
let mut read_overlay = S::Overlay::default();
let eph = Ephemeral {
storage: &self.storage,
overlay: &mut read_overlay,
};
let mut iter = move |db| -> Result<(), Box<TrieError<H::Out>>> {
let trie = TrieDB::<H>::new(db, root)?;
@@ -275,10 +248,10 @@ impl<S: TrieBackendStorage<H>, H: Hasher> TrieBackendEssence<S, H> where H::Out:
};
let result = if let Some(child_info) = child_info {
let db = KeySpacedDB::new(&eph, child_info.keyspace());
let db = KeySpacedDB::new(self, child_info.keyspace());
iter(&db)
} else {
iter(&eph)
iter(self)
};
if let Err(e) = result {
debug!(target: "trie", "Error while iterating by prefix: {}", e);
@@ -296,15 +269,6 @@ pub(crate) struct Ephemeral<'a, S: 'a + TrieBackendStorage<H>, H: 'a + Hasher> {
overlay: &'a mut S::Overlay,
}
impl<'a, S: 'a + TrieBackendStorage<H>, H: 'a + Hasher> hash_db::AsPlainDB<H::Out, DBValue>
for Ephemeral<'a, S, H>
{
fn as_plain_db<'b>(&'b self) -> &'b (dyn hash_db::PlainDB<H::Out, DBValue> + 'b) { self }
fn as_plain_db_mut<'b>(&'b mut self) -> &'b mut (dyn hash_db::PlainDB<H::Out, DBValue> + 'b) {
self
}
}
impl<'a, S: 'a + TrieBackendStorage<H>, H: 'a + Hasher> hash_db::AsHashDB<H, DBValue>
for Ephemeral<'a, S, H>
{
@@ -321,43 +285,6 @@ impl<'a, S: TrieBackendStorage<H>, H: Hasher> Ephemeral<'a, S, H> {
}
}
impl<'a, S: 'a + TrieBackendStorage<H>, H: Hasher> hash_db::PlainDB<H::Out, DBValue>
for Ephemeral<'a, S, H>
{
fn get(&self, key: &H::Out) -> Option<DBValue> {
if let Some(val) = hash_db::HashDB::get(self.overlay, key, EMPTY_PREFIX) {
Some(val)
} else {
match self.storage.get(&key, EMPTY_PREFIX) {
Ok(x) => x,
Err(e) => {
warn!(target: "trie", "Failed to read from DB: {}", e);
None
},
}
}
}
fn contains(&self, key: &H::Out) -> bool {
hash_db::HashDB::get(self, key, EMPTY_PREFIX).is_some()
}
fn emplace(&mut self, key: H::Out, value: DBValue) {
hash_db::HashDB::emplace(self.overlay, key, EMPTY_PREFIX, value)
}
fn remove(&mut self, key: &H::Out) {
hash_db::HashDB::remove(self.overlay, key, EMPTY_PREFIX)
}
}
impl<'a, S: 'a + TrieBackendStorage<H>, H: Hasher> hash_db::PlainDBRef<H::Out, DBValue>
for Ephemeral<'a, S, H>
{
fn get(&self, key: &H::Out) -> Option<DBValue> { hash_db::PlainDB::get(self, key) }
fn contains(&self, key: &H::Out) -> bool { hash_db::PlainDB::contains(self, key) }
}
impl<'a, S: 'a + TrieBackendStorage<H>, H: Hasher> hash_db::HashDB<H, DBValue>
for Ephemeral<'a, S, H>
{
@@ -438,6 +365,59 @@ impl<H: Hasher> TrieBackendStorage<H> for MemoryDB<H> {
}
}
impl<S: TrieBackendStorage<H>, H: Hasher> hash_db::AsHashDB<H, DBValue>
for TrieBackendEssence<S, H>
{
fn as_hash_db<'b>(&'b self) -> &'b (dyn hash_db::HashDB<H, DBValue> + 'b) { self }
fn as_hash_db_mut<'b>(&'b mut self) -> &'b mut (dyn hash_db::HashDB<H, DBValue> + 'b) { self }
}
impl<S: TrieBackendStorage<H>, H: Hasher> hash_db::HashDB<H, DBValue>
for TrieBackendEssence<S, H>
{
fn get(&self, key: &H::Out, prefix: Prefix) -> Option<DBValue> {
if *key == self.empty {
return Some([0u8].to_vec())
}
match self.storage.get(&key, prefix) {
Ok(x) => x,
Err(e) => {
warn!(target: "trie", "Failed to read from DB: {}", e);
None
},
}
}
fn contains(&self, key: &H::Out, prefix: Prefix) -> bool {
hash_db::HashDB::get(self, key, prefix).is_some()
}
fn insert(&mut self, _prefix: Prefix, _value: &[u8]) -> H::Out {
unimplemented!();
}
fn emplace(&mut self, _key: H::Out, _prefix: Prefix, _value: DBValue) {
unimplemented!();
}
fn remove(&mut self, _key: &H::Out, _prefix: Prefix) {
unimplemented!();
}
}
impl<S: TrieBackendStorage<H>, H: Hasher> hash_db::HashDBRef<H, DBValue>
for TrieBackendEssence<S, H>
{
fn get(&self, key: &H::Out, prefix: Prefix) -> Option<DBValue> {
hash_db::HashDB::get(self, key, prefix)
}
fn contains(&self, key: &H::Out, prefix: Prefix) -> bool {
hash_db::HashDB::contains(self, key, prefix)
}
}
#[cfg(test)]
mod test {
use sp_core::{Blake2Hasher, H256};
-6
View File
@@ -86,8 +86,6 @@ pub trait AsHashDB<H: Hasher>: hash_db::AsHashDB<H, trie_db::DBValue> {}
impl<H: Hasher, T: hash_db::AsHashDB<H, trie_db::DBValue>> AsHashDB<H> for T {}
/// Reexport from `hash_db`, with genericity set for `Hasher` trait.
pub type HashDB<'a, H> = dyn hash_db::HashDB<H, trie_db::DBValue> + 'a;
/// Reexport from `hash_db`, with genericity set for key only.
pub type PlainDB<'a, K> = dyn hash_db::PlainDB<K, trie_db::DBValue> + 'a;
/// Reexport from `hash_db`, with genericity set for `Hasher` trait.
/// This uses a `KeyFunction` for prefixing keys internally (avoiding
/// key conflict for non random keys).
@@ -244,7 +242,6 @@ pub fn child_delta_trie_root<L: TrieConfiguration, I, A, B, DB, RD>(
B: AsRef<[u8]>,
RD: AsRef<[u8]>,
DB: hash_db::HashDB<L::Hash, trie_db::DBValue>
+ hash_db::PlainDB<TrieHash<L>, trie_db::DBValue>,
{
let mut root = TrieHash::<L>::default();
// root is fetched from DB, not writable by runtime, so it's always valid.
@@ -274,7 +271,6 @@ pub fn for_keys_in_child_trie<L: TrieConfiguration, F: FnMut(&[u8]), DB>(
) -> Result<(), Box<TrieError<L>>>
where
DB: hash_db::HashDBRef<L::Hash, trie_db::DBValue>
+ hash_db::PlainDBRef<TrieHash<L>, trie_db::DBValue>,
{
let mut root = TrieHash::<L>::default();
// root is fetched from DB, not writable by runtime, so it's always valid.
@@ -324,7 +320,6 @@ pub fn read_child_trie_value<L: TrieConfiguration, DB>(
) -> Result<Option<Vec<u8>>, Box<TrieError<L>>>
where
DB: hash_db::HashDBRef<L::Hash, trie_db::DBValue>
+ hash_db::PlainDBRef<TrieHash<L>, trie_db::DBValue>,
{
let mut root = TrieHash::<L>::default();
// root is fetched from DB, not writable by runtime, so it's always valid.
@@ -344,7 +339,6 @@ pub fn read_child_trie_value_with<L: TrieConfiguration, Q: Query<L::Hash, Item=D
) -> Result<Option<Vec<u8>>, Box<TrieError<L>>>
where
DB: hash_db::HashDBRef<L::Hash, trie_db::DBValue>
+ hash_db::PlainDBRef<TrieHash<L>, trie_db::DBValue>,
{
let mut root = TrieHash::<L>::default();
// root is fetched from DB, not writable by runtime, so it's always valid.