journaldb changes (#10929)

* inject_batch && commit_batch are no longer a part of journaldb

* get rid of redundant KeyedHashDB trait

* journaldb edition 2018

* journaldb trait moved to the lib.rs file

* making journaldb more idiomatic

* fix parity_bytes reexport

* rename parity-util-mem package in Cargo.toml file
This commit is contained in:
Marek Kotewicz 2019-08-07 01:45:10 +02:00 committed by David
parent 72279856cd
commit 46954527e7
10 changed files with 594 additions and 686 deletions

View File

@ -21,7 +21,7 @@
//! should become general over time to the point where not even a
//! merkle trie is strictly necessary.
use std::collections::{HashMap, HashSet};
use std::collections::HashSet;
use std::sync::Arc;
use ethereum_types::{Address, H256};
@ -29,7 +29,6 @@ use hash_db::{AsHashDB, EMPTY_PREFIX, HashDB, Prefix};
use kvdb::DBValue;
use memory_db::{HashKey, MemoryDB};
use parking_lot::Mutex;
use journaldb::AsKeyedHashDB;
use keccak_hasher::KeccakHasher;
use crate::account::Account;
@ -90,10 +89,6 @@ impl ProofCheck {
}
}
impl journaldb::KeyedHashDB for ProofCheck {
fn keys(&self) -> HashMap<H256, i32> { self.0.keys() }
}
impl HashDB<KeccakHasher, DBValue> for ProofCheck {
fn get(&self, key: &H256, prefix: Prefix) -> Option<DBValue> {
self.0.get(key, prefix)
@ -146,23 +141,11 @@ pub struct Proving<H> {
proof: Mutex<HashSet<DBValue>>,
}
impl<AH: AsKeyedHashDB + Send + Sync> AsKeyedHashDB for Proving<AH> {
fn as_keyed_hash_db(&self) -> &dyn journaldb::KeyedHashDB { self }
}
impl<AH: AsHashDB<KeccakHasher, DBValue> + Send + Sync> AsHashDB<KeccakHasher, DBValue> for Proving<AH> {
fn as_hash_db(&self) -> &dyn HashDB<KeccakHasher, DBValue> { self }
fn as_hash_db_mut(&mut self) -> &mut dyn HashDB<KeccakHasher, DBValue> { self }
}
impl<H: AsKeyedHashDB + Send + Sync> journaldb::KeyedHashDB for Proving<H> {
fn keys(&self) -> HashMap<H256, i32> {
let mut keys = self.base.as_keyed_hash_db().keys();
keys.extend(self.changed.keys());
keys
}
}
impl<H: AsHashDB<KeccakHasher, DBValue> + Send + Sync> HashDB<KeccakHasher, DBValue> for Proving<H> {
fn get(&self, key: &H256, prefix: Prefix) -> Option<DBValue> {
match self.base.as_hash_db().get(key, prefix) {

View File

@ -4,12 +4,13 @@ version = "0.2.0"
authors = ["Parity Technologies <admin@parity.io>"]
description = "A `HashDB` which can manage a short-term journal potentially containing many forks of mutually exclusive actions"
license = "GPL3"
edition = "2018"
[dependencies]
parity-bytes = "0.1"
ethereum-types = "0.6.0"
hash-db = "0.12.4"
parity-util-mem = "0.1"
malloc_size_of = { version = "0.1", package = "parity-util-mem" }
keccak-hasher = { path = "../keccak-hasher" }
kvdb = "0.1"
log = "0.4"

View File

@ -16,20 +16,24 @@
//! Disk-backed `HashDB` implementation.
use std::collections::HashMap;
use std::collections::hash_map::Entry;
use std::io;
use std::sync::Arc;
use std::{
collections::{HashMap, hash_map::Entry},
io,
sync::Arc,
};
use bytes::Bytes;
use ethereum_types::H256;
use parity_util_mem::MallocSizeOfExt;
use hash_db::{HashDB, Prefix};
use keccak_hasher::KeccakHasher;
use kvdb::{KeyValueDB, DBTransaction, DBValue};
use malloc_size_of::MallocSizeOfExt;
use parity_bytes::Bytes;
use rlp::{encode, decode};
use super::{DB_PREFIX_LEN, LATEST_ERA_KEY, error_key_already_exists, error_negatively_reference_hash};
use traits::JournalDB;
use crate::{
DB_PREFIX_LEN, LATEST_ERA_KEY, error_key_already_exists, error_negatively_reference_hash,
JournalDB, new_memory_db
};
/// Implementation of the `HashDB` trait for a disk-backed database with a memory overlay
/// and latent-removal semantics.
@ -52,7 +56,7 @@ impl ArchiveDB {
.expect("Low-level database error.")
.map(|val| decode::<u64>(&val).expect("decoding db value failed"));
ArchiveDB {
overlay: ::new_memory_db(),
overlay: new_memory_db(),
backing,
latest_era,
column,
@ -92,28 +96,7 @@ impl HashDB<KeccakHasher, DBValue> for ArchiveDB {
}
}
impl ::traits::KeyedHashDB for ArchiveDB {
fn keys(&self) -> HashMap<H256, i32> {
let mut ret: HashMap<H256, i32> = self.backing.iter(self.column)
.map(|(key, _)| (H256::from_slice(&*key), 1))
.collect();
for (key, refs) in self.overlay.keys() {
match ret.entry(key) {
Entry::Occupied(mut entry) => {
*entry.get_mut() += refs;
},
Entry::Vacant(entry) => {
entry.insert(refs);
}
}
}
ret
}
}
impl JournalDB for ArchiveDB {
fn boxed_clone(&self) -> Box<dyn JournalDB> {
Box::new(ArchiveDB {
overlay: self.overlay.clone(),
@ -200,15 +183,33 @@ impl JournalDB for ArchiveDB {
fn consolidate(&mut self, with: super::MemoryDB) {
self.overlay.consolidate(with);
}
fn keys(&self) -> HashMap<H256, i32> {
let mut ret: HashMap<H256, i32> = self.backing.iter(self.column)
.map(|(key, _)| (H256::from_slice(&*key), 1))
.collect();
for (key, refs) in self.overlay.keys() {
match ret.entry(key) {
Entry::Occupied(mut entry) => {
*entry.get_mut() += refs;
},
Entry::Vacant(entry) => {
entry.insert(refs);
}
}
}
ret
}
}
#[cfg(test)]
mod tests {
use keccak::keccak;
use keccak_hash::keccak;
use hash_db::{HashDB, EMPTY_PREFIX};
use super::*;
use {kvdb_memorydb, JournalDB};
use kvdb_memorydb;
use crate::{JournalDB, inject_batch, commit_batch};
#[test]
fn insert_same_in_fork() {
@ -216,18 +217,18 @@ mod tests {
let mut jdb = ArchiveDB::new(Arc::new(kvdb_memorydb::create(0)), None);
let x = jdb.insert(EMPTY_PREFIX, b"X");
jdb.commit_batch(1, &keccak(b"1"), None).unwrap();
jdb.commit_batch(2, &keccak(b"2"), None).unwrap();
jdb.commit_batch(3, &keccak(b"1002a"), Some((1, keccak(b"1")))).unwrap();
jdb.commit_batch(4, &keccak(b"1003a"), Some((2, keccak(b"2")))).unwrap();
commit_batch(&mut jdb, 1, &keccak(b"1"), None).unwrap();
commit_batch(&mut jdb, 2, &keccak(b"2"), None).unwrap();
commit_batch(&mut jdb, 3, &keccak(b"1002a"), Some((1, keccak(b"1")))).unwrap();
commit_batch(&mut jdb, 4, &keccak(b"1003a"), Some((2, keccak(b"2")))).unwrap();
jdb.remove(&x, EMPTY_PREFIX);
jdb.commit_batch(3, &keccak(b"1002b"), Some((1, keccak(b"1")))).unwrap();
commit_batch(&mut jdb, 3, &keccak(b"1002b"), Some((1, keccak(b"1")))).unwrap();
let x = jdb.insert(EMPTY_PREFIX, b"X");
jdb.commit_batch(4, &keccak(b"1003b"), Some((2, keccak(b"2")))).unwrap();
commit_batch(&mut jdb, 4, &keccak(b"1003b"), Some((2, keccak(b"2")))).unwrap();
jdb.commit_batch(5, &keccak(b"1004a"), Some((3, keccak(b"1002a")))).unwrap();
jdb.commit_batch(6, &keccak(b"1005a"), Some((4, keccak(b"1003a")))).unwrap();
commit_batch(&mut jdb, 5, &keccak(b"1004a"), Some((3, keccak(b"1002a")))).unwrap();
commit_batch(&mut jdb, 6, &keccak(b"1005a"), Some((4, keccak(b"1003a")))).unwrap();
assert!(jdb.contains(&x, EMPTY_PREFIX));
}
@ -237,16 +238,16 @@ mod tests {
// history is 3
let mut jdb = ArchiveDB::new(Arc::new(kvdb_memorydb::create(0)), None);
let h = jdb.insert(EMPTY_PREFIX, b"foo");
jdb.commit_batch(0, &keccak(b"0"), None).unwrap();
commit_batch(&mut jdb, 0, &keccak(b"0"), None).unwrap();
assert!(jdb.contains(&h, EMPTY_PREFIX));
jdb.remove(&h, EMPTY_PREFIX);
jdb.commit_batch(1, &keccak(b"1"), None).unwrap();
commit_batch(&mut jdb, 1, &keccak(b"1"), None).unwrap();
assert!(jdb.contains(&h, EMPTY_PREFIX));
jdb.commit_batch(2, &keccak(b"2"), None).unwrap();
commit_batch(&mut jdb, 2, &keccak(b"2"), None).unwrap();
assert!(jdb.contains(&h, EMPTY_PREFIX));
jdb.commit_batch(3, &keccak(b"3"), Some((0, keccak(b"0")))).unwrap();
commit_batch(&mut jdb, 3, &keccak(b"3"), Some((0, keccak(b"0")))).unwrap();
assert!(jdb.contains(&h, EMPTY_PREFIX));
jdb.commit_batch(4, &keccak(b"4"), Some((1, keccak(b"1")))).unwrap();
commit_batch(&mut jdb, 4, &keccak(b"4"), Some((1, keccak(b"1")))).unwrap();
assert!(jdb.contains(&h, EMPTY_PREFIX));
}
@ -255,13 +256,13 @@ mod tests {
fn multiple_owed_removal_not_allowed() {
let mut jdb = ArchiveDB::new(Arc::new(kvdb_memorydb::create(0)), None);
let h = jdb.insert(EMPTY_PREFIX, b"foo");
jdb.commit_batch(0, &keccak(b"0"), None).unwrap();
commit_batch(&mut jdb, 0, &keccak(b"0"), None).unwrap();
assert!(jdb.contains(&h, EMPTY_PREFIX));
jdb.remove(&h, EMPTY_PREFIX);
jdb.remove(&h, EMPTY_PREFIX);
// commit_batch would call journal_under(),
// and we don't allow multiple owned removals.
jdb.commit_batch(1, &keccak(b"1"), None).unwrap();
commit_batch(&mut jdb, 1, &keccak(b"1"), None).unwrap();
}
#[test]
@ -271,29 +272,29 @@ mod tests {
let foo = jdb.insert(EMPTY_PREFIX, b"foo");
let bar = jdb.insert(EMPTY_PREFIX, b"bar");
jdb.commit_batch(0, &keccak(b"0"), None).unwrap();
commit_batch(&mut jdb, 0, &keccak(b"0"), None).unwrap();
assert!(jdb.contains(&foo, EMPTY_PREFIX));
assert!(jdb.contains(&bar, EMPTY_PREFIX));
jdb.remove(&foo, EMPTY_PREFIX);
jdb.remove(&bar, EMPTY_PREFIX);
let baz = jdb.insert(EMPTY_PREFIX, b"baz");
jdb.commit_batch(1, &keccak(b"1"), Some((0, keccak(b"0")))).unwrap();
commit_batch(&mut jdb, 1, &keccak(b"1"), Some((0, keccak(b"0")))).unwrap();
assert!(jdb.contains(&foo, EMPTY_PREFIX));
assert!(jdb.contains(&bar, EMPTY_PREFIX));
assert!(jdb.contains(&baz, EMPTY_PREFIX));
let foo = jdb.insert(EMPTY_PREFIX, b"foo");
jdb.remove(&baz, EMPTY_PREFIX);
jdb.commit_batch(2, &keccak(b"2"), Some((1, keccak(b"1")))).unwrap();
commit_batch(&mut jdb, 2, &keccak(b"2"), Some((1, keccak(b"1")))).unwrap();
assert!(jdb.contains(&foo, EMPTY_PREFIX));
assert!(jdb.contains(&baz, EMPTY_PREFIX));
jdb.remove(&foo, EMPTY_PREFIX);
jdb.commit_batch(3, &keccak(b"3"), Some((2, keccak(b"2")))).unwrap();
commit_batch(&mut jdb, 3, &keccak(b"3"), Some((2, keccak(b"2")))).unwrap();
assert!(jdb.contains(&foo, EMPTY_PREFIX));
jdb.commit_batch(4, &keccak(b"4"), Some((3, keccak(b"3")))).unwrap();
commit_batch(&mut jdb, 4, &keccak(b"4"), Some((3, keccak(b"3")))).unwrap();
}
#[test]
@ -303,22 +304,22 @@ mod tests {
let foo = jdb.insert(EMPTY_PREFIX, b"foo");
let bar = jdb.insert(EMPTY_PREFIX, b"bar");
jdb.commit_batch(0, &keccak(b"0"), None).unwrap();
commit_batch(&mut jdb, 0, &keccak(b"0"), None).unwrap();
assert!(jdb.contains(&foo, EMPTY_PREFIX));
assert!(jdb.contains(&bar, EMPTY_PREFIX));
jdb.remove(&foo, EMPTY_PREFIX);
let baz = jdb.insert(EMPTY_PREFIX, b"baz");
jdb.commit_batch(1, &keccak(b"1a"), Some((0, keccak(b"0")))).unwrap();
commit_batch(&mut jdb, 1, &keccak(b"1a"), Some((0, keccak(b"0")))).unwrap();
jdb.remove(&bar, EMPTY_PREFIX);
jdb.commit_batch(1, &keccak(b"1b"), Some((0, keccak(b"0")))).unwrap();
commit_batch(&mut jdb, 1, &keccak(b"1b"), Some((0, keccak(b"0")))).unwrap();
assert!(jdb.contains(&foo, EMPTY_PREFIX));
assert!(jdb.contains(&bar, EMPTY_PREFIX));
assert!(jdb.contains(&baz, EMPTY_PREFIX));
jdb.commit_batch(2, &keccak(b"2b"), Some((1, keccak(b"1b")))).unwrap();
commit_batch(&mut jdb, 2, &keccak(b"2b"), Some((1, keccak(b"1b")))).unwrap();
assert!(jdb.contains(&foo, EMPTY_PREFIX));
}
@ -328,16 +329,16 @@ mod tests {
let mut jdb = ArchiveDB::new(Arc::new(kvdb_memorydb::create(0)), None);
let foo = jdb.insert(EMPTY_PREFIX, b"foo");
jdb.commit_batch(0, &keccak(b"0"), None).unwrap();
commit_batch(&mut jdb, 0, &keccak(b"0"), None).unwrap();
assert!(jdb.contains(&foo, EMPTY_PREFIX));
jdb.remove(&foo, EMPTY_PREFIX);
jdb.commit_batch(1, &keccak(b"1"), Some((0, keccak(b"0")))).unwrap();
commit_batch(&mut jdb, 1, &keccak(b"1"), Some((0, keccak(b"0")))).unwrap();
jdb.insert(EMPTY_PREFIX, b"foo");
assert!(jdb.contains(&foo, EMPTY_PREFIX));
jdb.commit_batch(2, &keccak(b"2"), Some((1, keccak(b"1")))).unwrap();
commit_batch(&mut jdb, 2, &keccak(b"2"), Some((1, keccak(b"1")))).unwrap();
assert!(jdb.contains(&foo, EMPTY_PREFIX));
jdb.commit_batch(3, &keccak(b"2"), Some((0, keccak(b"2")))).unwrap();
commit_batch(&mut jdb, 3, &keccak(b"2"), Some((0, keccak(b"2")))).unwrap();
assert!(jdb.contains(&foo, EMPTY_PREFIX));
}
@ -345,16 +346,16 @@ mod tests {
fn fork_same_key() {
// history is 1
let mut jdb = ArchiveDB::new(Arc::new(kvdb_memorydb::create(0)), None);
jdb.commit_batch(0, &keccak(b"0"), None).unwrap();
commit_batch(&mut jdb, 0, &keccak(b"0"), None).unwrap();
let foo = jdb.insert(EMPTY_PREFIX, b"foo");
jdb.commit_batch(1, &keccak(b"1a"), Some((0, keccak(b"0")))).unwrap();
commit_batch(&mut jdb, 1, &keccak(b"1a"), Some((0, keccak(b"0")))).unwrap();
jdb.insert(EMPTY_PREFIX, b"foo");
jdb.commit_batch(1, &keccak(b"1b"), Some((0, keccak(b"0")))).unwrap();
commit_batch(&mut jdb, 1, &keccak(b"1b"), Some((0, keccak(b"0")))).unwrap();
assert!(jdb.contains(&foo, EMPTY_PREFIX));
jdb.commit_batch(2, &keccak(b"2a"), Some((1, keccak(b"1a")))).unwrap();
commit_batch(&mut jdb, 2, &keccak(b"2a"), Some((1, keccak(b"1a")))).unwrap();
assert!(jdb.contains(&foo, EMPTY_PREFIX));
}
@ -368,21 +369,21 @@ mod tests {
// history is 1
let foo = jdb.insert(EMPTY_PREFIX, b"foo");
jdb.emplace(bar.clone(), EMPTY_PREFIX, DBValue::from_slice(b"bar"));
jdb.commit_batch(0, &keccak(b"0"), None).unwrap();
commit_batch(&mut jdb, 0, &keccak(b"0"), None).unwrap();
foo
};
{
let mut jdb = ArchiveDB::new(shared_db.clone(), None);
jdb.remove(&foo, EMPTY_PREFIX);
jdb.commit_batch(1, &keccak(b"1"), Some((0, keccak(b"0")))).unwrap();
commit_batch(&mut jdb, 1, &keccak(b"1"), Some((0, keccak(b"0")))).unwrap();
}
{
let mut jdb = ArchiveDB::new(shared_db, None);
assert!(jdb.contains(&foo, EMPTY_PREFIX));
assert!(jdb.contains(&bar, EMPTY_PREFIX));
jdb.commit_batch(2, &keccak(b"2"), Some((1, keccak(b"1")))).unwrap();
commit_batch(&mut jdb, 2, &keccak(b"2"), Some((1, keccak(b"1")))).unwrap();
}
}
@ -394,24 +395,24 @@ mod tests {
let mut jdb = ArchiveDB::new(shared_db.clone(), None);
// history is 1
let foo = jdb.insert(EMPTY_PREFIX, b"foo");
jdb.commit_batch(0, &keccak(b"0"), None).unwrap();
jdb.commit_batch(1, &keccak(b"1"), Some((0, keccak(b"0")))).unwrap();
commit_batch(&mut jdb, 0, &keccak(b"0"), None).unwrap();
commit_batch(&mut jdb, 1, &keccak(b"1"), Some((0, keccak(b"0")))).unwrap();
// foo is ancient history.
jdb.insert(EMPTY_PREFIX, b"foo");
jdb.commit_batch(2, &keccak(b"2"), Some((1, keccak(b"1")))).unwrap();
commit_batch(&mut jdb, 2, &keccak(b"2"), Some((1, keccak(b"1")))).unwrap();
foo
};
{
let mut jdb = ArchiveDB::new(shared_db, None);
jdb.remove(&foo, EMPTY_PREFIX);
jdb.commit_batch(3, &keccak(b"3"), Some((2, keccak(b"2")))).unwrap();
commit_batch(&mut jdb, 3, &keccak(b"3"), Some((2, keccak(b"2")))).unwrap();
assert!(jdb.contains(&foo, EMPTY_PREFIX));
jdb.remove(&foo, EMPTY_PREFIX);
jdb.commit_batch(4, &keccak(b"4"), Some((3, keccak(b"3")))).unwrap();
jdb.commit_batch(5, &keccak(b"5"), Some((4, keccak(b"4")))).unwrap();
commit_batch(&mut jdb, 4, &keccak(b"4"), Some((3, keccak(b"3")))).unwrap();
commit_batch(&mut jdb, 5, &keccak(b"5"), Some((4, keccak(b"4")))).unwrap();
}
}
@ -423,19 +424,19 @@ mod tests {
// history is 1
let foo = jdb.insert(EMPTY_PREFIX, b"foo");
let bar = jdb.insert(EMPTY_PREFIX, b"bar");
jdb.commit_batch(0, &keccak(b"0"), None).unwrap();
commit_batch(&mut jdb, 0, &keccak(b"0"), None).unwrap();
jdb.remove(&foo, EMPTY_PREFIX);
let baz = jdb.insert(EMPTY_PREFIX, b"baz");
jdb.commit_batch(1, &keccak(b"1a"), Some((0, keccak(b"0")))).unwrap();
commit_batch(&mut jdb, 1, &keccak(b"1a"), Some((0, keccak(b"0")))).unwrap();
jdb.remove(&bar, EMPTY_PREFIX);
jdb.commit_batch(1, &keccak(b"1b"), Some((0, keccak(b"0")))).unwrap();
commit_batch(&mut jdb, 1, &keccak(b"1b"), Some((0, keccak(b"0")))).unwrap();
(foo, bar, baz)
};
{
let mut jdb = ArchiveDB::new(shared_db, None);
jdb.commit_batch(2, &keccak(b"2b"), Some((1, keccak(b"1b")))).unwrap();
commit_batch(&mut jdb, 2, &keccak(b"2b"), Some((1, keccak(b"1b")))).unwrap();
assert!(jdb.contains(&foo, EMPTY_PREFIX));
}
}
@ -447,7 +448,7 @@ mod tests {
let key = {
let mut jdb = ArchiveDB::new(shared_db.clone(), None);
let key = jdb.insert(EMPTY_PREFIX, b"foo");
jdb.commit_batch(0, &keccak(b"0"), None).unwrap();
commit_batch(&mut jdb, 0, &keccak(b"0"), None).unwrap();
key
};
@ -462,11 +463,11 @@ mod tests {
fn inject() {
let mut jdb = ArchiveDB::new(Arc::new(kvdb_memorydb::create(0)), None);
let key = jdb.insert(EMPTY_PREFIX, b"dog");
jdb.inject_batch().unwrap();
inject_batch(&mut jdb).unwrap();
assert_eq!(jdb.get(&key, EMPTY_PREFIX).unwrap(), DBValue::from_slice(b"dog"));
jdb.remove(&key, EMPTY_PREFIX);
jdb.inject_batch().unwrap();
inject_batch(&mut jdb).unwrap();
assert!(jdb.get(&key, EMPTY_PREFIX).is_none());
}

View File

@ -17,13 +17,16 @@
//! Impls of the `AsHashDB` upcast trait for all different variants of DB
use hash_db::{HashDB, AsHashDB};
use keccak_hasher::KeccakHasher;
use archivedb::ArchiveDB;
use earlymergedb::EarlyMergeDB;
use overlayrecentdb::OverlayRecentDB;
use refcounteddb::RefCountedDB;
use overlaydb::OverlayDB;
use kvdb::DBValue;
use crate::{KeyedHashDB, AsKeyedHashDB};
use crate::{
archivedb::ArchiveDB,
earlymergedb::EarlyMergeDB,
overlayrecentdb::OverlayRecentDB,
refcounteddb::RefCountedDB,
overlaydb::OverlayDB,
};
impl AsHashDB<KeccakHasher, DBValue> for ArchiveDB {
fn as_hash_db(&self) -> &dyn HashDB<KeccakHasher, DBValue> { self }
@ -49,23 +52,3 @@ impl AsHashDB<KeccakHasher, DBValue> for OverlayDB {
fn as_hash_db(&self) -> &dyn HashDB<KeccakHasher, DBValue> { self }
fn as_hash_db_mut(&mut self) -> &mut dyn HashDB<KeccakHasher, DBValue> { self }
}
impl AsKeyedHashDB for ArchiveDB {
fn as_keyed_hash_db(&self) -> &dyn KeyedHashDB { self }
}
impl AsKeyedHashDB for EarlyMergeDB {
fn as_keyed_hash_db(&self) -> &dyn KeyedHashDB { self }
}
impl AsKeyedHashDB for OverlayRecentDB {
fn as_keyed_hash_db(&self) -> &dyn KeyedHashDB { self }
}
impl AsKeyedHashDB for RefCountedDB {
fn as_keyed_hash_db(&self) -> &dyn KeyedHashDB { self }
}
impl AsKeyedHashDB for OverlayDB {
fn as_keyed_hash_db(&self) -> &dyn KeyedHashDB { self }
}

View File

@ -16,22 +16,27 @@
//! Disk-backed `HashDB` implementation.
use std::collections::HashMap;
use std::collections::hash_map::Entry;
use std::io;
use std::sync::Arc;
use std::{
collections::{HashMap, hash_map::Entry},
io,
sync::Arc,
};
use bytes::Bytes;
use ethereum_types::H256;
use hash_db::{HashDB, Prefix};
use parity_util_mem::{MallocSizeOf, allocators::new_malloc_size_ops};
use keccak_hasher::KeccakHasher;
use kvdb::{KeyValueDB, DBTransaction, DBValue};
use log::{trace, warn};
use malloc_size_of::{MallocSizeOf, allocators::new_malloc_size_ops};
use parity_bytes::Bytes;
use parking_lot::RwLock;
use rlp::{encode, decode};
use super::{DB_PREFIX_LEN, LATEST_ERA_KEY, error_negatively_reference_hash, error_key_already_exists};
use super::traits::JournalDB;
use util::{DatabaseKey, DatabaseValueView, DatabaseValueRef};
use crate::{
DB_PREFIX_LEN, LATEST_ERA_KEY, error_negatively_reference_hash, error_key_already_exists,
JournalDB, new_memory_db,
util::{DatabaseKey, DatabaseValueView, DatabaseValueRef},
};
#[derive(Debug, Clone, PartialEq, Eq, MallocSizeOf)]
struct RefInfo {
@ -115,7 +120,7 @@ impl EarlyMergeDB {
let (latest_era, refs) = EarlyMergeDB::read_refs(&*backing, col);
let refs = Some(Arc::new(RwLock::new(refs)));
EarlyMergeDB {
overlay: ::new_memory_db(),
overlay: new_memory_db(),
backing: backing,
refs: refs,
latest_era: latest_era,
@ -311,26 +316,6 @@ impl HashDB<KeccakHasher, DBValue> for EarlyMergeDB {
}
}
impl ::traits::KeyedHashDB for EarlyMergeDB {
fn keys(&self) -> HashMap<H256, i32> {
let mut ret: HashMap<H256, i32> = self.backing.iter(self.column)
.map(|(key, _)| (H256::from_slice(&*key), 1))
.collect();
for (key, refs) in self.overlay.keys() {
match ret.entry(key) {
Entry::Occupied(mut entry) => {
*entry.get_mut() += refs;
},
Entry::Vacant(entry) => {
entry.insert(refs);
}
}
}
ret
}
}
impl JournalDB for EarlyMergeDB {
fn boxed_clone(&self) -> Box<dyn JournalDB> {
Box::new(EarlyMergeDB {
@ -519,16 +504,33 @@ impl JournalDB for EarlyMergeDB {
fn consolidate(&mut self, with: super::MemoryDB) {
self.overlay.consolidate(with);
}
fn keys(&self) -> HashMap<H256, i32> {
let mut ret: HashMap<H256, i32> = self.backing.iter(self.column)
.map(|(key, _)| (H256::from_slice(&*key), 1))
.collect();
for (key, refs) in self.overlay.keys() {
match ret.entry(key) {
Entry::Occupied(mut entry) => {
*entry.get_mut() += refs;
},
Entry::Vacant(entry) => {
entry.insert(refs);
}
}
}
ret
}
}
#[cfg(test)]
mod tests {
use keccak::keccak;
use keccak_hash::keccak;
use hash_db::{HashDB, EMPTY_PREFIX};
use super::*;
use super::super::traits::JournalDB;
use kvdb_memorydb;
use crate::{inject_batch, commit_batch};
#[test]
fn insert_same_in_fork() {
@ -536,25 +538,25 @@ mod tests {
let mut jdb = new_db();
let x = jdb.insert(EMPTY_PREFIX, b"X");
jdb.commit_batch(1, &keccak(b"1"), None).unwrap();
commit_batch(&mut jdb, 1, &keccak(b"1"), None).unwrap();
assert!(jdb.can_reconstruct_refs());
jdb.commit_batch(2, &keccak(b"2"), None).unwrap();
commit_batch(&mut jdb, 2, &keccak(b"2"), None).unwrap();
assert!(jdb.can_reconstruct_refs());
jdb.commit_batch(3, &keccak(b"1002a"), Some((1, keccak(b"1")))).unwrap();
commit_batch(&mut jdb, 3, &keccak(b"1002a"), Some((1, keccak(b"1")))).unwrap();
assert!(jdb.can_reconstruct_refs());
jdb.commit_batch(4, &keccak(b"1003a"), Some((2, keccak(b"2")))).unwrap();
commit_batch(&mut jdb, 4, &keccak(b"1003a"), Some((2, keccak(b"2")))).unwrap();
assert!(jdb.can_reconstruct_refs());
jdb.remove(&x, EMPTY_PREFIX);
jdb.commit_batch(3, &keccak(b"1002b"), Some((1, keccak(b"1")))).unwrap();
commit_batch(&mut jdb, 3, &keccak(b"1002b"), Some((1, keccak(b"1")))).unwrap();
assert!(jdb.can_reconstruct_refs());
let x = jdb.insert(EMPTY_PREFIX, b"X");
jdb.commit_batch(4, &keccak(b"1003b"), Some((2, keccak(b"2")))).unwrap();
commit_batch(&mut jdb, 4, &keccak(b"1003b"), Some((2, keccak(b"2")))).unwrap();
assert!(jdb.can_reconstruct_refs());
jdb.commit_batch(5, &keccak(b"1004a"), Some((3, keccak(b"1002a")))).unwrap();
commit_batch(&mut jdb, 5, &keccak(b"1004a"), Some((3, keccak(b"1002a")))).unwrap();
assert!(jdb.can_reconstruct_refs());
jdb.commit_batch(6, &keccak(b"1005a"), Some((4, keccak(b"1003a")))).unwrap();
commit_batch(&mut jdb, 6, &keccak(b"1005a"), Some((4, keccak(b"1003a")))).unwrap();
assert!(jdb.can_reconstruct_refs());
assert!(jdb.contains(&x, EMPTY_PREFIX));
@ -564,17 +566,17 @@ mod tests {
fn insert_older_era() {
let mut jdb = new_db();
let foo = jdb.insert(EMPTY_PREFIX, b"foo");
jdb.commit_batch(0, &keccak(b"0a"), None).unwrap();
commit_batch(&mut jdb, 0, &keccak(b"0a"), None).unwrap();
assert!(jdb.can_reconstruct_refs());
let bar = jdb.insert(EMPTY_PREFIX, b"bar");
jdb.commit_batch(1, &keccak(b"1"), Some((0, keccak(b"0a")))).unwrap();
commit_batch(&mut jdb, 1, &keccak(b"1"), Some((0, keccak(b"0a")))).unwrap();
assert!(jdb.can_reconstruct_refs());
jdb.remove(&bar, EMPTY_PREFIX);
jdb.commit_batch(0, &keccak(b"0b"), None).unwrap();
commit_batch(&mut jdb, 0, &keccak(b"0b"), None).unwrap();
assert!(jdb.can_reconstruct_refs());
jdb.commit_batch(2, &keccak(b"2"), Some((1, keccak(b"1")))).unwrap();
commit_batch(&mut jdb, 2, &keccak(b"2"), Some((1, keccak(b"1")))).unwrap();
assert!(jdb.contains(&foo, EMPTY_PREFIX));
assert!(jdb.contains(&bar, EMPTY_PREFIX));
@ -585,20 +587,20 @@ mod tests {
// history is 3
let mut jdb = new_db();
let h = jdb.insert(EMPTY_PREFIX, b"foo");
jdb.commit_batch(0, &keccak(b"0"), None).unwrap();
commit_batch(&mut jdb, 0, &keccak(b"0"), None).unwrap();
assert!(jdb.can_reconstruct_refs());
assert!(jdb.contains(&h, EMPTY_PREFIX));
jdb.remove(&h, EMPTY_PREFIX);
jdb.commit_batch(1, &keccak(b"1"), None).unwrap();
commit_batch(&mut jdb, 1, &keccak(b"1"), None).unwrap();
assert!(jdb.can_reconstruct_refs());
assert!(jdb.contains(&h, EMPTY_PREFIX));
jdb.commit_batch(2, &keccak(b"2"), None).unwrap();
commit_batch(&mut jdb, 2, &keccak(b"2"), None).unwrap();
assert!(jdb.can_reconstruct_refs());
assert!(jdb.contains(&h, EMPTY_PREFIX));
jdb.commit_batch(3, &keccak(b"3"), Some((0, keccak(b"0")))).unwrap();
commit_batch(&mut jdb, 3, &keccak(b"3"), Some((0, keccak(b"0")))).unwrap();
assert!(jdb.can_reconstruct_refs());
assert!(jdb.contains(&h, EMPTY_PREFIX));
jdb.commit_batch(4, &keccak(b"4"), Some((1, keccak(b"1")))).unwrap();
commit_batch(&mut jdb, 4, &keccak(b"4"), Some((1, keccak(b"1")))).unwrap();
assert!(jdb.can_reconstruct_refs());
assert!(!jdb.contains(&h, EMPTY_PREFIX));
}
@ -610,7 +612,7 @@ mod tests {
let foo = jdb.insert(EMPTY_PREFIX, b"foo");
let bar = jdb.insert(EMPTY_PREFIX, b"bar");
jdb.commit_batch(0, &keccak(b"0"), None).unwrap();
commit_batch(&mut jdb, 0, &keccak(b"0"), None).unwrap();
assert!(jdb.can_reconstruct_refs());
assert!(jdb.contains(&foo, EMPTY_PREFIX));
assert!(jdb.contains(&bar, EMPTY_PREFIX));
@ -618,7 +620,7 @@ mod tests {
jdb.remove(&foo, EMPTY_PREFIX);
jdb.remove(&bar, EMPTY_PREFIX);
let baz = jdb.insert(EMPTY_PREFIX, b"baz");
jdb.commit_batch(1, &keccak(b"1"), Some((0, keccak(b"0")))).unwrap();
commit_batch(&mut jdb, 1, &keccak(b"1"), Some((0, keccak(b"0")))).unwrap();
assert!(jdb.can_reconstruct_refs());
assert!(jdb.contains(&foo, EMPTY_PREFIX));
assert!(jdb.contains(&bar, EMPTY_PREFIX));
@ -626,20 +628,20 @@ mod tests {
let foo = jdb.insert(EMPTY_PREFIX, b"foo");
jdb.remove(&baz, EMPTY_PREFIX);
jdb.commit_batch(2, &keccak(b"2"), Some((1, keccak(b"1")))).unwrap();
commit_batch(&mut jdb, 2, &keccak(b"2"), Some((1, keccak(b"1")))).unwrap();
assert!(jdb.can_reconstruct_refs());
assert!(jdb.contains(&foo, EMPTY_PREFIX));
assert!(!jdb.contains(&bar, EMPTY_PREFIX));
assert!(jdb.contains(&baz, EMPTY_PREFIX));
jdb.remove(&foo, EMPTY_PREFIX);
jdb.commit_batch(3, &keccak(b"3"), Some((2, keccak(b"2")))).unwrap();
commit_batch(&mut jdb, 3, &keccak(b"3"), Some((2, keccak(b"2")))).unwrap();
assert!(jdb.can_reconstruct_refs());
assert!(jdb.contains(&foo, EMPTY_PREFIX));
assert!(!jdb.contains(&bar, EMPTY_PREFIX));
assert!(!jdb.contains(&baz, EMPTY_PREFIX));
jdb.commit_batch(4, &keccak(b"4"), Some((3, keccak(b"3")))).unwrap();
commit_batch(&mut jdb, 4, &keccak(b"4"), Some((3, keccak(b"3")))).unwrap();
assert!(jdb.can_reconstruct_refs());
assert!(!jdb.contains(&foo, EMPTY_PREFIX));
assert!(!jdb.contains(&bar, EMPTY_PREFIX));
@ -653,25 +655,25 @@ mod tests {
let foo = jdb.insert(EMPTY_PREFIX, b"foo");
let bar = jdb.insert(EMPTY_PREFIX, b"bar");
jdb.commit_batch(0, &keccak(b"0"), None).unwrap();
commit_batch(&mut jdb, 0, &keccak(b"0"), None).unwrap();
assert!(jdb.can_reconstruct_refs());
assert!(jdb.contains(&foo, EMPTY_PREFIX));
assert!(jdb.contains(&bar, EMPTY_PREFIX));
jdb.remove(&foo, EMPTY_PREFIX);
let baz = jdb.insert(EMPTY_PREFIX, b"baz");
jdb.commit_batch(1, &keccak(b"1a"), Some((0, keccak(b"0")))).unwrap();
commit_batch(&mut jdb, 1, &keccak(b"1a"), Some((0, keccak(b"0")))).unwrap();
assert!(jdb.can_reconstruct_refs());
jdb.remove(&bar, EMPTY_PREFIX);
jdb.commit_batch(1, &keccak(b"1b"), Some((0, keccak(b"0")))).unwrap();
commit_batch(&mut jdb, 1, &keccak(b"1b"), Some((0, keccak(b"0")))).unwrap();
assert!(jdb.can_reconstruct_refs());
assert!(jdb.contains(&foo, EMPTY_PREFIX));
assert!(jdb.contains(&bar, EMPTY_PREFIX));
assert!(jdb.contains(&baz, EMPTY_PREFIX));
jdb.commit_batch(2, &keccak(b"2b"), Some((1, keccak(b"1b")))).unwrap();
commit_batch(&mut jdb, 2, &keccak(b"2b"), Some((1, keccak(b"1b")))).unwrap();
assert!(jdb.can_reconstruct_refs());
assert!(jdb.contains(&foo, EMPTY_PREFIX));
assert!(!jdb.contains(&baz, EMPTY_PREFIX));
@ -684,19 +686,19 @@ mod tests {
let mut jdb = new_db();
let foo = jdb.insert(EMPTY_PREFIX, b"foo");
jdb.commit_batch(0, &keccak(b"0"), None).unwrap();
commit_batch(&mut jdb, 0, &keccak(b"0"), None).unwrap();
assert!(jdb.can_reconstruct_refs());
assert!(jdb.contains(&foo, EMPTY_PREFIX));
jdb.remove(&foo, EMPTY_PREFIX);
jdb.commit_batch(1, &keccak(b"1"), Some((0, keccak(b"0")))).unwrap();
commit_batch(&mut jdb, 1, &keccak(b"1"), Some((0, keccak(b"0")))).unwrap();
assert!(jdb.can_reconstruct_refs());
jdb.insert(EMPTY_PREFIX, b"foo");
assert!(jdb.contains(&foo, EMPTY_PREFIX));
jdb.commit_batch(2, &keccak(b"2"), Some((1, keccak(b"1")))).unwrap();
commit_batch(&mut jdb, 2, &keccak(b"2"), Some((1, keccak(b"1")))).unwrap();
assert!(jdb.can_reconstruct_refs());
assert!(jdb.contains(&foo, EMPTY_PREFIX));
jdb.commit_batch(3, &keccak(b"2"), Some((0, keccak(b"2")))).unwrap();
commit_batch(&mut jdb, 3, &keccak(b"2"), Some((0, keccak(b"2")))).unwrap();
assert!(jdb.can_reconstruct_refs());
assert!(jdb.contains(&foo, EMPTY_PREFIX));
}
@ -705,24 +707,24 @@ mod tests {
fn fork_same_key_one() {
let mut jdb = new_db();
jdb.commit_batch(0, &keccak(b"0"), None).unwrap();
commit_batch(&mut jdb, 0, &keccak(b"0"), None).unwrap();
assert!(jdb.can_reconstruct_refs());
let foo = jdb.insert(EMPTY_PREFIX, b"foo");
jdb.commit_batch(1, &keccak(b"1a"), Some((0, keccak(b"0")))).unwrap();
commit_batch(&mut jdb, 1, &keccak(b"1a"), Some((0, keccak(b"0")))).unwrap();
assert!(jdb.can_reconstruct_refs());
jdb.insert(EMPTY_PREFIX, b"foo");
jdb.commit_batch(1, &keccak(b"1b"), Some((0, keccak(b"0")))).unwrap();
commit_batch(&mut jdb, 1, &keccak(b"1b"), Some((0, keccak(b"0")))).unwrap();
assert!(jdb.can_reconstruct_refs());
jdb.insert(EMPTY_PREFIX, b"foo");
jdb.commit_batch(1, &keccak(b"1c"), Some((0, keccak(b"0")))).unwrap();
commit_batch(&mut jdb, 1, &keccak(b"1c"), Some((0, keccak(b"0")))).unwrap();
assert!(jdb.can_reconstruct_refs());
assert!(jdb.contains(&foo, EMPTY_PREFIX));
jdb.commit_batch(2, &keccak(b"2a"), Some((1, keccak(b"1a")))).unwrap();
commit_batch(&mut jdb, 2, &keccak(b"2a"), Some((1, keccak(b"1a")))).unwrap();
assert!(jdb.can_reconstruct_refs());
assert!(jdb.contains(&foo, EMPTY_PREFIX));
}
@ -730,24 +732,24 @@ mod tests {
#[test]
fn fork_same_key_other() {
let mut jdb = new_db();
jdb.commit_batch(0, &keccak(b"0"), None).unwrap();
commit_batch(&mut jdb, 0, &keccak(b"0"), None).unwrap();
assert!(jdb.can_reconstruct_refs());
let foo = jdb.insert(EMPTY_PREFIX, b"foo");
jdb.commit_batch(1, &keccak(b"1a"), Some((0, keccak(b"0")))).unwrap();
commit_batch(&mut jdb, 1, &keccak(b"1a"), Some((0, keccak(b"0")))).unwrap();
assert!(jdb.can_reconstruct_refs());
jdb.insert(EMPTY_PREFIX, b"foo");
jdb.commit_batch(1, &keccak(b"1b"), Some((0, keccak(b"0")))).unwrap();
commit_batch(&mut jdb, 1, &keccak(b"1b"), Some((0, keccak(b"0")))).unwrap();
assert!(jdb.can_reconstruct_refs());
jdb.insert(EMPTY_PREFIX, b"foo");
jdb.commit_batch(1, &keccak(b"1c"), Some((0, keccak(b"0")))).unwrap();
commit_batch(&mut jdb, 1, &keccak(b"1c"), Some((0, keccak(b"0")))).unwrap();
assert!(jdb.can_reconstruct_refs());
assert!(jdb.contains(&foo, EMPTY_PREFIX));
jdb.commit_batch(2, &keccak(b"2b"), Some((1, keccak(b"1b")))).unwrap();
commit_batch(&mut jdb, 2, &keccak(b"2b"), Some((1, keccak(b"1b")))).unwrap();
assert!(jdb.can_reconstruct_refs());
assert!(jdb.contains(&foo, EMPTY_PREFIX));
}
@ -755,33 +757,33 @@ mod tests {
#[test]
fn fork_ins_del_ins() {
let mut jdb = new_db();
jdb.commit_batch(0, &keccak(b"0"), None).unwrap();
commit_batch(&mut jdb, 0, &keccak(b"0"), None).unwrap();
assert!(jdb.can_reconstruct_refs());
let foo = jdb.insert(EMPTY_PREFIX, b"foo");
jdb.commit_batch(1, &keccak(b"1"), None).unwrap();
commit_batch(&mut jdb, 1, &keccak(b"1"), None).unwrap();
assert!(jdb.can_reconstruct_refs());
jdb.remove(&foo, EMPTY_PREFIX);
jdb.commit_batch(2, &keccak(b"2a"), Some((0, keccak(b"0")))).unwrap();
commit_batch(&mut jdb, 2, &keccak(b"2a"), Some((0, keccak(b"0")))).unwrap();
assert!(jdb.can_reconstruct_refs());
jdb.remove(&foo, EMPTY_PREFIX);
jdb.commit_batch(2, &keccak(b"2b"), Some((0, keccak(b"0")))).unwrap();
commit_batch(&mut jdb, 2, &keccak(b"2b"), Some((0, keccak(b"0")))).unwrap();
assert!(jdb.can_reconstruct_refs());
jdb.insert(EMPTY_PREFIX, b"foo");
jdb.commit_batch(3, &keccak(b"3a"), Some((1, keccak(b"1")))).unwrap();
commit_batch(&mut jdb, 3, &keccak(b"3a"), Some((1, keccak(b"1")))).unwrap();
assert!(jdb.can_reconstruct_refs());
jdb.insert(EMPTY_PREFIX, b"foo");
jdb.commit_batch(3, &keccak(b"3b"), Some((1, keccak(b"1")))).unwrap();
commit_batch(&mut jdb, 3, &keccak(b"3b"), Some((1, keccak(b"1")))).unwrap();
assert!(jdb.can_reconstruct_refs());
jdb.commit_batch(4, &keccak(b"4a"), Some((2, keccak(b"2a")))).unwrap();
commit_batch(&mut jdb, 4, &keccak(b"4a"), Some((2, keccak(b"2a")))).unwrap();
assert!(jdb.can_reconstruct_refs());
jdb.commit_batch(5, &keccak(b"5a"), Some((3, keccak(b"3a")))).unwrap();
commit_batch(&mut jdb, 5, &keccak(b"5a"), Some((3, keccak(b"3a")))).unwrap();
assert!(jdb.can_reconstruct_refs());
}
@ -800,7 +802,7 @@ mod tests {
// history is 1
let foo = jdb.insert(EMPTY_PREFIX, b"foo");
jdb.emplace(bar.clone(), EMPTY_PREFIX, DBValue::from_slice(b"bar"));
jdb.commit_batch(0, &keccak(b"0"), None).unwrap();
commit_batch(&mut jdb, 0, &keccak(b"0"), None).unwrap();
assert!(jdb.can_reconstruct_refs());
foo
};
@ -808,7 +810,7 @@ mod tests {
{
let mut jdb = EarlyMergeDB::new(shared_db.clone(), None);
jdb.remove(&foo, EMPTY_PREFIX);
jdb.commit_batch(1, &keccak(b"1"), Some((0, keccak(b"0")))).unwrap();
commit_batch(&mut jdb, 1, &keccak(b"1"), Some((0, keccak(b"0")))).unwrap();
assert!(jdb.can_reconstruct_refs());
}
@ -816,7 +818,7 @@ mod tests {
let mut jdb = EarlyMergeDB::new(shared_db, None);
assert!(jdb.contains(&foo, EMPTY_PREFIX));
assert!(jdb.contains(&bar, EMPTY_PREFIX));
jdb.commit_batch(2, &keccak(b"2"), Some((1, keccak(b"1")))).unwrap();
commit_batch(&mut jdb, 2, &keccak(b"2"), Some((1, keccak(b"1")))).unwrap();
assert!(jdb.can_reconstruct_refs());
assert!(!jdb.contains(&foo, EMPTY_PREFIX));
}
@ -830,22 +832,22 @@ mod tests {
// history is 4
let foo = jdb.insert(EMPTY_PREFIX, b"foo");
jdb.commit_batch(0, &keccak(b"0"), None).unwrap();
commit_batch(&mut jdb, 0, &keccak(b"0"), None).unwrap();
assert!(jdb.can_reconstruct_refs());
jdb.remove(&foo, EMPTY_PREFIX);
jdb.commit_batch(1, &keccak(b"1"), None).unwrap();
commit_batch(&mut jdb, 1, &keccak(b"1"), None).unwrap();
assert!(jdb.can_reconstruct_refs());
jdb.insert(EMPTY_PREFIX, b"foo");
jdb.commit_batch(2, &keccak(b"2"), None).unwrap();
commit_batch(&mut jdb, 2, &keccak(b"2"), None).unwrap();
assert!(jdb.can_reconstruct_refs());
jdb.remove(&foo, EMPTY_PREFIX);
jdb.commit_batch(3, &keccak(b"3"), None).unwrap();
commit_batch(&mut jdb, 3, &keccak(b"3"), None).unwrap();
assert!(jdb.can_reconstruct_refs());
jdb.insert(EMPTY_PREFIX, b"foo");
jdb.commit_batch(4, &keccak(b"4"), Some((0, keccak(b"0")))).unwrap();
commit_batch(&mut jdb, 4, &keccak(b"4"), Some((0, keccak(b"0")))).unwrap();
assert!(jdb.can_reconstruct_refs());
// expunge foo
jdb.commit_batch(5, &keccak(b"5"), Some((1, keccak(b"1")))).unwrap();
commit_batch(&mut jdb, 5, &keccak(b"5"), Some((1, keccak(b"1")))).unwrap();
assert!(jdb.can_reconstruct_refs());
}
@ -856,43 +858,43 @@ mod tests {
// history is 4
let foo = jdb.insert(EMPTY_PREFIX, b"foo");
jdb.commit_batch(0, &keccak(b"0"), None).unwrap();
commit_batch(&mut jdb, 0, &keccak(b"0"), None).unwrap();
assert!(jdb.can_reconstruct_refs());
jdb.remove(&foo, EMPTY_PREFIX);
jdb.commit_batch(1, &keccak(b"1a"), None).unwrap();
commit_batch(&mut jdb, 1, &keccak(b"1a"), None).unwrap();
assert!(jdb.can_reconstruct_refs());
jdb.remove(&foo, EMPTY_PREFIX);
jdb.commit_batch(1, &keccak(b"1b"), None).unwrap();
commit_batch(&mut jdb, 1, &keccak(b"1b"), None).unwrap();
assert!(jdb.can_reconstruct_refs());
jdb.insert(EMPTY_PREFIX, b"foo");
jdb.commit_batch(2, &keccak(b"2a"), None).unwrap();
commit_batch(&mut jdb, 2, &keccak(b"2a"), None).unwrap();
assert!(jdb.can_reconstruct_refs());
jdb.insert(EMPTY_PREFIX, b"foo");
jdb.commit_batch(2, &keccak(b"2b"), None).unwrap();
commit_batch(&mut jdb, 2, &keccak(b"2b"), None).unwrap();
assert!(jdb.can_reconstruct_refs());
jdb.remove(&foo, EMPTY_PREFIX);
jdb.commit_batch(3, &keccak(b"3a"), None).unwrap();
commit_batch(&mut jdb, 3, &keccak(b"3a"), None).unwrap();
assert!(jdb.can_reconstruct_refs());
jdb.remove(&foo, EMPTY_PREFIX);
jdb.commit_batch(3, &keccak(b"3b"), None).unwrap();
commit_batch(&mut jdb, 3, &keccak(b"3b"), None).unwrap();
assert!(jdb.can_reconstruct_refs());
jdb.insert(EMPTY_PREFIX, b"foo");
jdb.commit_batch(4, &keccak(b"4a"), Some((0, keccak(b"0")))).unwrap();
commit_batch(&mut jdb, 4, &keccak(b"4a"), Some((0, keccak(b"0")))).unwrap();
assert!(jdb.can_reconstruct_refs());
jdb.insert(EMPTY_PREFIX, b"foo");
jdb.commit_batch(4, &keccak(b"4b"), Some((0, keccak(b"0")))).unwrap();
commit_batch(&mut jdb, 4, &keccak(b"4b"), Some((0, keccak(b"0")))).unwrap();
assert!(jdb.can_reconstruct_refs());
// expunge foo
jdb.commit_batch(5, &keccak(b"5"), Some((1, keccak(b"1a")))).unwrap();
commit_batch(&mut jdb, 5, &keccak(b"5"), Some((1, keccak(b"1a")))).unwrap();
assert!(jdb.can_reconstruct_refs());
}
@ -902,25 +904,25 @@ mod tests {
// history is 1
let foo = jdb.insert(EMPTY_PREFIX, b"foo");
jdb.commit_batch(1, &keccak(b"1"), Some((0, keccak(b"0")))).unwrap();
commit_batch(&mut jdb, 1, &keccak(b"1"), Some((0, keccak(b"0")))).unwrap();
assert!(jdb.can_reconstruct_refs());
// foo is ancient history.
jdb.remove(&foo, EMPTY_PREFIX);
jdb.commit_batch(2, &keccak(b"2"), Some((1, keccak(b"1")))).unwrap();
commit_batch(&mut jdb, 2, &keccak(b"2"), Some((1, keccak(b"1")))).unwrap();
assert!(jdb.can_reconstruct_refs());
jdb.insert(EMPTY_PREFIX, b"foo");
jdb.commit_batch(3, &keccak(b"3"), Some((2, keccak(b"2")))).unwrap(); // BROKEN
commit_batch(&mut jdb, 3, &keccak(b"3"), Some((2, keccak(b"2")))).unwrap(); // BROKEN
assert!(jdb.can_reconstruct_refs());
assert!(jdb.contains(&foo, EMPTY_PREFIX));
jdb.remove(&foo, EMPTY_PREFIX);
jdb.commit_batch(4, &keccak(b"4"), Some((3, keccak(b"3")))).unwrap();
commit_batch(&mut jdb, 4, &keccak(b"4"), Some((3, keccak(b"3")))).unwrap();
assert!(jdb.can_reconstruct_refs());
jdb.commit_batch(5, &keccak(b"5"), Some((4, keccak(b"4")))).unwrap();
commit_batch(&mut jdb, 5, &keccak(b"5"), Some((4, keccak(b"4")))).unwrap();
assert!(jdb.can_reconstruct_refs());
assert!(!jdb.contains(&foo, EMPTY_PREFIX));
}
@ -931,30 +933,30 @@ mod tests {
// history is 4
let foo = jdb.insert(EMPTY_PREFIX, b"foo");
jdb.commit_batch(0, &keccak(b"0"), None).unwrap();
commit_batch(&mut jdb, 0, &keccak(b"0"), None).unwrap();
assert!(jdb.can_reconstruct_refs());
jdb.commit_batch(1, &keccak(b"1"), None).unwrap();
commit_batch(&mut jdb, 1, &keccak(b"1"), None).unwrap();
assert!(jdb.can_reconstruct_refs());
jdb.commit_batch(2, &keccak(b"2"), None).unwrap();
commit_batch(&mut jdb, 2, &keccak(b"2"), None).unwrap();
assert!(jdb.can_reconstruct_refs());
jdb.commit_batch(3, &keccak(b"3"), None).unwrap();
commit_batch(&mut jdb, 3, &keccak(b"3"), None).unwrap();
assert!(jdb.can_reconstruct_refs());
jdb.commit_batch(4, &keccak(b"4"), Some((0, keccak(b"0")))).unwrap();
commit_batch(&mut jdb, 4, &keccak(b"4"), Some((0, keccak(b"0")))).unwrap();
assert!(jdb.can_reconstruct_refs());
// foo is ancient history.
jdb.insert(EMPTY_PREFIX, b"foo");
let bar = jdb.insert(EMPTY_PREFIX, b"bar");
jdb.commit_batch(5, &keccak(b"5"), Some((1, keccak(b"1")))).unwrap();
commit_batch(&mut jdb, 5, &keccak(b"5"), Some((1, keccak(b"1")))).unwrap();
assert!(jdb.can_reconstruct_refs());
jdb.remove(&foo, EMPTY_PREFIX);
jdb.remove(&bar, EMPTY_PREFIX);
jdb.commit_batch(6, &keccak(b"6"), Some((2, keccak(b"2")))).unwrap();
commit_batch(&mut jdb, 6, &keccak(b"6"), Some((2, keccak(b"2")))).unwrap();
assert!(jdb.can_reconstruct_refs());
jdb.insert(EMPTY_PREFIX, b"foo");
jdb.insert(EMPTY_PREFIX, b"bar");
jdb.commit_batch(7, &keccak(b"7"), Some((3, keccak(b"3")))).unwrap();
commit_batch(&mut jdb, 7, &keccak(b"7"), Some((3, keccak(b"3")))).unwrap();
assert!(jdb.can_reconstruct_refs());
}
@ -969,20 +971,20 @@ mod tests {
let mut jdb = EarlyMergeDB::new(shared_db.clone(), None);
// history is 1
jdb.insert(EMPTY_PREFIX, b"foo");
jdb.commit_batch(0, &keccak(b"0"), None).unwrap();
commit_batch(&mut jdb, 0, &keccak(b"0"), None).unwrap();
assert!(jdb.can_reconstruct_refs());
jdb.commit_batch(1, &keccak(b"1"), None).unwrap();
commit_batch(&mut jdb, 1, &keccak(b"1"), None).unwrap();
assert!(jdb.can_reconstruct_refs());
// foo is ancient history.
jdb.remove(&foo, EMPTY_PREFIX);
jdb.commit_batch(2, &keccak(b"2"), Some((0, keccak(b"0")))).unwrap();
commit_batch(&mut jdb, 2, &keccak(b"2"), Some((0, keccak(b"0")))).unwrap();
assert!(jdb.can_reconstruct_refs());
assert!(jdb.contains(&foo, EMPTY_PREFIX));
jdb.insert(EMPTY_PREFIX, b"foo");
jdb.commit_batch(3, &keccak(b"3"), Some((1, keccak(b"1")))).unwrap();
commit_batch(&mut jdb, 3, &keccak(b"3"), Some((1, keccak(b"1")))).unwrap();
assert!(jdb.can_reconstruct_refs());
assert!(jdb.contains(&foo, EMPTY_PREFIX));
@ -991,7 +993,7 @@ mod tests {
let mut jdb = EarlyMergeDB::new(shared_db.clone(), None);
jdb.remove(&foo, EMPTY_PREFIX);
jdb.commit_batch(4, &keccak(b"4"), Some((2, keccak(b"2")))).unwrap();
commit_batch(&mut jdb, 4, &keccak(b"4"), Some((2, keccak(b"2")))).unwrap();
assert!(jdb.can_reconstruct_refs());
assert!(jdb.contains(&foo, EMPTY_PREFIX));
@ -999,7 +1001,7 @@ mod tests {
}; {
let mut jdb = EarlyMergeDB::new(shared_db.clone(), None);
jdb.commit_batch(5, &keccak(b"5"), Some((3, keccak(b"3")))).unwrap();
commit_batch(&mut jdb, 5, &keccak(b"5"), Some((3, keccak(b"3")))).unwrap();
assert!(jdb.can_reconstruct_refs());
assert!(jdb.contains(&foo, EMPTY_PREFIX));
@ -1007,7 +1009,7 @@ mod tests {
}; {
let mut jdb = EarlyMergeDB::new(shared_db, None);
jdb.commit_batch(6, &keccak(b"6"), Some((4, keccak(b"4")))).unwrap();
commit_batch(&mut jdb, 6, &keccak(b"6"), Some((4, keccak(b"4")))).unwrap();
assert!(jdb.can_reconstruct_refs());
assert!(!jdb.contains(&foo, EMPTY_PREFIX));
}
@ -1022,22 +1024,22 @@ mod tests {
// history is 1
let foo = jdb.insert(EMPTY_PREFIX, b"foo");
let bar = jdb.insert(EMPTY_PREFIX, b"bar");
jdb.commit_batch(0, &keccak(b"0"), None).unwrap();
commit_batch(&mut jdb, 0, &keccak(b"0"), None).unwrap();
assert!(jdb.can_reconstruct_refs());
jdb.remove(&foo, EMPTY_PREFIX);
let baz = jdb.insert(EMPTY_PREFIX, b"baz");
jdb.commit_batch(1, &keccak(b"1a"), Some((0, keccak(b"0")))).unwrap();
commit_batch(&mut jdb, 1, &keccak(b"1a"), Some((0, keccak(b"0")))).unwrap();
assert!(jdb.can_reconstruct_refs());
jdb.remove(&bar, EMPTY_PREFIX);
jdb.commit_batch(1, &keccak(b"1b"), Some((0, keccak(b"0")))).unwrap();
commit_batch(&mut jdb, 1, &keccak(b"1b"), Some((0, keccak(b"0")))).unwrap();
assert!(jdb.can_reconstruct_refs());
(foo, bar, baz)
};
{
let mut jdb = EarlyMergeDB::new(shared_db, None);
jdb.commit_batch(2, &keccak(b"2b"), Some((1, keccak(b"1b")))).unwrap();
commit_batch(&mut jdb, 2, &keccak(b"2b"), Some((1, keccak(b"1b")))).unwrap();
assert!(jdb.can_reconstruct_refs());
assert!(jdb.contains(&foo, EMPTY_PREFIX));
assert!(!jdb.contains(&baz, EMPTY_PREFIX));
@ -1049,11 +1051,11 @@ mod tests {
fn inject() {
let mut jdb = new_db();
let key = jdb.insert(EMPTY_PREFIX, b"dog");
jdb.inject_batch().unwrap();
inject_batch(&mut jdb).unwrap();
assert_eq!(jdb.get(&key, EMPTY_PREFIX).unwrap(), DBValue::from_slice(b"dog"));
jdb.remove(&key, EMPTY_PREFIX);
jdb.inject_batch().unwrap();
inject_batch(&mut jdb).unwrap();
assert!(jdb.get(&key, EMPTY_PREFIX).is_none());
}

View File

@ -16,51 +16,84 @@
//! `JournalDB` interface and implementation.
extern crate parity_util_mem;
extern crate parity_util_mem as mem;
extern crate parity_util_mem as malloc_size_of;
#[macro_use]
extern crate log;
use std::{
fmt, str, io,
sync::Arc,
collections::HashMap,
};
extern crate ethereum_types;
extern crate parity_bytes as bytes;
extern crate hash_db;
extern crate keccak_hasher;
extern crate kvdb;
extern crate memory_db;
extern crate parking_lot;
extern crate fastmap;
extern crate rlp;
use ethereum_types::H256;
use hash_db::HashDB;
use keccak_hasher::KeccakHasher;
use kvdb::{self, DBTransaction, DBValue};
use parity_bytes::Bytes;
#[cfg(test)]
extern crate env_logger;
#[cfg(test)]
extern crate keccak_hash as keccak;
#[cfg(test)]
extern crate kvdb_memorydb;
use std::{fmt, str, io};
use std::sync::Arc;
/// Export the journaldb module.
mod traits;
mod archivedb;
mod earlymergedb;
mod overlayrecentdb;
mod refcounteddb;
mod util;
mod as_hash_db_impls;
mod overlaydb;
pub mod overlaydb;
/// A `HashDB` which can manage a short-term journal potentially containing many forks of mutually
/// exclusive actions.
pub trait JournalDB: HashDB<KeccakHasher, DBValue> {
/// Return a copy of ourself, in a box.
fn boxed_clone(&self) -> Box<dyn JournalDB>;
/// Export the `JournalDB` trait.
pub use self::traits::JournalDB;
/// Returns heap memory size used
fn mem_used(&self) -> usize;
/// Export keyed hash trait
pub use self::traits::KeyedHashDB;
/// Export as keyed hash trait
pub use self::traits::AsKeyedHashDB;
/// Returns the size of journalled state in memory.
/// This function has a considerable speed requirement --
/// it must be fast enough to call several times per block imported.
fn journal_size(&self) -> usize { 0 }
/// Check if this database has any commits
fn is_empty(&self) -> bool;
/// Get the earliest era in the DB. None if there isn't yet any data in there.
fn earliest_era(&self) -> Option<u64> { None }
/// Get the latest era in the DB. None if there isn't yet any data in there.
fn latest_era(&self) -> Option<u64>;
/// Journal recent database operations as being associated with a given era and id.
// TODO: give the overlay to this function so journaldbs don't manage the overlays themselves.
fn journal_under(&mut self, batch: &mut DBTransaction, now: u64, id: &H256) -> io::Result<u32>;
/// Mark a given block as canonical, indicating that competing blocks' states may be pruned out.
fn mark_canonical(&mut self, batch: &mut DBTransaction, era: u64, id: &H256) -> io::Result<u32>;
/// Commit all queued insert and delete operations without affecting any journalling -- this requires that all insertions
/// and deletions are indeed canonical and will likely lead to an invalid database if that assumption is violated.
///
/// Any keys or values inserted or deleted must be completely independent of those affected
/// by any previous `commit` operations. Essentially, this means that `inject` can be used
/// either to restore a state to a fresh database, or to insert data which may only be journalled
/// from this point onwards.
fn inject(&mut self, batch: &mut DBTransaction) -> io::Result<u32>;
/// State data query
fn state(&self, _id: &H256) -> Option<Bytes>;
/// Whether this database is pruned.
fn is_prunable(&self) -> bool { true }
/// Get backing database.
fn backing(&self) -> &Arc<dyn kvdb::KeyValueDB>;
/// Clear internal strucutres. This should called after changes have been written
/// to the backing strage
fn flush(&self) {}
/// Consolidate all the insertions and deletions in the given memory overlay.
fn consolidate(&mut self, overlay: MemoryDB);
/// Primarily use for tests, highly inefficient.
fn keys(&self) -> HashMap<H256, i32>;
}
/// Alias to ethereum MemoryDB
type MemoryDB = memory_db::MemoryDB<
@ -177,6 +210,29 @@ pub fn new_memory_db() -> MemoryDB {
MemoryDB::from_null_node(&rlp::NULL_RLP, rlp::NULL_RLP.as_ref().into())
}
#[cfg(test)]
/// Inject all changes in a single batch.
pub fn inject_batch(jdb: &mut dyn JournalDB) -> io::Result<u32> {
let mut batch = jdb.backing().transaction();
let res = jdb.inject(&mut batch)?;
jdb.backing().write(batch).map(|_| res).map_err(Into::into)
}
/// Commit all changes in a single batch
#[cfg(test)]
fn commit_batch(jdb: &mut dyn JournalDB, now: u64, id: &H256, end: Option<(u64, H256)>) -> io::Result<u32> {
let mut batch = jdb.backing().transaction();
let mut ops = jdb.journal_under(&mut batch, now, id)?;
if let Some((end_era, canon_id)) = end {
ops += jdb.mark_canonical(&mut batch, end_era, &canon_id)?;
}
let result = jdb.backing().write(batch).map(|_| ops).map_err(Into::into);
jdb.flush();
result
}
#[cfg(test)]
mod tests {
use super::Algorithm;

View File

@ -16,17 +16,20 @@
//! Disk-backed `HashDB` implementation.
use std::collections::HashMap;
use std::collections::hash_map::Entry;
use std::io;
use std::sync::Arc;
use std::{
collections::{HashMap, hash_map::Entry},
io,
sync::Arc,
};
use ethereum_types::H256;
use rlp::{Rlp, RlpStream, Encodable, DecoderError, Decodable, encode, decode};
use hash_db::{HashDB, Prefix, EMPTY_PREFIX};
use hash_db::{HashDB, Prefix};
use keccak_hasher::KeccakHasher;
use kvdb::{KeyValueDB, DBTransaction, DBValue};
use super::{error_negatively_reference_hash};
use log::trace;
use rlp::{Rlp, RlpStream, Encodable, DecoderError, Decodable, encode, decode};
use crate::{error_negatively_reference_hash, new_memory_db};
/// Implementation of the `HashDB` trait for a disk-backed database with a memory overlay.
///
@ -78,8 +81,12 @@ impl Decodable for Payload {
impl OverlayDB {
/// Create a new instance of OverlayDB given a `backing` database.
pub fn new(backing: Arc<dyn KeyValueDB>, col: Option<u32>) -> OverlayDB {
OverlayDB{ overlay: ::new_memory_db(), backing: backing, column: col }
pub fn new(backing: Arc<dyn KeyValueDB>, column: Option<u32>) -> OverlayDB {
OverlayDB {
overlay: new_memory_db(),
backing,
column,
}
}
/// Create a new instance of OverlayDB with an anonymous temporary database.
@ -128,13 +135,6 @@ impl OverlayDB {
Ok(ret)
}
/// Revert all operations on this object (i.e. `insert()`s and `remove()`s) since the
/// last `commit()`.
pub fn revert(&mut self) { self.overlay.clear(); }
/// Get the number of references that would be committed.
pub fn commit_refs(&self, key: &H256) -> i32 { self.overlay.raw(key, EMPTY_PREFIX).map_or(0, |(_, refs)| refs) }
/// Get the refs and value of the given key.
fn payload(&self, key: &H256) -> Option<Payload> {
self.backing.get(self.column, key.as_bytes())
@ -153,10 +153,7 @@ impl OverlayDB {
}
}
}
impl crate::KeyedHashDB for OverlayDB {
fn keys(&self) -> HashMap<H256, i32> {
pub fn keys(&self) -> HashMap<H256, i32> {
let mut ret: HashMap<H256, i32> = self.backing.iter(self.column)
.map(|(key, _)| {
let h = H256::from_slice(&*key);
@ -177,7 +174,6 @@ impl crate::KeyedHashDB for OverlayDB {
}
ret
}
}
impl HashDB<KeccakHasher, DBValue> for OverlayDB {
@ -233,6 +229,11 @@ impl HashDB<KeccakHasher, DBValue> for OverlayDB {
fn remove(&mut self, key: &H256, prefix: Prefix) { self.overlay.remove(key, prefix); }
}
#[cfg(test)]
mod tests {
use hash_db::EMPTY_PREFIX;
use super::*;
#[test]
fn overlaydb_revert() {
let mut m = OverlayDB::new_temp();
@ -244,9 +245,6 @@ fn overlaydb_revert() {
m.remove(&foo, EMPTY_PREFIX); // remove foo.
assert!(!m.contains(&foo, EMPTY_PREFIX)); // foo is gone.
assert!(m.contains(&bar, EMPTY_PREFIX)); // bar is here.
m.revert(); // revert the last two operations.
assert!(m.contains(&foo, EMPTY_PREFIX)); // foo is here.
assert!(!m.contains(&bar, EMPTY_PREFIX)); // bar is gone.
}
#[test]
@ -265,8 +263,6 @@ fn overlaydb_backing_insert_revert() {
assert_eq!(trie.get(&h, EMPTY_PREFIX).unwrap(), DBValue::from_slice(b"hello world"));
trie.commit().unwrap();
assert_eq!(trie.get(&h, EMPTY_PREFIX).unwrap(), DBValue::from_slice(b"hello world"));
trie.revert();
assert_eq!(trie.get(&h, EMPTY_PREFIX).unwrap(), DBValue::from_slice(b"hello world"));
}
#[test]
@ -278,8 +274,6 @@ fn overlaydb_backing_remove() {
assert_eq!(trie.get(&h, EMPTY_PREFIX), None);
trie.commit().unwrap();
assert_eq!(trie.get(&h, EMPTY_PREFIX), None);
trie.revert();
assert_eq!(trie.get(&h, EMPTY_PREFIX), None);
}
#[test]
@ -289,8 +283,6 @@ fn overlaydb_backing_remove_revert() {
trie.commit().unwrap();
trie.remove(&h, EMPTY_PREFIX);
assert_eq!(trie.get(&h, EMPTY_PREFIX), None);
trie.revert();
assert_eq!(trie.get(&h, EMPTY_PREFIX).unwrap(), DBValue::from_slice(b"hello world"));
}
#[test]
@ -336,3 +328,4 @@ fn overlaydb_complex() {
trie.commit().unwrap(); //
assert_eq!(trie.get(&hfoo, EMPTY_PREFIX), None);
}
}

View File

@ -16,22 +16,28 @@
//! `JournalDB` over in-memory overlay
use std::collections::HashMap;
use std::collections::hash_map::Entry;
use std::io;
use std::sync::Arc;
use std::{
collections::{HashMap, hash_map::Entry},
io,
sync::Arc,
};
use bytes::Bytes;
use ethereum_types::H256;
use fastmap::H256FastMap;
use hash_db::{HashDB, Prefix, EMPTY_PREFIX};
use parity_util_mem::{MallocSizeOf, allocators::new_malloc_size_ops};
use keccak_hasher::KeccakHasher;
use kvdb::{KeyValueDB, DBTransaction, DBValue};
use log::trace;
use malloc_size_of::{MallocSizeOf, allocators::new_malloc_size_ops};
use parity_bytes::Bytes;
use parking_lot::RwLock;
use fastmap::H256FastMap;
use rlp::{Rlp, RlpStream, encode, decode, DecoderError, Decodable, Encodable};
use super::{DB_PREFIX_LEN, LATEST_ERA_KEY, JournalDB, error_negatively_reference_hash};
use util::DatabaseKey;
use crate::{
DB_PREFIX_LEN, LATEST_ERA_KEY, JournalDB, error_negatively_reference_hash,
new_memory_db,
util::DatabaseKey
};
/// Implementation of the `JournalDB` trait for a disk-backed database with a memory overlay
/// and, possibly, latent-removal semantics.
@ -150,7 +156,7 @@ impl OverlayRecentDB {
pub fn new(backing: Arc<dyn KeyValueDB>, col: Option<u32>) -> OverlayRecentDB {
let journal_overlay = Arc::new(RwLock::new(OverlayRecentDB::read_overlay(&*backing, col)));
OverlayRecentDB {
transaction_overlay: ::new_memory_db(),
transaction_overlay: new_memory_db(),
backing: backing,
journal_overlay: journal_overlay,
column: col,
@ -176,7 +182,7 @@ impl OverlayRecentDB {
fn read_overlay(db: &dyn KeyValueDB, col: Option<u32>) -> JournalOverlay {
let mut journal = HashMap::new();
let mut overlay = ::new_memory_db();
let mut overlay = new_memory_db();
let mut count = 0;
let mut latest_era = None;
let mut earliest_era = None;
@ -238,26 +244,6 @@ fn to_short_key(key: &H256) -> H256 {
k
}
impl ::traits::KeyedHashDB for OverlayRecentDB {
fn keys(&self) -> HashMap<H256, i32> {
let mut ret: HashMap<H256, i32> = self.backing.iter(self.column)
.map(|(key, _)| (H256::from_slice(&*key), 1))
.collect();
for (key, refs) in self.transaction_overlay.keys() {
match ret.entry(key) {
Entry::Occupied(mut entry) => {
*entry.get_mut() += refs;
},
Entry::Vacant(entry) => {
entry.insert(refs);
}
}
}
ret
}
}
impl JournalDB for OverlayRecentDB {
fn boxed_clone(&self) -> Box<dyn JournalDB> {
@ -455,6 +441,24 @@ impl JournalDB for OverlayRecentDB {
fn consolidate(&mut self, with: super::MemoryDB) {
self.transaction_overlay.consolidate(with);
}
fn keys(&self) -> HashMap<H256, i32> {
let mut ret: HashMap<H256, i32> = self.backing.iter(self.column)
.map(|(key, _)| (H256::from_slice(&*key), 1))
.collect();
for (key, refs) in self.transaction_overlay.keys() {
match ret.entry(key) {
Entry::Occupied(mut entry) => {
*entry.get_mut() += refs;
},
Entry::Vacant(entry) => {
entry.insert(refs);
}
}
}
ret
}
}
impl HashDB<KeccakHasher, DBValue> for OverlayRecentDB {
@ -490,11 +494,11 @@ impl HashDB<KeccakHasher, DBValue> for OverlayRecentDB {
#[cfg(test)]
mod tests {
use keccak::keccak;
use keccak_hash::keccak;
use super::*;
use hash_db::{HashDB, EMPTY_PREFIX};
use {kvdb_memorydb, JournalDB};
use kvdb_memorydb;
use crate::{JournalDB, inject_batch, commit_batch};
fn new_db() -> OverlayRecentDB {
let backing = Arc::new(kvdb_memorydb::create(0));
@ -507,25 +511,25 @@ mod tests {
let mut jdb = new_db();
let x = jdb.insert(EMPTY_PREFIX, b"X");
jdb.commit_batch(1, &keccak(b"1"), None).unwrap();
commit_batch(&mut jdb, 1, &keccak(b"1"), None).unwrap();
assert!(jdb.can_reconstruct_refs());
jdb.commit_batch(2, &keccak(b"2"), None).unwrap();
commit_batch(&mut jdb, 2, &keccak(b"2"), None).unwrap();
assert!(jdb.can_reconstruct_refs());
jdb.commit_batch(3, &keccak(b"1002a"), Some((1, keccak(b"1")))).unwrap();
commit_batch(&mut jdb, 3, &keccak(b"1002a"), Some((1, keccak(b"1")))).unwrap();
assert!(jdb.can_reconstruct_refs());
jdb.commit_batch(4, &keccak(b"1003a"), Some((2, keccak(b"2")))).unwrap();
commit_batch(&mut jdb, 4, &keccak(b"1003a"), Some((2, keccak(b"2")))).unwrap();
assert!(jdb.can_reconstruct_refs());
jdb.remove(&x, EMPTY_PREFIX);
jdb.commit_batch(3, &keccak(b"1002b"), Some((1, keccak(b"1")))).unwrap();
commit_batch(&mut jdb, 3, &keccak(b"1002b"), Some((1, keccak(b"1")))).unwrap();
assert!(jdb.can_reconstruct_refs());
let x = jdb.insert(EMPTY_PREFIX, b"X");
jdb.commit_batch(4, &keccak(b"1003b"), Some((2, keccak(b"2")))).unwrap();
commit_batch(&mut jdb, 4, &keccak(b"1003b"), Some((2, keccak(b"2")))).unwrap();
assert!(jdb.can_reconstruct_refs());
jdb.commit_batch(5, &keccak(b"1004a"), Some((3, keccak(b"1002a")))).unwrap();
commit_batch(&mut jdb, 5, &keccak(b"1004a"), Some((3, keccak(b"1002a")))).unwrap();
assert!(jdb.can_reconstruct_refs());
jdb.commit_batch(6, &keccak(b"1005a"), Some((4, keccak(b"1003a")))).unwrap();
commit_batch(&mut jdb, 6, &keccak(b"1005a"), Some((4, keccak(b"1003a")))).unwrap();
assert!(jdb.can_reconstruct_refs());
assert!(jdb.contains(&x, EMPTY_PREFIX));
@ -536,20 +540,20 @@ mod tests {
// history is 3
let mut jdb = new_db();
let h = jdb.insert(EMPTY_PREFIX, b"foo");
jdb.commit_batch(0, &keccak(b"0"), None).unwrap();
commit_batch(&mut jdb, 0, &keccak(b"0"), None).unwrap();
assert!(jdb.can_reconstruct_refs());
assert!(jdb.contains(&h, EMPTY_PREFIX));
jdb.remove(&h, EMPTY_PREFIX);
jdb.commit_batch(1, &keccak(b"1"), None).unwrap();
commit_batch(&mut jdb, 1, &keccak(b"1"), None).unwrap();
assert!(jdb.can_reconstruct_refs());
assert!(jdb.contains(&h, EMPTY_PREFIX));
jdb.commit_batch(2, &keccak(b"2"), None).unwrap();
commit_batch(&mut jdb, 2, &keccak(b"2"), None).unwrap();
assert!(jdb.can_reconstruct_refs());
assert!(jdb.contains(&h, EMPTY_PREFIX));
jdb.commit_batch(3, &keccak(b"3"), Some((0, keccak(b"0")))).unwrap();
commit_batch(&mut jdb, 3, &keccak(b"3"), Some((0, keccak(b"0")))).unwrap();
assert!(jdb.can_reconstruct_refs());
assert!(jdb.contains(&h, EMPTY_PREFIX));
jdb.commit_batch(4, &keccak(b"4"), Some((1, keccak(b"1")))).unwrap();
commit_batch(&mut jdb, 4, &keccak(b"4"), Some((1, keccak(b"1")))).unwrap();
assert!(jdb.can_reconstruct_refs());
assert!(!jdb.contains(&h, EMPTY_PREFIX));
}
@ -561,7 +565,7 @@ mod tests {
let foo = jdb.insert(EMPTY_PREFIX, b"foo");
let bar = jdb.insert(EMPTY_PREFIX, b"bar");
jdb.commit_batch(0, &keccak(b"0"), None).unwrap();
commit_batch(&mut jdb, 0, &keccak(b"0"), None).unwrap();
assert!(jdb.can_reconstruct_refs());
assert!(jdb.contains(&foo, EMPTY_PREFIX));
assert!(jdb.contains(&bar, EMPTY_PREFIX));
@ -569,7 +573,7 @@ mod tests {
jdb.remove(&foo, EMPTY_PREFIX);
jdb.remove(&bar, EMPTY_PREFIX);
let baz = jdb.insert(EMPTY_PREFIX, b"baz");
jdb.commit_batch(1, &keccak(b"1"), Some((0, keccak(b"0")))).unwrap();
commit_batch(&mut jdb, 1, &keccak(b"1"), Some((0, keccak(b"0")))).unwrap();
assert!(jdb.can_reconstruct_refs());
assert!(jdb.contains(&foo, EMPTY_PREFIX));
assert!(jdb.contains(&bar, EMPTY_PREFIX));
@ -577,20 +581,20 @@ mod tests {
let foo = jdb.insert(EMPTY_PREFIX, b"foo");
jdb.remove(&baz, EMPTY_PREFIX);
jdb.commit_batch(2, &keccak(b"2"), Some((1, keccak(b"1")))).unwrap();
commit_batch(&mut jdb, 2, &keccak(b"2"), Some((1, keccak(b"1")))).unwrap();
assert!(jdb.can_reconstruct_refs());
assert!(jdb.contains(&foo, EMPTY_PREFIX));
assert!(!jdb.contains(&bar, EMPTY_PREFIX));
assert!(jdb.contains(&baz, EMPTY_PREFIX));
jdb.remove(&foo, EMPTY_PREFIX);
jdb.commit_batch(3, &keccak(b"3"), Some((2, keccak(b"2")))).unwrap();
commit_batch(&mut jdb, 3, &keccak(b"3"), Some((2, keccak(b"2")))).unwrap();
assert!(jdb.can_reconstruct_refs());
assert!(jdb.contains(&foo, EMPTY_PREFIX));
assert!(!jdb.contains(&bar, EMPTY_PREFIX));
assert!(!jdb.contains(&baz, EMPTY_PREFIX));
jdb.commit_batch(4, &keccak(b"4"), Some((3, keccak(b"3")))).unwrap();
commit_batch(&mut jdb, 4, &keccak(b"4"), Some((3, keccak(b"3")))).unwrap();
assert!(jdb.can_reconstruct_refs());
assert!(!jdb.contains(&foo, EMPTY_PREFIX));
assert!(!jdb.contains(&bar, EMPTY_PREFIX));
@ -604,25 +608,25 @@ mod tests {
let foo = jdb.insert(EMPTY_PREFIX, b"foo");
let bar = jdb.insert(EMPTY_PREFIX, b"bar");
jdb.commit_batch(0, &keccak(b"0"), None).unwrap();
commit_batch(&mut jdb, 0, &keccak(b"0"), None).unwrap();
assert!(jdb.can_reconstruct_refs());
assert!(jdb.contains(&foo, EMPTY_PREFIX));
assert!(jdb.contains(&bar, EMPTY_PREFIX));
jdb.remove(&foo, EMPTY_PREFIX);
let baz = jdb.insert(EMPTY_PREFIX, b"baz");
jdb.commit_batch(1, &keccak(b"1a"), Some((0, keccak(b"0")))).unwrap();
commit_batch(&mut jdb, 1, &keccak(b"1a"), Some((0, keccak(b"0")))).unwrap();
assert!(jdb.can_reconstruct_refs());
jdb.remove(&bar, EMPTY_PREFIX);
jdb.commit_batch(1, &keccak(b"1b"), Some((0, keccak(b"0")))).unwrap();
commit_batch(&mut jdb, 1, &keccak(b"1b"), Some((0, keccak(b"0")))).unwrap();
assert!(jdb.can_reconstruct_refs());
assert!(jdb.contains(&foo, EMPTY_PREFIX));
assert!(jdb.contains(&bar, EMPTY_PREFIX));
assert!(jdb.contains(&baz, EMPTY_PREFIX));
jdb.commit_batch(2, &keccak(b"2b"), Some((1, keccak(b"1b")))).unwrap();
commit_batch(&mut jdb, 2, &keccak(b"2b"), Some((1, keccak(b"1b")))).unwrap();
assert!(jdb.can_reconstruct_refs());
assert!(jdb.contains(&foo, EMPTY_PREFIX));
assert!(!jdb.contains(&baz, EMPTY_PREFIX));
@ -635,19 +639,19 @@ mod tests {
let mut jdb = new_db();
let foo = jdb.insert(EMPTY_PREFIX, b"foo");
jdb.commit_batch(0, &keccak(b"0"), None).unwrap();
commit_batch(&mut jdb, 0, &keccak(b"0"), None).unwrap();
assert!(jdb.can_reconstruct_refs());
assert!(jdb.contains(&foo, EMPTY_PREFIX));
jdb.remove(&foo, EMPTY_PREFIX);
jdb.commit_batch(1, &keccak(b"1"), Some((0, keccak(b"0")))).unwrap();
commit_batch(&mut jdb, 1, &keccak(b"1"), Some((0, keccak(b"0")))).unwrap();
assert!(jdb.can_reconstruct_refs());
jdb.insert(EMPTY_PREFIX, b"foo");
assert!(jdb.contains(&foo, EMPTY_PREFIX));
jdb.commit_batch(2, &keccak(b"2"), Some((1, keccak(b"1")))).unwrap();
commit_batch(&mut jdb, 2, &keccak(b"2"), Some((1, keccak(b"1")))).unwrap();
assert!(jdb.can_reconstruct_refs());
assert!(jdb.contains(&foo, EMPTY_PREFIX));
jdb.commit_batch(3, &keccak(b"2"), Some((0, keccak(b"2")))).unwrap();
commit_batch(&mut jdb, 3, &keccak(b"2"), Some((0, keccak(b"2")))).unwrap();
assert!(jdb.can_reconstruct_refs());
assert!(jdb.contains(&foo, EMPTY_PREFIX));
}
@ -655,24 +659,24 @@ mod tests {
#[test]
fn fork_same_key_one() {
let mut jdb = new_db();
jdb.commit_batch(0, &keccak(b"0"), None).unwrap();
commit_batch(&mut jdb, 0, &keccak(b"0"), None).unwrap();
assert!(jdb.can_reconstruct_refs());
let foo = jdb.insert(EMPTY_PREFIX, b"foo");
jdb.commit_batch(1, &keccak(b"1a"), Some((0, keccak(b"0")))).unwrap();
commit_batch(&mut jdb, 1, &keccak(b"1a"), Some((0, keccak(b"0")))).unwrap();
assert!(jdb.can_reconstruct_refs());
jdb.insert(EMPTY_PREFIX, b"foo");
jdb.commit_batch(1, &keccak(b"1b"), Some((0, keccak(b"0")))).unwrap();
commit_batch(&mut jdb, 1, &keccak(b"1b"), Some((0, keccak(b"0")))).unwrap();
assert!(jdb.can_reconstruct_refs());
jdb.insert(EMPTY_PREFIX, b"foo");
jdb.commit_batch(1, &keccak(b"1c"), Some((0, keccak(b"0")))).unwrap();
commit_batch(&mut jdb, 1, &keccak(b"1c"), Some((0, keccak(b"0")))).unwrap();
assert!(jdb.can_reconstruct_refs());
assert!(jdb.contains(&foo, EMPTY_PREFIX));
jdb.commit_batch(2, &keccak(b"2a"), Some((1, keccak(b"1a")))).unwrap();
commit_batch(&mut jdb, 2, &keccak(b"2a"), Some((1, keccak(b"1a")))).unwrap();
assert!(jdb.can_reconstruct_refs());
assert!(jdb.contains(&foo, EMPTY_PREFIX));
}
@ -681,24 +685,24 @@ mod tests {
fn fork_same_key_other() {
let mut jdb = new_db();
jdb.commit_batch(0, &keccak(b"0"), None).unwrap();
commit_batch(&mut jdb, 0, &keccak(b"0"), None).unwrap();
assert!(jdb.can_reconstruct_refs());
let foo = jdb.insert(EMPTY_PREFIX, b"foo");
jdb.commit_batch(1, &keccak(b"1a"), Some((0, keccak(b"0")))).unwrap();
commit_batch(&mut jdb, 1, &keccak(b"1a"), Some((0, keccak(b"0")))).unwrap();
assert!(jdb.can_reconstruct_refs());
jdb.insert(EMPTY_PREFIX, b"foo");
jdb.commit_batch(1, &keccak(b"1b"), Some((0, keccak(b"0")))).unwrap();
commit_batch(&mut jdb, 1, &keccak(b"1b"), Some((0, keccak(b"0")))).unwrap();
assert!(jdb.can_reconstruct_refs());
jdb.insert(EMPTY_PREFIX, b"foo");
jdb.commit_batch(1, &keccak(b"1c"), Some((0, keccak(b"0")))).unwrap();
commit_batch(&mut jdb, 1, &keccak(b"1c"), Some((0, keccak(b"0")))).unwrap();
assert!(jdb.can_reconstruct_refs());
assert!(jdb.contains(&foo, EMPTY_PREFIX));
jdb.commit_batch(2, &keccak(b"2b"), Some((1, keccak(b"1b")))).unwrap();
commit_batch(&mut jdb, 2, &keccak(b"2b"), Some((1, keccak(b"1b")))).unwrap();
assert!(jdb.can_reconstruct_refs());
assert!(jdb.contains(&foo, EMPTY_PREFIX));
}
@ -707,33 +711,33 @@ mod tests {
fn fork_ins_del_ins() {
let mut jdb = new_db();
jdb.commit_batch(0, &keccak(b"0"), None).unwrap();
commit_batch(&mut jdb, 0, &keccak(b"0"), None).unwrap();
assert!(jdb.can_reconstruct_refs());
let foo = jdb.insert(EMPTY_PREFIX, b"foo");
jdb.commit_batch(1, &keccak(b"1"), None).unwrap();
commit_batch(&mut jdb, 1, &keccak(b"1"), None).unwrap();
assert!(jdb.can_reconstruct_refs());
jdb.remove(&foo, EMPTY_PREFIX);
jdb.commit_batch(2, &keccak(b"2a"), Some((0, keccak(b"0")))).unwrap();
commit_batch(&mut jdb, 2, &keccak(b"2a"), Some((0, keccak(b"0")))).unwrap();
assert!(jdb.can_reconstruct_refs());
jdb.remove(&foo, EMPTY_PREFIX);
jdb.commit_batch(2, &keccak(b"2b"), Some((0, keccak(b"0")))).unwrap();
commit_batch(&mut jdb, 2, &keccak(b"2b"), Some((0, keccak(b"0")))).unwrap();
assert!(jdb.can_reconstruct_refs());
jdb.insert(EMPTY_PREFIX, b"foo");
jdb.commit_batch(3, &keccak(b"3a"), Some((1, keccak(b"1")))).unwrap();
commit_batch(&mut jdb, 3, &keccak(b"3a"), Some((1, keccak(b"1")))).unwrap();
assert!(jdb.can_reconstruct_refs());
jdb.insert(EMPTY_PREFIX, b"foo");
jdb.commit_batch(3, &keccak(b"3b"), Some((1, keccak(b"1")))).unwrap();
commit_batch(&mut jdb, 3, &keccak(b"3b"), Some((1, keccak(b"1")))).unwrap();
assert!(jdb.can_reconstruct_refs());
jdb.commit_batch(4, &keccak(b"4a"), Some((2, keccak(b"2a")))).unwrap();
commit_batch(&mut jdb, 4, &keccak(b"4a"), Some((2, keccak(b"2a")))).unwrap();
assert!(jdb.can_reconstruct_refs());
jdb.commit_batch(5, &keccak(b"5a"), Some((3, keccak(b"3a")))).unwrap();
commit_batch(&mut jdb, 5, &keccak(b"5a"), Some((3, keccak(b"3a")))).unwrap();
assert!(jdb.can_reconstruct_refs());
}
@ -747,7 +751,7 @@ mod tests {
// history is 1
let foo = jdb.insert(EMPTY_PREFIX, b"foo");
jdb.emplace(bar.clone(), EMPTY_PREFIX, DBValue::from_slice(b"bar"));
jdb.commit_batch(0, &keccak(b"0"), None).unwrap();
commit_batch(&mut jdb, 0, &keccak(b"0"), None).unwrap();
assert!(jdb.can_reconstruct_refs());
foo
};
@ -755,7 +759,7 @@ mod tests {
{
let mut jdb = OverlayRecentDB::new(shared_db.clone(), None);
jdb.remove(&foo, EMPTY_PREFIX);
jdb.commit_batch(1, &keccak(b"1"), Some((0, keccak(b"0")))).unwrap();
commit_batch(&mut jdb, 1, &keccak(b"1"), Some((0, keccak(b"0")))).unwrap();
assert!(jdb.can_reconstruct_refs());
}
@ -763,7 +767,7 @@ mod tests {
let mut jdb = OverlayRecentDB::new(shared_db.clone(), None);
assert!(jdb.contains(&foo, EMPTY_PREFIX));
assert!(jdb.contains(&bar, EMPTY_PREFIX));
jdb.commit_batch(2, &keccak(b"2"), Some((1, keccak(b"1")))).unwrap();
commit_batch(&mut jdb, 2, &keccak(b"2"), Some((1, keccak(b"1")))).unwrap();
assert!(jdb.can_reconstruct_refs());
assert!(!jdb.contains(&foo, EMPTY_PREFIX));
}
@ -776,22 +780,22 @@ mod tests {
// history is 4
let foo = jdb.insert(EMPTY_PREFIX, b"foo");
jdb.commit_batch(0, &keccak(b"0"), None).unwrap();
commit_batch(&mut jdb, 0, &keccak(b"0"), None).unwrap();
assert!(jdb.can_reconstruct_refs());
jdb.remove(&foo, EMPTY_PREFIX);
jdb.commit_batch(1, &keccak(b"1"), None).unwrap();
commit_batch(&mut jdb, 1, &keccak(b"1"), None).unwrap();
assert!(jdb.can_reconstruct_refs());
jdb.insert(EMPTY_PREFIX, b"foo");
jdb.commit_batch(2, &keccak(b"2"), None).unwrap();
commit_batch(&mut jdb, 2, &keccak(b"2"), None).unwrap();
assert!(jdb.can_reconstruct_refs());
jdb.remove(&foo, EMPTY_PREFIX);
jdb.commit_batch(3, &keccak(b"3"), None).unwrap();
commit_batch(&mut jdb, 3, &keccak(b"3"), None).unwrap();
assert!(jdb.can_reconstruct_refs());
jdb.insert(EMPTY_PREFIX, b"foo");
jdb.commit_batch(4, &keccak(b"4"), Some((0, keccak(b"0")))).unwrap();
commit_batch(&mut jdb, 4, &keccak(b"4"), Some((0, keccak(b"0")))).unwrap();
assert!(jdb.can_reconstruct_refs());
// expunge foo
jdb.commit_batch(5, &keccak(b"5"), Some((1, keccak(b"1")))).unwrap();
commit_batch(&mut jdb, 5, &keccak(b"5"), Some((1, keccak(b"1")))).unwrap();
assert!(jdb.can_reconstruct_refs());
}
@ -802,43 +806,43 @@ mod tests {
// history is 4
let foo = jdb.insert(EMPTY_PREFIX, b"foo");
jdb.commit_batch(0, &keccak(b"0"), None).unwrap();
commit_batch(&mut jdb, 0, &keccak(b"0"), None).unwrap();
assert!(jdb.can_reconstruct_refs());
jdb.remove(&foo, EMPTY_PREFIX);
jdb.commit_batch(1, &keccak(b"1a"), None).unwrap();
commit_batch(&mut jdb, 1, &keccak(b"1a"), None).unwrap();
assert!(jdb.can_reconstruct_refs());
jdb.remove(&foo, EMPTY_PREFIX);
jdb.commit_batch(1, &keccak(b"1b"), None).unwrap();
commit_batch(&mut jdb, 1, &keccak(b"1b"), None).unwrap();
assert!(jdb.can_reconstruct_refs());
jdb.insert(EMPTY_PREFIX, b"foo");
jdb.commit_batch(2, &keccak(b"2a"), None).unwrap();
commit_batch(&mut jdb, 2, &keccak(b"2a"), None).unwrap();
assert!(jdb.can_reconstruct_refs());
jdb.insert(EMPTY_PREFIX, b"foo");
jdb.commit_batch(2, &keccak(b"2b"), None).unwrap();
commit_batch(&mut jdb, 2, &keccak(b"2b"), None).unwrap();
assert!(jdb.can_reconstruct_refs());
jdb.remove(&foo, EMPTY_PREFIX);
jdb.commit_batch(3, &keccak(b"3a"), None).unwrap();
commit_batch(&mut jdb, 3, &keccak(b"3a"), None).unwrap();
assert!(jdb.can_reconstruct_refs());
jdb.remove(&foo, EMPTY_PREFIX);
jdb.commit_batch(3, &keccak(b"3b"), None).unwrap();
commit_batch(&mut jdb, 3, &keccak(b"3b"), None).unwrap();
assert!(jdb.can_reconstruct_refs());
jdb.insert(EMPTY_PREFIX, b"foo");
jdb.commit_batch(4, &keccak(b"4a"), Some((0, keccak(b"0")))).unwrap();
commit_batch(&mut jdb, 4, &keccak(b"4a"), Some((0, keccak(b"0")))).unwrap();
assert!(jdb.can_reconstruct_refs());
jdb.insert(EMPTY_PREFIX, b"foo");
jdb.commit_batch(4, &keccak(b"4b"), Some((0, keccak(b"0")))).unwrap();
commit_batch(&mut jdb, 4, &keccak(b"4b"), Some((0, keccak(b"0")))).unwrap();
assert!(jdb.can_reconstruct_refs());
// expunge foo
jdb.commit_batch(5, &keccak(b"5"), Some((1, keccak(b"1a")))).unwrap();
commit_batch(&mut jdb, 5, &keccak(b"5"), Some((1, keccak(b"1a")))).unwrap();
assert!(jdb.can_reconstruct_refs());
}
@ -847,25 +851,25 @@ mod tests {
let mut jdb = new_db();
let foo = jdb.insert(EMPTY_PREFIX, b"foo");
jdb.commit_batch(1, &keccak(b"1"), Some((0, keccak(b"0")))).unwrap();
commit_batch(&mut jdb, 1, &keccak(b"1"), Some((0, keccak(b"0")))).unwrap();
assert!(jdb.can_reconstruct_refs());
// foo is ancient history.
jdb.remove(&foo, EMPTY_PREFIX);
jdb.commit_batch(2, &keccak(b"2"), Some((1, keccak(b"1")))).unwrap();
commit_batch(&mut jdb, 2, &keccak(b"2"), Some((1, keccak(b"1")))).unwrap();
assert!(jdb.can_reconstruct_refs());
jdb.insert(EMPTY_PREFIX, b"foo");
jdb.commit_batch(3, &keccak(b"3"), Some((2, keccak(b"2")))).unwrap(); // BROKEN
commit_batch(&mut jdb, 3, &keccak(b"3"), Some((2, keccak(b"2")))).unwrap(); // BROKEN
assert!(jdb.can_reconstruct_refs());
assert!(jdb.contains(&foo, EMPTY_PREFIX));
jdb.remove(&foo, EMPTY_PREFIX);
jdb.commit_batch(4, &keccak(b"4"), Some((3, keccak(b"3")))).unwrap();
commit_batch(&mut jdb, 4, &keccak(b"4"), Some((3, keccak(b"3")))).unwrap();
assert!(jdb.can_reconstruct_refs());
jdb.commit_batch(5, &keccak(b"5"), Some((4, keccak(b"4")))).unwrap();
commit_batch(&mut jdb, 5, &keccak(b"5"), Some((4, keccak(b"4")))).unwrap();
assert!(jdb.can_reconstruct_refs());
assert!(!jdb.contains(&foo, EMPTY_PREFIX));
}
@ -875,30 +879,30 @@ mod tests {
let mut jdb = new_db();
// history is 4
let foo = jdb.insert(EMPTY_PREFIX, b"foo");
jdb.commit_batch(0, &keccak(b"0"), None).unwrap();
commit_batch(&mut jdb, 0, &keccak(b"0"), None).unwrap();
assert!(jdb.can_reconstruct_refs());
jdb.commit_batch(1, &keccak(b"1"), None).unwrap();
commit_batch(&mut jdb, 1, &keccak(b"1"), None).unwrap();
assert!(jdb.can_reconstruct_refs());
jdb.commit_batch(2, &keccak(b"2"), None).unwrap();
commit_batch(&mut jdb, 2, &keccak(b"2"), None).unwrap();
assert!(jdb.can_reconstruct_refs());
jdb.commit_batch(3, &keccak(b"3"), None).unwrap();
commit_batch(&mut jdb, 3, &keccak(b"3"), None).unwrap();
assert!(jdb.can_reconstruct_refs());
jdb.commit_batch(4, &keccak(b"4"), Some((0, keccak(b"0")))).unwrap();
commit_batch(&mut jdb, 4, &keccak(b"4"), Some((0, keccak(b"0")))).unwrap();
assert!(jdb.can_reconstruct_refs());
// foo is ancient history.
jdb.insert(EMPTY_PREFIX, b"foo");
let bar = jdb.insert(EMPTY_PREFIX, b"bar");
jdb.commit_batch(5, &keccak(b"5"), Some((1, keccak(b"1")))).unwrap();
commit_batch(&mut jdb, 5, &keccak(b"5"), Some((1, keccak(b"1")))).unwrap();
assert!(jdb.can_reconstruct_refs());
jdb.remove(&foo, EMPTY_PREFIX);
jdb.remove(&bar, EMPTY_PREFIX);
jdb.commit_batch(6, &keccak(b"6"), Some((2, keccak(b"2")))).unwrap();
commit_batch(&mut jdb, 6, &keccak(b"6"), Some((2, keccak(b"2")))).unwrap();
assert!(jdb.can_reconstruct_refs());
jdb.insert(EMPTY_PREFIX, b"foo");
jdb.insert(EMPTY_PREFIX, b"bar");
jdb.commit_batch(7, &keccak(b"7"), Some((3, keccak(b"3")))).unwrap();
commit_batch(&mut jdb, 7, &keccak(b"7"), Some((3, keccak(b"3")))).unwrap();
assert!(jdb.can_reconstruct_refs());
}
@ -913,20 +917,20 @@ mod tests {
let mut jdb = OverlayRecentDB::new(shared_db.clone(), None);
// history is 1
jdb.insert(EMPTY_PREFIX, b"foo");
jdb.commit_batch(0, &keccak(b"0"), None).unwrap();
commit_batch(&mut jdb, 0, &keccak(b"0"), None).unwrap();
assert!(jdb.can_reconstruct_refs());
jdb.commit_batch(1, &keccak(b"1"), None).unwrap();
commit_batch(&mut jdb, 1, &keccak(b"1"), None).unwrap();
assert!(jdb.can_reconstruct_refs());
// foo is ancient history.
jdb.remove(&foo, EMPTY_PREFIX);
jdb.commit_batch(2, &keccak(b"2"), Some((0, keccak(b"0")))).unwrap();
commit_batch(&mut jdb, 2, &keccak(b"2"), Some((0, keccak(b"0")))).unwrap();
assert!(jdb.can_reconstruct_refs());
assert!(jdb.contains(&foo, EMPTY_PREFIX));
jdb.insert(EMPTY_PREFIX, b"foo");
jdb.commit_batch(3, &keccak(b"3"), Some((1, keccak(b"1")))).unwrap();
commit_batch(&mut jdb, 3, &keccak(b"3"), Some((1, keccak(b"1")))).unwrap();
assert!(jdb.can_reconstruct_refs());
assert!(jdb.contains(&foo, EMPTY_PREFIX));
@ -935,7 +939,7 @@ mod tests {
let mut jdb = OverlayRecentDB::new(shared_db.clone(), None);
jdb.remove(&foo, EMPTY_PREFIX);
jdb.commit_batch(4, &keccak(b"4"), Some((2, keccak(b"2")))).unwrap();
commit_batch(&mut jdb, 4, &keccak(b"4"), Some((2, keccak(b"2")))).unwrap();
assert!(jdb.can_reconstruct_refs());
assert!(jdb.contains(&foo, EMPTY_PREFIX));
@ -943,7 +947,7 @@ mod tests {
}; {
let mut jdb = OverlayRecentDB::new(shared_db.clone(), None);
jdb.commit_batch(5, &keccak(b"5"), Some((3, keccak(b"3")))).unwrap();
commit_batch(&mut jdb, 5, &keccak(b"5"), Some((3, keccak(b"3")))).unwrap();
assert!(jdb.can_reconstruct_refs());
assert!(jdb.contains(&foo, EMPTY_PREFIX));
@ -951,7 +955,7 @@ mod tests {
}; {
let mut jdb = OverlayRecentDB::new(shared_db, None);
jdb.commit_batch(6, &keccak(b"6"), Some((4, keccak(b"4")))).unwrap();
commit_batch(&mut jdb, 6, &keccak(b"6"), Some((4, keccak(b"4")))).unwrap();
assert!(jdb.can_reconstruct_refs());
assert!(!jdb.contains(&foo, EMPTY_PREFIX));
}
@ -966,22 +970,22 @@ mod tests {
// history is 1
let foo = jdb.insert(EMPTY_PREFIX, b"foo");
let bar = jdb.insert(EMPTY_PREFIX, b"bar");
jdb.commit_batch(0, &keccak(b"0"), None).unwrap();
commit_batch(&mut jdb, 0, &keccak(b"0"), None).unwrap();
assert!(jdb.can_reconstruct_refs());
jdb.remove(&foo, EMPTY_PREFIX);
let baz = jdb.insert(EMPTY_PREFIX, b"baz");
jdb.commit_batch(1, &keccak(b"1a"), Some((0, keccak(b"0")))).unwrap();
commit_batch(&mut jdb, 1, &keccak(b"1a"), Some((0, keccak(b"0")))).unwrap();
assert!(jdb.can_reconstruct_refs());
jdb.remove(&bar, EMPTY_PREFIX);
jdb.commit_batch(1, &keccak(b"1b"), Some((0, keccak(b"0")))).unwrap();
commit_batch(&mut jdb, 1, &keccak(b"1b"), Some((0, keccak(b"0")))).unwrap();
assert!(jdb.can_reconstruct_refs());
(foo, bar, baz)
};
{
let mut jdb = OverlayRecentDB::new(shared_db, None);
jdb.commit_batch(2, &keccak(b"2b"), Some((1, keccak(b"1b")))).unwrap();
commit_batch(&mut jdb, 2, &keccak(b"2b"), Some((1, keccak(b"1b")))).unwrap();
assert!(jdb.can_reconstruct_refs());
assert!(jdb.contains(&foo, EMPTY_PREFIX));
assert!(!jdb.contains(&baz, EMPTY_PREFIX));
@ -993,17 +997,17 @@ mod tests {
fn insert_older_era() {
let mut jdb = new_db();
let foo = jdb.insert(EMPTY_PREFIX, b"foo");
jdb.commit_batch(0, &keccak(b"0a"), None).unwrap();
commit_batch(&mut jdb, 0, &keccak(b"0a"), None).unwrap();
assert!(jdb.can_reconstruct_refs());
let bar = jdb.insert(EMPTY_PREFIX, b"bar");
jdb.commit_batch(1, &keccak(b"1"), Some((0, keccak(b"0a")))).unwrap();
commit_batch(&mut jdb, 1, &keccak(b"1"), Some((0, keccak(b"0a")))).unwrap();
assert!(jdb.can_reconstruct_refs());
jdb.remove(&bar, EMPTY_PREFIX);
jdb.commit_batch(0, &keccak(b"0b"), None).unwrap();
commit_batch(&mut jdb, 0, &keccak(b"0b"), None).unwrap();
assert!(jdb.can_reconstruct_refs());
jdb.commit_batch(2, &keccak(b"2"), Some((1, keccak(b"1")))).unwrap();
commit_batch(&mut jdb, 2, &keccak(b"2"), Some((1, keccak(b"1")))).unwrap();
assert!(jdb.contains(&foo, EMPTY_PREFIX));
assert!(jdb.contains(&bar, EMPTY_PREFIX));
@ -1013,11 +1017,11 @@ mod tests {
fn inject() {
let mut jdb = new_db();
let key = jdb.insert(EMPTY_PREFIX, b"dog");
jdb.inject_batch().unwrap();
inject_batch(&mut jdb).unwrap();
assert_eq!(jdb.get(&key, EMPTY_PREFIX).unwrap(), DBValue::from_slice(b"dog"));
jdb.remove(&key, EMPTY_PREFIX);
jdb.inject_batch().unwrap();
inject_batch(&mut jdb).unwrap();
assert!(jdb.get(&key, EMPTY_PREFIX).is_none());
}

View File

@ -16,21 +16,26 @@
//! Disk-backed, ref-counted `JournalDB` implementation.
use std::collections::HashMap;
use std::io;
use std::sync::Arc;
use std::{
io,
sync::Arc,
collections::HashMap,
};
use bytes::Bytes;
use ethereum_types::H256;
use hash_db::{HashDB, Prefix, EMPTY_PREFIX};
use parity_util_mem::{MallocSizeOf, allocators::new_malloc_size_ops};
use keccak_hasher::KeccakHasher;
use kvdb::{KeyValueDB, DBTransaction, DBValue};
use overlaydb::OverlayDB;
use log::trace;
use malloc_size_of::{MallocSizeOf, allocators::new_malloc_size_ops};
use parity_bytes::Bytes;
use rlp::{encode, decode};
use super::{DB_PREFIX_LEN, LATEST_ERA_KEY};
use super::traits::JournalDB;
use util::{DatabaseKey, DatabaseValueView, DatabaseValueRef};
use crate::{
overlaydb::OverlayDB,
JournalDB, DB_PREFIX_LEN, LATEST_ERA_KEY,
util::{DatabaseKey, DatabaseValueView, DatabaseValueRef},
};
/// Implementation of the `HashDB` trait for a disk-backed database with a memory overlay
/// and latent-removal semantics.
@ -87,10 +92,6 @@ impl HashDB<KeccakHasher, DBValue> for RefCountedDB {
fn remove(&mut self, key: &H256, _prefix: Prefix) { self.removes.push(key.clone()); }
}
impl ::traits::KeyedHashDB for RefCountedDB {
fn keys(&self) -> HashMap<H256, i32> { self.forward.keys() }
}
impl JournalDB for RefCountedDB {
fn boxed_clone(&self) -> Box<dyn JournalDB> {
Box::new(RefCountedDB {
@ -213,15 +214,19 @@ impl JournalDB for RefCountedDB {
}
}
}
fn keys(&self) -> HashMap<H256, i32> {
self.forward.keys()
}
}
#[cfg(test)]
mod tests {
use keccak::keccak;
use keccak_hash::keccak;
use hash_db::{HashDB, EMPTY_PREFIX};
use super::*;
use {JournalDB, kvdb_memorydb};
use kvdb_memorydb;
use crate::{JournalDB, inject_batch, commit_batch};
fn new_db() -> RefCountedDB {
let backing = Arc::new(kvdb_memorydb::create(0));
@ -233,16 +238,16 @@ mod tests {
// history is 3
let mut jdb = new_db();
let h = jdb.insert(EMPTY_PREFIX, b"foo");
jdb.commit_batch(0, &keccak(b"0"), None).unwrap();
commit_batch(&mut jdb, 0, &keccak(b"0"), None).unwrap();
assert!(jdb.contains(&h, EMPTY_PREFIX));
jdb.remove(&h, EMPTY_PREFIX);
jdb.commit_batch(1, &keccak(b"1"), None).unwrap();
commit_batch(&mut jdb, 1, &keccak(b"1"), None).unwrap();
assert!(jdb.contains(&h, EMPTY_PREFIX));
jdb.commit_batch(2, &keccak(b"2"), None).unwrap();
commit_batch(&mut jdb, 2, &keccak(b"2"), None).unwrap();
assert!(jdb.contains(&h, EMPTY_PREFIX));
jdb.commit_batch(3, &keccak(b"3"), Some((0, keccak(b"0")))).unwrap();
commit_batch(&mut jdb, 3, &keccak(b"3"), Some((0, keccak(b"0")))).unwrap();
assert!(jdb.contains(&h, EMPTY_PREFIX));
jdb.commit_batch(4, &keccak(b"4"), Some((1, keccak(b"1")))).unwrap();
commit_batch(&mut jdb, 4, &keccak(b"4"), Some((1, keccak(b"1")))).unwrap();
assert!(!jdb.contains(&h, EMPTY_PREFIX));
}
@ -252,16 +257,16 @@ mod tests {
let mut jdb = new_db();
assert_eq!(jdb.latest_era(), None);
let h = jdb.insert(EMPTY_PREFIX, b"foo");
jdb.commit_batch(0, &keccak(b"0"), None).unwrap();
commit_batch(&mut jdb, 0, &keccak(b"0"), None).unwrap();
assert_eq!(jdb.latest_era(), Some(0));
jdb.remove(&h, EMPTY_PREFIX);
jdb.commit_batch(1, &keccak(b"1"), None).unwrap();
commit_batch(&mut jdb, 1, &keccak(b"1"), None).unwrap();
assert_eq!(jdb.latest_era(), Some(1));
jdb.commit_batch(2, &keccak(b"2"), None).unwrap();
commit_batch(&mut jdb, 2, &keccak(b"2"), None).unwrap();
assert_eq!(jdb.latest_era(), Some(2));
jdb.commit_batch(3, &keccak(b"3"), Some((0, keccak(b"0")))).unwrap();
commit_batch(&mut jdb, 3, &keccak(b"3"), Some((0, keccak(b"0")))).unwrap();
assert_eq!(jdb.latest_era(), Some(3));
jdb.commit_batch(4, &keccak(b"4"), Some((1, keccak(b"1")))).unwrap();
commit_batch(&mut jdb, 4, &keccak(b"4"), Some((1, keccak(b"1")))).unwrap();
assert_eq!(jdb.latest_era(), Some(4));
}
@ -272,32 +277,32 @@ mod tests {
let foo = jdb.insert(EMPTY_PREFIX, b"foo");
let bar = jdb.insert(EMPTY_PREFIX, b"bar");
jdb.commit_batch(0, &keccak(b"0"), None).unwrap();
commit_batch(&mut jdb, 0, &keccak(b"0"), None).unwrap();
assert!(jdb.contains(&foo, EMPTY_PREFIX));
assert!(jdb.contains(&bar, EMPTY_PREFIX));
jdb.remove(&foo, EMPTY_PREFIX);
jdb.remove(&bar, EMPTY_PREFIX);
let baz = jdb.insert(EMPTY_PREFIX, b"baz");
jdb.commit_batch(1, &keccak(b"1"), Some((0, keccak(b"0")))).unwrap();
commit_batch(&mut jdb, 1, &keccak(b"1"), Some((0, keccak(b"0")))).unwrap();
assert!(jdb.contains(&foo, EMPTY_PREFIX));
assert!(jdb.contains(&bar, EMPTY_PREFIX));
assert!(jdb.contains(&baz, EMPTY_PREFIX));
let foo = jdb.insert(EMPTY_PREFIX, b"foo");
jdb.remove(&baz, EMPTY_PREFIX);
jdb.commit_batch(2, &keccak(b"2"), Some((1, keccak(b"1")))).unwrap();
commit_batch(&mut jdb, 2, &keccak(b"2"), Some((1, keccak(b"1")))).unwrap();
assert!(jdb.contains(&foo, EMPTY_PREFIX));
assert!(!jdb.contains(&bar, EMPTY_PREFIX));
assert!(jdb.contains(&baz, EMPTY_PREFIX));
jdb.remove(&foo, EMPTY_PREFIX);
jdb.commit_batch(3, &keccak(b"3"), Some((2, keccak(b"2")))).unwrap();
commit_batch(&mut jdb, 3, &keccak(b"3"), Some((2, keccak(b"2")))).unwrap();
assert!(jdb.contains(&foo, EMPTY_PREFIX));
assert!(!jdb.contains(&bar, EMPTY_PREFIX));
assert!(!jdb.contains(&baz, EMPTY_PREFIX));
jdb.commit_batch(4, &keccak(b"4"), Some((3, keccak(b"3")))).unwrap();
commit_batch(&mut jdb, 4, &keccak(b"4"), Some((3, keccak(b"3")))).unwrap();
assert!(!jdb.contains(&foo, EMPTY_PREFIX));
assert!(!jdb.contains(&bar, EMPTY_PREFIX));
assert!(!jdb.contains(&baz, EMPTY_PREFIX));
@ -310,22 +315,22 @@ mod tests {
let foo = jdb.insert(EMPTY_PREFIX, b"foo");
let bar = jdb.insert(EMPTY_PREFIX, b"bar");
jdb.commit_batch(0, &keccak(b"0"), None).unwrap();
commit_batch(&mut jdb, 0, &keccak(b"0"), None).unwrap();
assert!(jdb.contains(&foo, EMPTY_PREFIX));
assert!(jdb.contains(&bar, EMPTY_PREFIX));
jdb.remove(&foo, EMPTY_PREFIX);
let baz = jdb.insert(EMPTY_PREFIX, b"baz");
jdb.commit_batch(1, &keccak(b"1a"), Some((0, keccak(b"0")))).unwrap();
commit_batch(&mut jdb, 1, &keccak(b"1a"), Some((0, keccak(b"0")))).unwrap();
jdb.remove(&bar, EMPTY_PREFIX);
jdb.commit_batch(1, &keccak(b"1b"), Some((0, keccak(b"0")))).unwrap();
commit_batch(&mut jdb, 1, &keccak(b"1b"), Some((0, keccak(b"0")))).unwrap();
assert!(jdb.contains(&foo, EMPTY_PREFIX));
assert!(jdb.contains(&bar, EMPTY_PREFIX));
assert!(jdb.contains(&baz, EMPTY_PREFIX));
jdb.commit_batch(2, &keccak(b"2b"), Some((1, keccak(b"1b")))).unwrap();
commit_batch(&mut jdb, 2, &keccak(b"2b"), Some((1, keccak(b"1b")))).unwrap();
assert!(jdb.contains(&foo, EMPTY_PREFIX));
assert!(!jdb.contains(&baz, EMPTY_PREFIX));
assert!(!jdb.contains(&bar, EMPTY_PREFIX));
@ -335,11 +340,11 @@ mod tests {
fn inject() {
let mut jdb = new_db();
let key = jdb.insert(EMPTY_PREFIX, b"dog");
jdb.inject_batch().unwrap();
inject_batch(&mut jdb).unwrap();
assert_eq!(jdb.get(&key, EMPTY_PREFIX).unwrap(), DBValue::from_slice(b"dog"));
jdb.remove(&key, EMPTY_PREFIX);
jdb.inject_batch().unwrap();
inject_batch(&mut jdb).unwrap();
assert!(jdb.get(&key, EMPTY_PREFIX).is_none());
}

View File

@ -1,120 +0,0 @@
// Copyright 2015-2019 Parity Technologies (UK) Ltd.
// This file is part of Parity Ethereum.
// Parity Ethereum is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Parity Ethereum is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Parity Ethereum. If not, see <http://www.gnu.org/licenses/>.
//! Disk-backed `HashDB` implementation.
use std::io;
use std::sync::Arc;
use bytes::Bytes;
use ethereum_types::H256;
use hash_db::{HashDB, AsHashDB};
use keccak_hasher::KeccakHasher;
use kvdb::{self, DBTransaction, DBValue};
use std::collections::HashMap;
/// expose keys of a hashDB for debugging or tests (slow).
pub trait KeyedHashDB: HashDB<KeccakHasher, DBValue> {
/// Primarily use for tests, highly inefficient.
fn keys(&self) -> HashMap<H256, i32>;
}
/// Upcast to `KeyedHashDB`
pub trait AsKeyedHashDB: AsHashDB<KeccakHasher, DBValue> {
/// Perform upcast to KeyedHashDB.
fn as_keyed_hash_db(&self) -> &dyn KeyedHashDB;
}
/// A `HashDB` which can manage a short-term journal potentially containing many forks of mutually
/// exclusive actions.
pub trait JournalDB: KeyedHashDB {
/// Return a copy of ourself, in a box.
fn boxed_clone(&self) -> Box<dyn JournalDB>;
/// Returns heap memory size used
fn mem_used(&self) -> usize;
/// Returns the size of journalled state in memory.
/// This function has a considerable speed requirement --
/// it must be fast enough to call several times per block imported.
fn journal_size(&self) -> usize { 0 }
/// Check if this database has any commits
fn is_empty(&self) -> bool;
/// Get the earliest era in the DB. None if there isn't yet any data in there.
fn earliest_era(&self) -> Option<u64> { None }
/// Get the latest era in the DB. None if there isn't yet any data in there.
fn latest_era(&self) -> Option<u64>;
/// Journal recent database operations as being associated with a given era and id.
// TODO: give the overlay to this function so journaldbs don't manage the overlays themselves.
fn journal_under(&mut self, batch: &mut DBTransaction, now: u64, id: &H256) -> io::Result<u32>;
/// Mark a given block as canonical, indicating that competing blocks' states may be pruned out.
fn mark_canonical(&mut self, batch: &mut DBTransaction, era: u64, id: &H256) -> io::Result<u32>;
/// Commit all queued insert and delete operations without affecting any journalling -- this requires that all insertions
/// and deletions are indeed canonical and will likely lead to an invalid database if that assumption is violated.
///
/// Any keys or values inserted or deleted must be completely independent of those affected
/// by any previous `commit` operations. Essentially, this means that `inject` can be used
/// either to restore a state to a fresh database, or to insert data which may only be journalled
/// from this point onwards.
fn inject(&mut self, batch: &mut DBTransaction) -> io::Result<u32>;
/// State data query
fn state(&self, _id: &H256) -> Option<Bytes>;
/// Whether this database is pruned.
fn is_prunable(&self) -> bool { true }
/// Get backing database.
fn backing(&self) -> &Arc<dyn kvdb::KeyValueDB>;
/// Clear internal strucutres. This should called after changes have been written
/// to the backing strage
fn flush(&self) {}
/// Consolidate all the insertions and deletions in the given memory overlay.
fn consolidate(&mut self, overlay: super::MemoryDB);
/// Commit all changes in a single batch
#[cfg(test)]
fn commit_batch(&mut self, now: u64, id: &H256, end: Option<(u64, H256)>) -> io::Result<u32> {
let mut batch = self.backing().transaction();
let mut ops = self.journal_under(&mut batch, now, id)?;
if let Some((end_era, canon_id)) = end {
ops += self.mark_canonical(&mut batch, end_era, &canon_id)?;
}
let result = self.backing().write(batch).map(|_| ops).map_err(Into::into);
self.flush();
result
}
/// Inject all changes in a single batch.
#[cfg(test)]
fn inject_batch(&mut self) -> io::Result<u32> {
let mut batch = self.backing().transaction();
let res = self.inject(&mut batch)?;
self.backing().write(batch).map(|_| res).map_err(Into::into)
}
}