trie node ref counter. good for testing.
This commit is contained in:
		
							parent
							
								
									84cc7715b4
								
							
						
					
					
						commit
						cbbe5ee0fe
					
				@ -1,7 +1,11 @@
 | 
				
			|||||||
use hash::*;
 | 
					use hash::*;
 | 
				
			||||||
use bytes::*;
 | 
					use bytes::*;
 | 
				
			||||||
 | 
					use std::collections::HashMap;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub trait HashDB {
 | 
					pub trait HashDB {
 | 
				
			||||||
 | 
						/// Get the keys in the database together with number of underlying references.
 | 
				
			||||||
 | 
						fn keys(&self) -> HashMap<H256, u32>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/// Look up a given hash into the bytes that hash to it, returning None if the 
 | 
						/// Look up a given hash into the bytes that hash to it, returning None if the 
 | 
				
			||||||
	/// hash is not known.
 | 
						/// hash is not known.
 | 
				
			||||||
	///
 | 
						///
 | 
				
			||||||
 | 
				
			|||||||
@ -116,6 +116,10 @@ impl MemoryDB {
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
		self.data.get(key).unwrap()
 | 
							self.data.get(key).unwrap()
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						pub fn raw_keys(&self) -> HashMap<H256, i32> {
 | 
				
			||||||
 | 
							self.data.iter().filter_map(|(k, v)| if v.1 != 0 {Some((k.clone(), v.1))} else {None}).collect::<HashMap<H256, i32>>()
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl HashDB for MemoryDB {
 | 
					impl HashDB for MemoryDB {
 | 
				
			||||||
@ -126,6 +130,10 @@ impl HashDB for MemoryDB {
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						fn keys(&self) -> HashMap<H256, u32> {
 | 
				
			||||||
 | 
							self.data.iter().filter_map(|(k, v)| if v.1 > 0 {Some((k.clone(), v.1 as u32))} else {None} ).collect::<HashMap<H256, u32>>()
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	fn exists(&self, key: &H256) -> bool {
 | 
						fn exists(&self, key: &H256) -> bool {
 | 
				
			||||||
		match self.data.get(key) {
 | 
							match self.data.get(key) {
 | 
				
			||||||
			Some(&(_, x)) if x > 0 => true,
 | 
								Some(&(_, x)) if x > 0 => true,
 | 
				
			||||||
 | 
				
			|||||||
@ -9,6 +9,7 @@ use memorydb::*;
 | 
				
			|||||||
use std::ops::*;
 | 
					use std::ops::*;
 | 
				
			||||||
use std::sync::*;
 | 
					use std::sync::*;
 | 
				
			||||||
use std::env;
 | 
					use std::env;
 | 
				
			||||||
 | 
					use std::collections::HashMap;
 | 
				
			||||||
use rocksdb::{DB, Writable};
 | 
					use rocksdb::{DB, Writable};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(Clone)]
 | 
					#[derive(Clone)]
 | 
				
			||||||
@ -135,6 +136,20 @@ impl OverlayDB {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl HashDB for OverlayDB {
 | 
					impl HashDB for OverlayDB {
 | 
				
			||||||
 | 
						fn keys(&self) -> HashMap<H256, u32> {
 | 
				
			||||||
 | 
							let mut ret: HashMap<H256, u32> = HashMap::new();
 | 
				
			||||||
 | 
							for (key, _) in self.backing.iterator().from_start() {
 | 
				
			||||||
 | 
								let h = H256::from_slice(key.deref());
 | 
				
			||||||
 | 
								let r = self.payload(&h).unwrap().1;
 | 
				
			||||||
 | 
								ret.insert(h, r);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							for (key, refs) in self.overlay.raw_keys().into_iter() {
 | 
				
			||||||
 | 
								let refs = *ret.get(&key).unwrap_or(&0u32) as i32 + refs as i32;
 | 
				
			||||||
 | 
								ret.insert(key, refs as u32);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							ret
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	fn lookup(&self, key: &H256) -> Option<&[u8]> {
 | 
						fn lookup(&self, key: &H256) -> Option<&[u8]> {
 | 
				
			||||||
		// return ok if positive; if negative, check backing - might be enough references there to make
 | 
							// return ok if positive; if negative, check backing - might be enough references there to make
 | 
				
			||||||
		// it positive again.
 | 
							// it positive again.
 | 
				
			||||||
 | 
				
			|||||||
@ -125,6 +125,7 @@ impl<'a> From<Rlp<'a>> for UntrustedRlp<'a> {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(Debug)]
 | 
				
			||||||
pub enum Prototype {
 | 
					pub enum Prototype {
 | 
				
			||||||
	Null,
 | 
						Null,
 | 
				
			||||||
	Data(usize),
 | 
						Data(usize),
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										54
									
								
								src/trie.rs
									
									
									
									
									
								
							
							
						
						
									
										54
									
								
								src/trie.rs
									
									
									
									
									
								
							@ -8,6 +8,7 @@ use hash::*;
 | 
				
			|||||||
use nibbleslice::*;
 | 
					use nibbleslice::*;
 | 
				
			||||||
use bytes::*;
 | 
					use bytes::*;
 | 
				
			||||||
use rlp::*;
 | 
					use rlp::*;
 | 
				
			||||||
 | 
					use std::collections::HashMap;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
//use log::*;
 | 
					//use log::*;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -238,6 +239,52 @@ impl TrieDB {
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						pub fn keys(&self) -> Vec<H256> {
 | 
				
			||||||
 | 
							let mut ret: Vec<H256> = Vec::new();
 | 
				
			||||||
 | 
							ret.push(self.root.clone());
 | 
				
			||||||
 | 
							self.accumulate_keys(self.root_node(), &mut ret);
 | 
				
			||||||
 | 
							ret
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						fn accumulate_keys(&self, node: Node, acc: &mut Vec<H256>) {
 | 
				
			||||||
 | 
							let mut handle_payload = |payload| {
 | 
				
			||||||
 | 
								let p = Rlp::new(payload);
 | 
				
			||||||
 | 
								if p.is_data() && p.size() == 32 {
 | 
				
			||||||
 | 
									acc.push(H256::decode(&p));
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								self.accumulate_keys(self.get_node(payload), acc);
 | 
				
			||||||
 | 
							};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							match node {
 | 
				
			||||||
 | 
								Node::Extension(_, payload) => handle_payload(payload),
 | 
				
			||||||
 | 
								Node::Branch(payloads, _) => for payload in payloads.iter() { handle_payload(payload) },
 | 
				
			||||||
 | 
								_ => {},
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						fn to_map(hashes: Vec<H256>) -> HashMap<H256, u32> {
 | 
				
			||||||
 | 
							let mut r: HashMap<H256, u32> = HashMap::new();
 | 
				
			||||||
 | 
							for h in hashes.into_iter() {
 | 
				
			||||||
 | 
								let c = *r.get(&h).unwrap_or(&0);
 | 
				
			||||||
 | 
								r.insert(h, c + 1);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							r
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						pub fn db_items_remaining(&self) -> HashMap<H256, u32> {
 | 
				
			||||||
 | 
							let mut ret = self.db().keys();
 | 
				
			||||||
 | 
							for (k, v) in Self::to_map(self.keys()).into_iter() {
 | 
				
			||||||
 | 
								let old = *ret.get(&k).expect("Node in trie is not in database!");
 | 
				
			||||||
 | 
								assert!(old >= v);
 | 
				
			||||||
 | 
								match old > v {
 | 
				
			||||||
 | 
									true => ret.insert(k, old - v),
 | 
				
			||||||
 | 
									_ => ret.remove(&k),
 | 
				
			||||||
 | 
								};
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							ret
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	fn fmt_indent(&self, f: &mut fmt::Formatter, size: usize) -> fmt::Result {
 | 
						fn fmt_indent(&self, f: &mut fmt::Formatter, size: usize) -> fmt::Result {
 | 
				
			||||||
		for _ in 0..size { 
 | 
							for _ in 0..size { 
 | 
				
			||||||
			try!(write!(f, "  "));
 | 
								try!(write!(f, "  "));
 | 
				
			||||||
@ -245,6 +292,10 @@ impl TrieDB {
 | 
				
			|||||||
		Ok(())
 | 
							Ok(())
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						fn root_node(&self) -> Node {
 | 
				
			||||||
 | 
							Node::decoded(self.db.lookup(&self.root).expect("Trie root not found!"))
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	fn get_node<'a>(&'a self, node: &'a [u8]) -> Node {
 | 
						fn get_node<'a>(&'a self, node: &'a [u8]) -> Node {
 | 
				
			||||||
		Node::decoded(self.get_raw_or_lookup(node))
 | 
							Node::decoded(self.get_raw_or_lookup(node))
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@ -762,11 +813,14 @@ mod tests {
 | 
				
			|||||||
		let mut t1 = TrieDB::new_memory();
 | 
							let mut t1 = TrieDB::new_memory();
 | 
				
			||||||
		t1.insert(&[0x01, 0x23], &big_value.to_vec());
 | 
							t1.insert(&[0x01, 0x23], &big_value.to_vec());
 | 
				
			||||||
		t1.insert(&[0x01, 0x34], &big_value.to_vec());
 | 
							t1.insert(&[0x01, 0x34], &big_value.to_vec());
 | 
				
			||||||
 | 
							trace!("keys remaining {:?}", t1.db_items_remaining());
 | 
				
			||||||
 | 
							assert!(t1.db_items_remaining().is_empty());
 | 
				
			||||||
		let mut t2 = TrieDB::new_memory();
 | 
							let mut t2 = TrieDB::new_memory();
 | 
				
			||||||
		t2.insert(&[0x01], &big_value.to_vec());
 | 
							t2.insert(&[0x01], &big_value.to_vec());
 | 
				
			||||||
		t2.insert(&[0x01, 0x23], &big_value.to_vec());
 | 
							t2.insert(&[0x01, 0x23], &big_value.to_vec());
 | 
				
			||||||
		t2.insert(&[0x01, 0x34], &big_value.to_vec());
 | 
							t2.insert(&[0x01, 0x34], &big_value.to_vec());
 | 
				
			||||||
		t2.remove(&[0x01]);
 | 
							t2.remove(&[0x01]);
 | 
				
			||||||
 | 
							assert!(t2.db_items_remaining().is_empty());
 | 
				
			||||||
		/*if t1.root() != t2.root()*/ {
 | 
							/*if t1.root() != t2.root()*/ {
 | 
				
			||||||
			trace!("{:?}", t1);
 | 
								trace!("{:?}", t1);
 | 
				
			||||||
			trace!("{:?}", t2);
 | 
								trace!("{:?}", t2);
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
		Reference in New Issue
	
	Block a user