From 5f7d0e2ec6859231fe9428a01258ac2838b30fce Mon Sep 17 00:00:00 2001 From: Johann Tuffe Date: Wed, 22 Aug 2018 18:23:56 +0800 Subject: [PATCH] have memorydb be generic over the value type --- memorydb/Cargo.toml | 1 - memorydb/src/lib.rs | 171 ++++++++++++++++++++++++++------------------ 2 files changed, 101 insertions(+), 71 deletions(-) diff --git a/memorydb/Cargo.toml b/memorydb/Cargo.toml index 20c4365..81b5874 100644 --- a/memorydb/Cargo.toml +++ b/memorydb/Cargo.toml @@ -7,7 +7,6 @@ repository = "https://github.com/paritytech/parity-common" license = "GPL-3.0" [dependencies] -elastic-array = "0.10" heapsize = "0.4" hashdb = { version = "0.2", path = "../hashdb" } plain_hasher = { version = "0.2", path = "../plain_hasher", default-features = false } diff --git a/memorydb/src/lib.rs b/memorydb/src/lib.rs index f07bce8..9e4c5dc 100644 --- a/memorydb/src/lib.rs +++ b/memorydb/src/lib.rs @@ -15,7 +15,6 @@ // along with Parity. If not, see . //! Reference-counted memory-based `HashDB` implementation. -extern crate elastic_array; extern crate hashdb; extern crate heapsize; extern crate rlp; @@ -23,7 +22,7 @@ extern crate rlp; #[cfg(test)] extern crate tiny_keccak; #[cfg(test)] extern crate ethereum_types; -use hashdb::{HashDB, Hasher as KeyHasher, DBValue, AsHashDB}; +use hashdb::{HashDB, Hasher as KeyHasher, AsHashDB}; use heapsize::HeapSizeOf; use rlp::NULL_RLP; use std::collections::hash_map::Entry; @@ -82,23 +81,64 @@ type FastMap = HashMap<::Out, T, hash::BuildHasherDefault< /// } /// ``` #[derive(Clone, PartialEq)] -pub struct MemoryDB { - data: FastMap, +pub struct MemoryDB { + data: FastMap, hashed_null_node: H::Out, + null_node_data: T, } -impl Default for MemoryDB where H: KeyHasher, H::Out: HeapSizeOf { +impl<'a, H, T> Default for MemoryDB where H: KeyHasher, H::Out: HeapSizeOf, T: From<&'a [u8]> { fn default() -> Self { Self::new() } } -impl MemoryDB where H: KeyHasher, H::Out: HeapSizeOf { +impl<'a, H, T> MemoryDB + where H: KeyHasher, + H::Out: HeapSizeOf, + T: From<&'a [u8]>, +{ /// Create a new instance of the memory DB. - pub fn new() -> MemoryDB { - MemoryDB { - data: FastMap::::default(), - hashed_null_node: H::hash(&NULL_RLP) + pub fn new() -> Self { + MemoryDB::from_null_node(&NULL_RLP, NULL_RLP.as_ref().into()) + } +} + +impl MemoryDB + where H: KeyHasher, + H::Out: HeapSizeOf, + T: Default, +{ + /// Remove an element and delete it from storage if reference count reaches zero. + /// If the value was purged, return the old value. + pub fn remove_and_purge(&mut self, key: &::Out) -> Option { + if key == &self.hashed_null_node { + return None; + } + match self.data.entry(key.clone()) { + Entry::Occupied(mut entry) => + if entry.get().1 == 1 { + Some(entry.remove().0) + } else { + entry.get_mut().1 -= 1; + None + }, + Entry::Vacant(entry) => { + entry.insert((T::default(), -1)); // FIXME: shouldn't it be purged? + None + } } } +} + +impl MemoryDB { + + /// Create a new `MemoryDB` from a given null key/data + pub fn from_null_node(null_key: &[u8], null_node_data: T) -> Self { + MemoryDB { + data: FastMap::::default(), + hashed_null_node: H::hash(null_key), + null_node_data, + } + } /// Clear all data from the database. /// @@ -131,7 +171,7 @@ impl MemoryDB where H: KeyHasher, H::Out: HeapSizeOf { } /// Return the internal map of hashes to data, clearing the current state. - pub fn drain(&mut self) -> FastMap { + pub fn drain(&mut self) -> FastMap { mem::replace(&mut self.data, FastMap::::default()) } @@ -140,37 +180,11 @@ impl MemoryDB where H: KeyHasher, H::Out: HeapSizeOf { /// /// Even when Some is returned, the data is only guaranteed to be useful /// when the refs > 0. - pub fn raw(&self, key: &::Out) -> Option<(DBValue, i32)> { + pub fn raw(&self, key: &::Out) -> Option<(&T, i32)> { if key == &self.hashed_null_node { - return Some((DBValue::from_slice(&NULL_RLP), 1)); - } - self.data.get(key).cloned() - } - - /// Returns the size of allocated heap memory - pub fn mem_used(&self) -> usize { - self.data.heap_size_of_children() - } - - /// Remove an element and delete it from storage if reference count reaches zero. - /// If the value was purged, return the old value. - pub fn remove_and_purge(&mut self, key: &::Out) -> Option { - if key == &self.hashed_null_node { - return None; - } - match self.data.entry(key.clone()) { - Entry::Occupied(mut entry) => - if entry.get().1 == 1 { - Some(entry.remove().0) - } else { - entry.get_mut().1 -= 1; - None - }, - Entry::Vacant(entry) => { - entry.insert((DBValue::new(), -1)); - None - } + return Some((&self.null_node_data, 1)); } + self.data.get(key).map(|(value, count)| (value, *count)) } /// Consolidate all the entries of `other` into `self`. @@ -192,8 +206,21 @@ impl MemoryDB where H: KeyHasher, H::Out: HeapSizeOf { } } -impl HashDB for MemoryDB { +impl MemoryDB + where H: KeyHasher, + H::Out: HeapSizeOf, + T: HeapSizeOf, +{ + /// Returns the size of allocated heap memory + pub fn mem_used(&self) -> usize { + self.data.heap_size_of_children() + } +} +impl HashDB for MemoryDB + where H: KeyHasher, + T: Default + PartialEq + for<'a> From<&'a [u8]> + Send + Sync, +{ fn keys(&self) -> HashMap { self.data.iter() .filter_map(|(k, v)| if v.1 != 0 { @@ -204,13 +231,13 @@ impl HashDB for MemoryDB { .collect() } - fn get(&self, key: &H::Out) -> Option { + fn get(&self, key: &H::Out) -> Option<&T> { if key == &self.hashed_null_node { - return Some(DBValue::from_slice(&NULL_RLP)); + return Some(&self.null_node_data); } match self.data.get(key) { - Some(&(ref d, rc)) if rc > 0 => Some(d.clone()), + Some(&(ref d, rc)) if rc > 0 => Some(d), _ => None } } @@ -226,28 +253,8 @@ impl HashDB for MemoryDB { } } - fn insert(&mut self, value: &[u8]) -> H::Out { - if value == &NULL_RLP { - return self.hashed_null_node.clone(); - } - let key = H::hash(value); - match self.data.entry(key) { - Entry::Occupied(mut entry) => { - let &mut (ref mut old_value, ref mut rc) = entry.get_mut(); - if *rc <= 0 { - *old_value = DBValue::from_slice(value); - } - *rc += 1; - }, - Entry::Vacant(entry) => { - entry.insert((DBValue::from_slice(value), 1)); - }, - } - key - } - - fn emplace(&mut self, key:H::Out, value: DBValue) { - if &*value == &NULL_RLP { + fn emplace(&mut self, key:H::Out, value: T) { + if value == self.null_node_data { return; } @@ -265,6 +272,26 @@ impl HashDB for MemoryDB { } } + fn insert(&mut self, value: &[u8]) -> H::Out { + if value == &NULL_RLP { + return self.hashed_null_node.clone(); + } + let key = H::hash(value); + match self.data.entry(key) { + Entry::Occupied(mut entry) => { + let &mut (ref mut old_value, ref mut rc) = entry.get_mut(); + if *rc <= 0 { + *old_value = value.into(); + } + *rc += 1; + }, + Entry::Vacant(entry) => { + entry.insert((value.into(), 1)); + }, + } + key + } + fn remove(&mut self, key: &H::Out) { if key == &self.hashed_null_node { return; @@ -276,15 +303,19 @@ impl HashDB for MemoryDB { *rc -= 1; }, Entry::Vacant(entry) => { - entry.insert((DBValue::new(), -1)); + entry.insert((T::default(), -1)); }, } } + } -impl AsHashDB for MemoryDB { - fn as_hashdb(&self) -> &HashDB { self } - fn as_hashdb_mut(&mut self) -> &mut HashDB { self } +impl AsHashDB for MemoryDB + where H: KeyHasher, + T: Default + PartialEq + for<'a> From<&'a[u8]> + Send + Sync, +{ + fn as_hashdb(&self) -> &HashDB { self } + fn as_hashdb_mut(&mut self) -> &mut HashDB { self } } #[cfg(test)]