memorydb/
lib.rs

1// Copyright 2015-2018 Parity Technologies (UK) Ltd.
2// This file is part of Parity.
3
4// Parity is free software: you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation, either version 3 of the License, or
7// (at your option) any later version.
8
9// Parity is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12// GNU General Public License for more details.
13
14// You should have received a copy of the GNU General Public License
15// along with Parity.  If not, see <http://www.gnu.org/licenses/>.
16
17//! Reference-counted memory-based `HashDB` implementation.
18extern crate hashdb;
19extern crate heapsize;
20extern crate rlp;
21#[cfg(test)] extern crate keccak_hasher;
22#[cfg(test)] extern crate tiny_keccak;
23#[cfg(test)] extern crate ethereum_types;
24
25use hashdb::{HashDB, Hasher as KeyHasher, AsHashDB};
26use heapsize::HeapSizeOf;
27use rlp::NULL_RLP;
28use std::collections::hash_map::Entry;
29use std::collections::HashMap;
30use std::hash;
31use std::mem;
32
33// Backing `HashMap` parametrized with a `Hasher` for the keys `Hasher::Out` and the `Hasher::StdHasher`
34// as hash map builder.
35type FastMap<H, T> = HashMap<<H as KeyHasher>::Out, T, hash::BuildHasherDefault<<H as KeyHasher>::StdHasher>>;
36
37/// Reference-counted memory-based `HashDB` implementation.
38///
39/// Use `new()` to create a new database. Insert items with `insert()`, remove items
40/// with `remove()`, check for existence with `contains()` and lookup a hash to derive
41/// the data with `get()`. Clear with `clear()` and purge the portions of the data
42/// that have no references with `purge()`.
43///
44/// # Example
45/// ```rust
46/// extern crate hashdb;
47/// extern crate keccak_hasher;
48/// extern crate memorydb;
49///
50/// use hashdb::*;
51/// use keccak_hasher::KeccakHasher;
52/// use memorydb::*;
53/// fn main() {
54///   let mut m = MemoryDB::<KeccakHasher, Vec<u8>>::new();
55///   let d = "Hello world!".as_bytes();
56///
57///   let k = m.insert(d);
58///   assert!(m.contains(&k));
59///   assert_eq!(m.get(&k).unwrap(), d);
60///
61///   m.insert(d);
62///   assert!(m.contains(&k));
63///
64///   m.remove(&k);
65///   assert!(m.contains(&k));
66///
67///   m.remove(&k);
68///   assert!(!m.contains(&k));
69///
70///   m.remove(&k);
71///   assert!(!m.contains(&k));
72///
73///   m.insert(d);
74///   assert!(!m.contains(&k));
75
76///   m.insert(d);
77///   assert!(m.contains(&k));
78///   assert_eq!(m.get(&k).unwrap(), d);
79///
80///   m.remove(&k);
81///   assert!(!m.contains(&k));
82/// }
83/// ```
84#[derive(Clone, PartialEq)]
85pub struct MemoryDB<H: KeyHasher, T> {
86	data: FastMap<H, (T, i32)>,
87	hashed_null_node: H::Out,
88	null_node_data: T,
89}
90
91impl<'a, H, T> Default for MemoryDB<H, T>
92where
93	H: KeyHasher,
94	H::Out: HeapSizeOf,
95	T: From<&'a [u8]> + Clone
96{
97	fn default() -> Self { Self::new() }
98}
99
100impl<'a, H, T> MemoryDB<H, T>
101where
102	H: KeyHasher,
103	H::Out: HeapSizeOf,
104	T: From<&'a [u8]> + Clone,
105{
106	/// Create a new instance of the memory DB.
107	pub fn new() -> Self {
108		MemoryDB::from_null_node(&NULL_RLP, NULL_RLP.as_ref().into())
109	}
110}
111
112impl<H, T> MemoryDB<H, T>
113where
114	H: KeyHasher,
115	H::Out: HeapSizeOf,
116	T: Default,
117{
118	/// Remove an element and delete it from storage if reference count reaches zero.
119	/// If the value was purged, return the old value.
120	pub fn remove_and_purge(&mut self, key: &<H as KeyHasher>::Out) -> Option<T> {
121		if key == &self.hashed_null_node {
122			return None;
123		}
124		match self.data.entry(key.clone()) {
125			Entry::Occupied(mut entry) =>
126				if entry.get().1 == 1 {
127					Some(entry.remove().0)
128				} else {
129					entry.get_mut().1 -= 1;
130					None
131				},
132			Entry::Vacant(entry) => {
133				entry.insert((T::default(), -1)); // FIXME: shouldn't it be purged?
134				None
135			}
136		}
137	}
138}
139
140impl<H: KeyHasher, T: Clone> MemoryDB<H, T> {
141
142	/// Create a new `MemoryDB` from a given null key/data
143	pub fn from_null_node(null_key: &[u8], null_node_data: T) -> Self {
144		MemoryDB {
145			data: FastMap::<H,_>::default(),
146			hashed_null_node: H::hash(null_key),
147			null_node_data,
148		}
149	}
150
151	/// Clear all data from the database.
152	///
153	/// # Examples
154	/// ```rust
155	/// extern crate hashdb;
156	/// extern crate keccak_hasher;
157	/// extern crate memorydb;
158	///
159	/// use hashdb::*;
160	/// use keccak_hasher::KeccakHasher;
161	/// use memorydb::*;
162	///
163	/// fn main() {
164	///   let mut m = MemoryDB::<KeccakHasher, Vec<u8>>::new();
165	///   let hello_bytes = "Hello world!".as_bytes();
166	///   let hash = m.insert(hello_bytes);
167	///   assert!(m.contains(&hash));
168	///   m.clear();
169	///   assert!(!m.contains(&hash));
170	/// }
171	/// ```
172	pub fn clear(&mut self) {
173		self.data.clear();
174	}
175
176	/// Purge all zero-referenced data from the database.
177	pub fn purge(&mut self) {
178		self.data.retain(|_, &mut (_, rc)| rc != 0);
179	}
180
181	/// Return the internal map of hashes to data, clearing the current state.
182	pub fn drain(&mut self) -> FastMap<H, (T, i32)> {
183		mem::replace(&mut self.data, FastMap::<H,_>::default())
184	}
185
186	/// Grab the raw information associated with a key. Returns None if the key
187	/// doesn't exist.
188	///
189	/// Even when Some is returned, the data is only guaranteed to be useful
190	/// when the refs > 0.
191	pub fn raw(&self, key: &<H as KeyHasher>::Out) -> Option<(T, i32)> {
192		if key == &self.hashed_null_node {
193			return Some((self.null_node_data.clone(), 1));
194		}
195		self.data.get(key).map(|(value, count)| (value.clone(), *count))
196	}
197
198	/// Consolidate all the entries of `other` into `self`.
199	pub fn consolidate(&mut self, mut other: Self) {
200		for (key, (value, rc)) in other.drain() {
201			match self.data.entry(key) {
202				Entry::Occupied(mut entry) => {
203					if entry.get().1 < 0 {
204						entry.get_mut().0 = value;
205					}
206
207					entry.get_mut().1 += rc;
208				}
209				Entry::Vacant(entry) => {
210					entry.insert((value, rc));
211				}
212			}
213		}
214	}
215}
216
217impl<H, T> MemoryDB<H, T>
218where
219	H: KeyHasher,
220	H::Out: HeapSizeOf,
221	T: HeapSizeOf,
222{
223	/// Returns the size of allocated heap memory
224	pub fn mem_used(&self) -> usize {
225		self.data.heap_size_of_children()
226	}
227}
228
229impl<H, T> HashDB<H, T> for MemoryDB<H, T>
230where
231	H: KeyHasher,
232	T: Default + PartialEq<T> + for<'a> From<&'a [u8]> + Send + Sync + Clone,
233{
234	fn keys(&self) -> HashMap<H::Out, i32> {
235		self.data.iter()
236			.filter_map(|(k, v)| if v.1 != 0 {
237				Some((*k, v.1))
238			} else {
239				None
240			})
241			.collect()
242	}
243
244	fn get(&self, key: &H::Out) -> Option<T> {
245		if key == &self.hashed_null_node {
246			return Some(self.null_node_data.clone());
247		}
248
249		match self.data.get(key) {
250			Some(&(ref d, rc)) if rc > 0 => Some(d.clone()),
251			_ => None
252		}
253	}
254
255	fn contains(&self, key: &H::Out) -> bool {
256		if key == &self.hashed_null_node {
257			return true;
258		}
259
260		match self.data.get(key) {
261			Some(&(_, x)) if x > 0 => true,
262			_ => false
263		}
264	}
265
266	fn emplace(&mut self, key:H::Out, value: T) {
267		if value == self.null_node_data {
268			return;
269		}
270
271		match self.data.entry(key) {
272			Entry::Occupied(mut entry) => {
273				let &mut (ref mut old_value, ref mut rc) = entry.get_mut();
274				if *rc <= 0 {
275					*old_value = value;
276				}
277				*rc += 1;
278			},
279			Entry::Vacant(entry) => {
280				entry.insert((value, 1));
281			},
282		}
283	}
284
285	fn insert(&mut self, value: &[u8]) -> H::Out {
286		if value == &NULL_RLP {
287			return self.hashed_null_node.clone();
288		}
289		let key = H::hash(value);
290		match self.data.entry(key) {
291			Entry::Occupied(mut entry) => {
292				let &mut (ref mut old_value, ref mut rc) = entry.get_mut();
293				if *rc <= 0 {
294					*old_value = value.into();
295				}
296				*rc += 1;
297			},
298			Entry::Vacant(entry) => {
299				entry.insert((value.into(), 1));
300			},
301		}
302		key
303	}
304
305	fn remove(&mut self, key: &H::Out) {
306		if key == &self.hashed_null_node {
307			return;
308		}
309
310		match self.data.entry(*key) {
311			Entry::Occupied(mut entry) => {
312				let &mut (_, ref mut rc) = entry.get_mut();
313				*rc -= 1;
314			},
315			Entry::Vacant(entry) => {
316				entry.insert((T::default(), -1));
317			},
318		}
319	}
320
321}
322
323impl<H, T> AsHashDB<H, T> for MemoryDB<H, T>
324where
325	H: KeyHasher,
326	T: Default + PartialEq<T> + for<'a> From<&'a[u8]> + Send + Sync + Clone,
327{
328	fn as_hashdb(&self) -> &HashDB<H, T> { self }
329	fn as_hashdb_mut(&mut self) -> &mut HashDB<H, T> { self }
330}
331
332#[cfg(test)]
333mod tests {
334	use super::*;
335	use tiny_keccak::Keccak;
336	use ethereum_types::H256;
337	use keccak_hasher::KeccakHasher;
338
339	#[test]
340	fn memorydb_remove_and_purge() {
341		let hello_bytes = b"Hello world!";
342		let mut hello_key = [0;32];
343		Keccak::keccak256(hello_bytes, &mut hello_key);
344		let hello_key = H256(hello_key);
345
346		let mut m = MemoryDB::<KeccakHasher, Vec<u8>>::new();
347		m.remove(&hello_key);
348		assert_eq!(m.raw(&hello_key).unwrap().1, -1);
349		m.purge();
350		assert_eq!(m.raw(&hello_key).unwrap().1, -1);
351		m.insert(hello_bytes);
352		assert_eq!(m.raw(&hello_key).unwrap().1, 0);
353		m.purge();
354		assert_eq!(m.raw(&hello_key), None);
355
356		let mut m = MemoryDB::<KeccakHasher, Vec<u8>>::new();
357		assert!(m.remove_and_purge(&hello_key).is_none());
358		assert_eq!(m.raw(&hello_key).unwrap().1, -1);
359		m.insert(hello_bytes);
360		m.insert(hello_bytes);
361		assert_eq!(m.raw(&hello_key).unwrap().1, 1);
362		assert_eq!(&*m.remove_and_purge(&hello_key).unwrap(), hello_bytes);
363		assert_eq!(m.raw(&hello_key), None);
364		assert!(m.remove_and_purge(&hello_key).is_none());
365	}
366
367	#[test]
368	fn consolidate() {
369		let mut main = MemoryDB::<KeccakHasher, Vec<u8>>::new();
370		let mut other = MemoryDB::<KeccakHasher, Vec<u8>>::new();
371		let remove_key = other.insert(b"doggo");
372		main.remove(&remove_key);
373
374		let insert_key = other.insert(b"arf");
375		main.emplace(insert_key, "arf".as_bytes().to_vec());
376
377		let negative_remove_key = other.insert(b"negative");
378		other.remove(&negative_remove_key);	// ref cnt: 0
379		other.remove(&negative_remove_key);	// ref cnt: -1
380		main.remove(&negative_remove_key);	// ref cnt: -1
381
382		main.consolidate(other);
383
384		let overlay = main.drain();
385
386		assert_eq!(overlay.get(&remove_key).unwrap(), &("doggo".as_bytes().to_vec(), 0));
387		assert_eq!(overlay.get(&insert_key).unwrap(), &("arf".as_bytes().to_vec(), 2));
388		assert_eq!(overlay.get(&negative_remove_key).unwrap(), &("negative".as_bytes().to_vec(), -2));
389	}
390
391	#[test]
392	fn default_works() {
393		let mut db = MemoryDB::<KeccakHasher, Vec<u8>>::default();
394		let hashed_null_node = KeccakHasher::hash(&NULL_RLP);
395		assert_eq!(db.insert(&NULL_RLP), hashed_null_node);
396	}
397}