JournalDB passing all tests.

This commit is contained in:
Gav Wood 2016-01-18 13:30:01 +01:00
parent 193d615f9a
commit 28c07cba52
1 changed files with 111 additions and 21 deletions

View File

@ -26,8 +26,6 @@ impl JournalDB {
/// Create a new instance given a `backing` database. /// Create a new instance given a `backing` database.
pub fn new(backing: DB) -> JournalDB { pub fn new(backing: DB) -> JournalDB {
let db = Arc::new(backing); let db = Arc::new(backing);
// TODO: check it doesn't overwrite anything before.
// TODO: proper handling of errors (return )
JournalDB { JournalDB {
forward: OverlayDB::new_with_arc(db.clone()), forward: OverlayDB::new_with_arc(db.clone()),
backing: db, backing: db,
@ -48,7 +46,7 @@ impl JournalDB {
/// Commit all recent insert operations and historical removals from the old era /// Commit all recent insert operations and historical removals from the old era
/// to the backing database. /// to the backing database.
pub fn commit(&mut self, now: u64, id: &H256, end_era: u64, canon_id: &H256) -> Result<u32, UtilError> { pub fn commit(&mut self, now: u64, id: &H256, end: Option<(u64, &H256)>) -> Result<u32, UtilError> {
// journal format: // journal format:
// [era, 0] => [ id, [insert_0, ...], [remove_0, ...] ] // [era, 0] => [ id, [insert_0, ...], [remove_0, ...] ]
// [era, 1] => [ id, [insert_0, ...], [remove_0, ...] ] // [era, 1] => [ id, [insert_0, ...], [remove_0, ...] ]
@ -81,30 +79,31 @@ impl JournalDB {
r.append(&self.inserts); r.append(&self.inserts);
r.append(&self.removes); r.append(&self.removes);
try!(self.backing.put(&last, &r.out())); try!(self.backing.put(&last, &r.out()));
self.inserts.clear();
self.removes.clear();
} }
// apply old commits' details // apply old commits' details
let mut index = 0usize; if let Some((end_era, canon_id)) = end {
let mut last; let mut index = 0usize;
while let Some(rlp_data) = try!(self.backing.get({ let mut last;
let mut r = RlpStream::new_list(2); while let Some(rlp_data) = try!(self.backing.get({
r.append(&end_era); let mut r = RlpStream::new_list(2);
r.append(&index); r.append(&end_era);
last = r.out(); r.append(&index);
&last last = r.out();
})) { &last
let rlp = Rlp::new(&rlp_data); })) {
let to_remove: Vec<H256> = rlp.val_at(if *canon_id == rlp.val_at(0) {2} else {1}); let rlp = Rlp::new(&rlp_data);
for i in to_remove.iter() { let to_remove: Vec<H256> = rlp.val_at(if *canon_id == rlp.val_at(0) {2} else {1});
self.forward.remove(i); for i in to_remove.iter() {
self.forward.remove(i);
}
try!(self.backing.delete(&last));
index += 1;
} }
try!(self.backing.delete(&last));
index += 1;
} }
self.inserts.clear();
self.removes.clear();
self.forward.commit() self.forward.commit()
} }
@ -121,3 +120,94 @@ impl HashDB for JournalDB {
fn emplace(&mut self, key: H256, value: Bytes) { self.inserts.push(key.clone()); self.forward.emplace(key, value); } fn emplace(&mut self, key: H256, value: Bytes) { self.inserts.push(key.clone()); self.forward.emplace(key, value); }
fn kill(&mut self, key: &H256) { self.removes.push(key.clone()); } fn kill(&mut self, key: &H256) { self.removes.push(key.clone()); }
} }
#[cfg(test)]
mod tests {
use common::*;
use super::*;
use hashdb::*;
#[test]
fn long_history() {
// history is 3
let mut jdb = JournalDB::new_temp();
let h = jdb.insert(b"foo");
jdb.commit(0, &b"0".sha3(), None).unwrap();
assert!(jdb.exists(&h));
jdb.remove(&h);
jdb.commit(1, &b"1".sha3(), None).unwrap();
assert!(jdb.exists(&h));
jdb.commit(2, &b"2".sha3(), None).unwrap();
assert!(jdb.exists(&h));
jdb.commit(3, &b"3".sha3(), Some((0, &b"0".sha3()))).unwrap();
assert!(jdb.exists(&h));
jdb.commit(4, &b"4".sha3(), Some((1, &b"1".sha3()))).unwrap();
assert!(!jdb.exists(&h));
}
#[test]
fn complex() {
// history is 1
let mut jdb = JournalDB::new_temp();
let foo = jdb.insert(b"foo");
let bar = jdb.insert(b"bar");
jdb.commit(0, &b"0".sha3(), None).unwrap();
assert!(jdb.exists(&foo));
assert!(jdb.exists(&bar));
jdb.remove(&foo);
jdb.remove(&bar);
let baz = jdb.insert(b"baz");
jdb.commit(1, &b"1".sha3(), Some((0, &b"0".sha3()))).unwrap();
assert!(jdb.exists(&foo));
assert!(jdb.exists(&bar));
assert!(jdb.exists(&baz));
let foo = jdb.insert(b"foo");
jdb.remove(&baz);
jdb.commit(2, &b"2".sha3(), Some((1, &b"1".sha3()))).unwrap();
assert!(jdb.exists(&foo));
assert!(!jdb.exists(&bar));
assert!(jdb.exists(&baz));
jdb.remove(&foo);
jdb.commit(3, &b"3".sha3(), Some((2, &b"2".sha3()))).unwrap();
assert!(jdb.exists(&foo));
assert!(!jdb.exists(&bar));
assert!(!jdb.exists(&baz));
jdb.commit(4, &b"4".sha3(), Some((3, &b"3".sha3()))).unwrap();
assert!(!jdb.exists(&foo));
assert!(!jdb.exists(&bar));
assert!(!jdb.exists(&baz));
}
#[test]
fn fork() {
// history is 1
let mut jdb = JournalDB::new_temp();
let foo = jdb.insert(b"foo");
let bar = jdb.insert(b"bar");
jdb.commit(0, &b"0".sha3(), None).unwrap();
assert!(jdb.exists(&foo));
assert!(jdb.exists(&bar));
jdb.remove(&foo);
let baz = jdb.insert(b"baz");
jdb.commit(1, &b"1a".sha3(), Some((0, &b"0".sha3()))).unwrap();
jdb.remove(&bar);
jdb.commit(1, &b"1b".sha3(), Some((0, &b"0".sha3()))).unwrap();
assert!(jdb.exists(&foo));
assert!(jdb.exists(&bar));
assert!(jdb.exists(&baz));
jdb.commit(2, &b"2b".sha3(), Some((1, &b"1b".sha3()))).unwrap();
assert!(jdb.exists(&foo));
assert!(!jdb.exists(&baz));
assert!(!jdb.exists(&bar));
}
}