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"
|
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 }
|
||||||
|
|
|
@ -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)]
|
||||||
|
|
Loading…
Reference in New Issue