Pin states in memory so that they are not pruned away while still referenced (#2761)

* State pinning in client

* Canonicalization queue

* Fixed prioritization queue

* possible fix of "hash mismatch"

* Check for pinned discarded states

* Release state before finalization

* Style

* Style
This commit is contained in:
Arkadiy Paronyan
2019-06-04 10:01:12 +02:00
committed by Gavin Wood
parent 6ce7c1c8c8
commit 3b26453047
13 changed files with 392 additions and 194 deletions
+19 -16
View File
@@ -106,7 +106,7 @@ pub trait Backend<H: Hasher> {
}
/// Try convert into trie backend.
fn try_into_trie_backend(self) -> Option<TrieBackend<Self::TrieBackendStorage, H>>;
fn as_trie_backend(&mut self) -> Option<&TrieBackend<Self::TrieBackendStorage, H>>;
/// Calculate the storage root, with given delta over what is already stored
/// in the backend, and produce a "transaction" that can be used to commit.
@@ -185,31 +185,33 @@ impl error::Error for Void {
/// In-memory backend. Fully recomputes tries on each commit but useful for
/// tests.
#[derive(Eq)]
pub struct InMemory<H> {
pub struct InMemory<H: Hasher> {
inner: HashMap<Option<Vec<u8>>, HashMap<Vec<u8>, Vec<u8>>>,
trie: Option<TrieBackend<MemoryDB<H>, H>>,
_hasher: PhantomData<H>,
}
impl<H> Default for InMemory<H> {
impl<H: Hasher> Default for InMemory<H> {
fn default() -> Self {
InMemory {
inner: Default::default(),
trie: None,
_hasher: PhantomData,
}
}
}
impl<H> Clone for InMemory<H> {
impl<H: Hasher> Clone for InMemory<H> {
fn clone(&self) -> Self {
InMemory {
inner: self.inner.clone(),
trie: None,
_hasher: PhantomData,
}
}
}
impl<H> PartialEq for InMemory<H> {
impl<H: Hasher> PartialEq for InMemory<H> {
fn eq(&self, other: &Self) -> bool {
self.inner.eq(&other.inner)
}
@@ -230,27 +232,29 @@ impl<H: Hasher> InMemory<H> {
}
}
impl<H> From<HashMap<Option<Vec<u8>>, HashMap<Vec<u8>, Vec<u8>>>> for InMemory<H> {
impl<H: Hasher> From<HashMap<Option<Vec<u8>>, HashMap<Vec<u8>, Vec<u8>>>> for InMemory<H> {
fn from(inner: HashMap<Option<Vec<u8>>, HashMap<Vec<u8>, Vec<u8>>>) -> Self {
InMemory {
inner: inner,
trie: None,
_hasher: PhantomData,
}
}
}
impl<H> From<HashMap<Vec<u8>, Vec<u8>>> for InMemory<H> {
impl<H: Hasher> From<HashMap<Vec<u8>, Vec<u8>>> for InMemory<H> {
fn from(inner: HashMap<Vec<u8>, Vec<u8>>) -> Self {
let mut expanded = HashMap::new();
expanded.insert(None, inner);
InMemory {
inner: expanded,
trie: None,
_hasher: PhantomData,
}
}
}
impl<H> From<Vec<(Option<Vec<u8>>, Vec<u8>, Option<Vec<u8>>)>> for InMemory<H> {
impl<H: Hasher> From<Vec<(Option<Vec<u8>>, Vec<u8>, Option<Vec<u8>>)>> for InMemory<H> {
fn from(inner: Vec<(Option<Vec<u8>>, Vec<u8>, Option<Vec<u8>>)>) -> Self {
let mut expanded: HashMap<Option<Vec<u8>>, HashMap<Vec<u8>, Vec<u8>>> = HashMap::new();
for (child_key, key, value) in inner {
@@ -365,16 +369,14 @@ impl<H: Hasher> Backend<H> for InMemory<H> {
.collect()
}
fn try_into_trie_backend(
self
)-> Option<TrieBackend<Self::TrieBackendStorage, H>> {
fn as_trie_backend(&mut self)-> Option<&TrieBackend<Self::TrieBackendStorage, H>> {
let mut mdb = MemoryDB::default();
let mut root = None;
let mut new_child_roots = Vec::new();
let mut root_map = None;
for (storage_key, map) in self.inner {
for (storage_key, map) in &self.inner {
if let Some(storage_key) = storage_key.as_ref() {
let ch = insert_into_memory_db::<H, _>(&mut mdb, map.into_iter())?;
let ch = insert_into_memory_db::<H, _>(&mut mdb, map.clone().into_iter())?;
new_child_roots.push((storage_key.clone(), ch.as_ref().into()));
} else {
root_map = Some(map);
@@ -384,14 +386,15 @@ impl<H: Hasher> Backend<H> for InMemory<H> {
if let Some(map) = root_map.take() {
root = Some(insert_into_memory_db::<H, _>(
&mut mdb,
map.into_iter().chain(new_child_roots.into_iter())
map.clone().into_iter().chain(new_child_roots.into_iter())
)?);
}
let root = match root {
Some(root) => root,
None => insert_into_memory_db::<H, _>(&mut mdb, ::std::iter::empty())?,
};
Some(TrieBackend::new(mdb, root))
self.trie = Some(TrieBackend::new(mdb, root));
self.trie.as_ref()
}
}