have memorydb be generic over the value type
This commit is contained in:
parent
09da6da010
commit
5f7d0e2ec6
|
@ -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 }
|
||||
|
|
|
@ -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)]
|
||||
|
|
Loading…
Reference in New Issue