In-memory trie operations (#1408)

* small cleanups in trie

* Memory trie skeleton

* decode nodes from RLP

* memorytrie -> memorytriedb

* implement Trie for MemoryTrie

* partially implement insert

* implement trie insertion

* don't load whole trie into memory, lookup across memory and db

* re-implement insertion and lazily load necessary nodes from DB

* node removal w/o fixing

* reduce churn in node storage

* finish remove implementation

* committing the in-memory trie

* reload root node after commit

* generate elastic arrays when converting nodes to rlp

* port triedbmut tests over to memorytriedb, fix a few bugs.

* hash count and dirty flag

* initial attempt for node inspection

* back to skeleton

* inspection framework

* implement insertion

* no panic paths in insert

* implement deletion without fixing

* node fixing

* commit nodes to db

* tracing targets and bugfix

* get tests to pass with a lot of tracing

* set playpen iterations to 10

* remove some tracing statements

* make TrieMut::root take &mut self

* replace triedbmut with memorytriedb

* treat empty insert value as removal

* add test for null insert

* fix some style concerns

* trie: use nodehandle for root_node, minor cleanup
This commit is contained in:
Robert Habermeier 2016-07-14 18:06:46 +02:00 committed by Arkadiy Paronyan
parent 598833d1ea
commit 517c705ab5
7 changed files with 833 additions and 717 deletions

View File

@ -54,10 +54,14 @@ impl<'db> FatDBMut<'db> {
} }
impl<'db> TrieMut for FatDBMut<'db> { impl<'db> TrieMut for FatDBMut<'db> {
fn root(&self) -> &H256 { fn root(&mut self) -> &H256 {
self.raw.root() self.raw.root()
} }
fn is_empty(&self) -> bool {
self.raw.is_empty()
}
fn contains(&self, key: &[u8]) -> bool { fn contains(&self, key: &[u8]) -> bool {
self.raw.contains(&key.sha3()) self.raw.contains(&key.sha3())
} }

View File

@ -38,7 +38,6 @@ pub mod sectriedb;
pub mod sectriedbmut; pub mod sectriedbmut;
mod fatdb; mod fatdb;
mod fatdbmut; mod fatdbmut;
pub use self::trietraits::{Trie, TrieMut}; pub use self::trietraits::{Trie, TrieMut};

View File

@ -25,11 +25,11 @@ pub enum Node<'a> {
/// Null trie node; could be an empty root or an empty branch entry. /// Null trie node; could be an empty root or an empty branch entry.
Empty, Empty,
/// Leaf node; has key slice and value. Value may not be empty. /// Leaf node; has key slice and value. Value may not be empty.
Leaf(NibbleSlice<'a>, &'a[u8]), Leaf(NibbleSlice<'a>, &'a [u8]),
/// Extension node; has key slice and node data. Data may not be null. /// Extension node; has key slice and node data. Data may not be null.
Extension(NibbleSlice<'a>, &'a[u8]), Extension(NibbleSlice<'a>, &'a [u8]),
/// Branch node; has array of 16 child nodes (each possibly null) and an optional immediate node data. /// Branch node; has array of 16 child nodes (each possibly null) and an optional immediate node data.
Branch([&'a[u8]; 16], Option<&'a [u8]>) Branch([&'a [u8]; 16], Option<&'a [u8]>)
} }
impl<'a> Node<'a> { impl<'a> Node<'a> {

View File

@ -51,7 +51,13 @@ impl<'db> SecTrieDBMut<'db> {
} }
impl<'db> TrieMut for SecTrieDBMut<'db> { impl<'db> TrieMut for SecTrieDBMut<'db> {
fn root(&self) -> &H256 { self.raw.root() } fn root(&mut self) -> &H256 {
self.raw.root()
}
fn is_empty(&self) -> bool {
self.raw.is_empty()
}
fn contains(&self, key: &[u8]) -> bool { fn contains(&self, key: &[u8]) -> bool {
self.raw.contains(&key.sha3()) self.raw.contains(&key.sha3())

View File

@ -88,8 +88,7 @@ impl<'db> TrieDB<'db> {
pub fn to_map(hashes: Vec<H256>) -> HashMap<H256, u32> { pub fn to_map(hashes: Vec<H256>) -> HashMap<H256, u32> {
let mut r: HashMap<H256, u32> = HashMap::new(); let mut r: HashMap<H256, u32> = HashMap::new();
for h in hashes.into_iter() { for h in hashes.into_iter() {
let c = *r.get(&h).unwrap_or(&0); *r.entry(h).or_insert(0) += 1;
r.insert(h, c + 1);
} }
r r
} }
@ -184,7 +183,7 @@ impl<'db> TrieDB<'db> {
/// Return optional data for a key given as a `NibbleSlice`. Returns `None` if no data exists. /// Return optional data for a key given as a `NibbleSlice`. Returns `None` if no data exists.
fn do_lookup<'a, 'key>(&'a self, key: &NibbleSlice<'key>) -> Option<&'a [u8]> where 'a: 'key { fn do_lookup<'a, 'key>(&'a self, key: &NibbleSlice<'key>) -> Option<&'a [u8]> where 'a: 'key {
let root_rlp = self.db.get(&self.root).expect("Trie root not found!"); let root_rlp = self.root_data();
self.get_from_node(&root_rlp, key) self.get_from_node(&root_rlp, key)
} }

File diff suppressed because it is too large Load Diff

View File

@ -18,7 +18,7 @@ use hash::H256;
use rlp::SHA3_NULL_RLP; use rlp::SHA3_NULL_RLP;
/// Trie-Item type. /// Trie-Item type.
pub type TrieItem<'a> = (Vec<u8>, &'a[u8]); pub type TrieItem<'a> = (Vec<u8>, &'a [u8]);
/// A key-value datastore implemented as a database-backed modified Merkle tree. /// A key-value datastore implemented as a database-backed modified Merkle tree.
pub trait Trie { pub trait Trie {
@ -41,10 +41,10 @@ pub trait Trie {
/// A key-value datastore implemented as a database-backed modified Merkle tree. /// A key-value datastore implemented as a database-backed modified Merkle tree.
pub trait TrieMut { pub trait TrieMut {
/// Return the root of the trie. /// Return the root of the trie.
fn root(&self) -> &H256; fn root(&mut self) -> &H256;
/// Is the trie empty? /// Is the trie empty?
fn is_empty(&self) -> bool { *self.root() == SHA3_NULL_RLP } fn is_empty(&self) -> bool;
/// Does the trie contain a given key? /// Does the trie contain a given key?
fn contains(&self, key: &[u8]) -> bool; fn contains(&self, key: &[u8]) -> bool;