have memorydb be generic over the value type

This commit is contained in:
Johann Tuffe 2018-08-22 18:23:56 +08:00
parent 09da6da010
commit 5f7d0e2ec6
2 changed files with 101 additions and 71 deletions

View File

@ -7,7 +7,6 @@ repository = "https://github.com/paritytech/parity-common"
license = "GPL-3.0" license = "GPL-3.0"
[dependencies] [dependencies]
elastic-array = "0.10"
heapsize = "0.4" heapsize = "0.4"
hashdb = { version = "0.2", path = "../hashdb" } hashdb = { version = "0.2", path = "../hashdb" }
plain_hasher = { version = "0.2", path = "../plain_hasher", default-features = false } plain_hasher = { version = "0.2", path = "../plain_hasher", default-features = false }

View File

@ -15,7 +15,6 @@
// along with Parity. If not, see <http://www.gnu.org/licenses/>. // along with Parity. If not, see <http://www.gnu.org/licenses/>.
//! Reference-counted memory-based `HashDB` implementation. //! Reference-counted memory-based `HashDB` implementation.
extern crate elastic_array;
extern crate hashdb; extern crate hashdb;
extern crate heapsize; extern crate heapsize;
extern crate rlp; extern crate rlp;
@ -23,7 +22,7 @@ extern crate rlp;
#[cfg(test)] extern crate tiny_keccak; #[cfg(test)] extern crate tiny_keccak;
#[cfg(test)] extern crate ethereum_types; #[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 heapsize::HeapSizeOf;
use rlp::NULL_RLP; use rlp::NULL_RLP;
use std::collections::hash_map::Entry; use std::collections::hash_map::Entry;
@ -82,23 +81,64 @@ type FastMap<H, T> = HashMap<<H as KeyHasher>::Out, T, hash::BuildHasherDefault<
/// } /// }
/// ``` /// ```
#[derive(Clone, PartialEq)] #[derive(Clone, PartialEq)]
pub struct MemoryDB<H: KeyHasher> { pub struct MemoryDB<H: KeyHasher, T> {
data: FastMap<H, (DBValue, i32)>, data: FastMap<H, (T, i32)>,
hashed_null_node: H::Out, hashed_null_node: H::Out,
null_node_data: T,
} }
impl<H> Default for MemoryDB<H> where H: KeyHasher, H::Out: HeapSizeOf { impl<'a, H, T> Default for MemoryDB<H, T> where H: KeyHasher, H::Out: HeapSizeOf, T: From<&'a [u8]> {
fn default() -> Self { Self::new() } fn default() -> Self { Self::new() }
} }
impl<H> MemoryDB<H> where H: KeyHasher, H::Out: HeapSizeOf { impl<'a, H, T> MemoryDB<H, T>
where H: KeyHasher,
H::Out: HeapSizeOf,
T: From<&'a [u8]>,
{
/// Create a new instance of the memory DB. /// Create a new instance of the memory DB.
pub fn new() -> MemoryDB<H> { pub fn new() -> Self {
MemoryDB { MemoryDB::from_null_node(&NULL_RLP, NULL_RLP.as_ref().into())
data: FastMap::<H,_>::default(), }
hashed_null_node: H::hash(&NULL_RLP) }
impl<H, T> MemoryDB<H, T>
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: &<H as KeyHasher>::Out) -> Option<T> {
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<H: KeyHasher, T> MemoryDB<H, T> {
/// 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::<H,_>::default(),
hashed_null_node: H::hash(null_key),
null_node_data,
}
}
/// Clear all data from the database. /// Clear all data from the database.
/// ///
@ -131,7 +171,7 @@ impl<H> MemoryDB<H> where H: KeyHasher, H::Out: HeapSizeOf {
} }
/// Return the internal map of hashes to data, clearing the current state. /// Return the internal map of hashes to data, clearing the current state.
pub fn drain(&mut self) -> FastMap<H, (DBValue, i32)> { pub fn drain(&mut self) -> FastMap<H, (T, i32)> {
mem::replace(&mut self.data, FastMap::<H,_>::default()) mem::replace(&mut self.data, FastMap::<H,_>::default())
} }
@ -140,37 +180,11 @@ impl<H> MemoryDB<H> where H: KeyHasher, H::Out: HeapSizeOf {
/// ///
/// Even when Some is returned, the data is only guaranteed to be useful /// Even when Some is returned, the data is only guaranteed to be useful
/// when the refs > 0. /// when the refs > 0.
pub fn raw(&self, key: &<H as KeyHasher>::Out) -> Option<(DBValue, i32)> { pub fn raw(&self, key: &<H as KeyHasher>::Out) -> Option<(&T, i32)> {
if key == &self.hashed_null_node { if key == &self.hashed_null_node {
return Some((DBValue::from_slice(&NULL_RLP), 1)); return Some((&self.null_node_data, 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: &<H as KeyHasher>::Out) -> Option<DBValue> {
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
}
} }
self.data.get(key).map(|(value, count)| (value, *count))
} }
/// Consolidate all the entries of `other` into `self`. /// Consolidate all the entries of `other` into `self`.
@ -192,8 +206,21 @@ impl<H> MemoryDB<H> where H: KeyHasher, H::Out: HeapSizeOf {
} }
} }
impl<H: KeyHasher> HashDB<H> for MemoryDB<H> { impl<H, T> MemoryDB<H, T>
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<H, T> HashDB<H, T> for MemoryDB<H, T>
where H: KeyHasher,
T: Default + PartialEq<T> + for<'a> From<&'a [u8]> + Send + Sync,
{
fn keys(&self) -> HashMap<H::Out, i32> { fn keys(&self) -> HashMap<H::Out, i32> {
self.data.iter() self.data.iter()
.filter_map(|(k, v)| if v.1 != 0 { .filter_map(|(k, v)| if v.1 != 0 {
@ -204,13 +231,13 @@ impl<H: KeyHasher> HashDB<H> for MemoryDB<H> {
.collect() .collect()
} }
fn get(&self, key: &H::Out) -> Option<DBValue> { fn get(&self, key: &H::Out) -> Option<&T> {
if key == &self.hashed_null_node { if key == &self.hashed_null_node {
return Some(DBValue::from_slice(&NULL_RLP)); return Some(&self.null_node_data);
} }
match self.data.get(key) { 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 _ => None
} }
} }
@ -226,28 +253,8 @@ impl<H: KeyHasher> HashDB<H> for MemoryDB<H> {
} }
} }
fn insert(&mut self, value: &[u8]) -> H::Out { fn emplace(&mut self, key:H::Out, value: T) {
if value == &NULL_RLP { if value == self.null_node_data {
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 {
return; return;
} }
@ -265,6 +272,26 @@ impl<H: KeyHasher> HashDB<H> for MemoryDB<H> {
} }
} }
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) { fn remove(&mut self, key: &H::Out) {
if key == &self.hashed_null_node { if key == &self.hashed_null_node {
return; return;
@ -276,15 +303,19 @@ impl<H: KeyHasher> HashDB<H> for MemoryDB<H> {
*rc -= 1; *rc -= 1;
}, },
Entry::Vacant(entry) => { Entry::Vacant(entry) => {
entry.insert((DBValue::new(), -1)); entry.insert((T::default(), -1));
}, },
} }
} }
} }
impl<H: KeyHasher> AsHashDB<H> for MemoryDB<H> { impl<H, T> AsHashDB<H, T> for MemoryDB<H, T>
fn as_hashdb(&self) -> &HashDB<H> { self } where H: KeyHasher,
fn as_hashdb_mut(&mut self) -> &mut HashDB<H> { self } T: Default + PartialEq<T> + for<'a> From<&'a[u8]> + Send + Sync,
{
fn as_hashdb(&self) -> &HashDB<H, T> { self }
fn as_hashdb_mut(&mut self) -> &mut HashDB<H, T> { self }
} }
#[cfg(test)] #[cfg(test)]