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"
[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 }

View File

@ -15,7 +15,6 @@
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
//! 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<H, T> = HashMap<<H as KeyHasher>::Out, T, hash::BuildHasherDefault<
/// }
/// ```
#[derive(Clone, PartialEq)]
pub struct MemoryDB<H: KeyHasher> {
data: FastMap<H, (DBValue, i32)>,
pub struct MemoryDB<H: KeyHasher, T> {
data: FastMap<H, (T, i32)>,
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() }
}
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.
pub fn new() -> MemoryDB<H> {
MemoryDB {
data: FastMap::<H,_>::default(),
hashed_null_node: H::hash(&NULL_RLP)
pub fn new() -> Self {
MemoryDB::from_null_node(&NULL_RLP, NULL_RLP.as_ref().into())
}
}
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.
///
@ -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.
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())
}
@ -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
/// 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 {
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: &<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
}
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<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> {
self.data.iter()
.filter_map(|(k, v)| if v.1 != 0 {
@ -204,13 +231,13 @@ impl<H: KeyHasher> HashDB<H> for MemoryDB<H> {
.collect()
}
fn get(&self, key: &H::Out) -> Option<DBValue> {
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<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 = 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<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) {
if key == &self.hashed_null_node {
return;
@ -276,15 +303,19 @@ impl<H: KeyHasher> HashDB<H> for MemoryDB<H> {
*rc -= 1;
},
Entry::Vacant(entry) => {
entry.insert((DBValue::new(), -1));
entry.insert((T::default(), -1));
},
}
}
}
impl<H: KeyHasher> AsHashDB<H> for MemoryDB<H> {
fn as_hashdb(&self) -> &HashDB<H> { self }
fn as_hashdb_mut(&mut self) -> &mut HashDB<H> { self }
impl<H, T> AsHashDB<H, T> for MemoryDB<H, T>
where H: KeyHasher,
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)]