Remove panickers from trie iterators (#2209)
* port trie iterators to use error handling * use new trie iterators in snapshot allows proper recovery from a premature periodic snapshot
This commit is contained in:
parent
8c111da70b
commit
a100b9d09e
@ -144,7 +144,9 @@ pub struct Client {
|
|||||||
factories: Factories,
|
factories: Factories,
|
||||||
}
|
}
|
||||||
|
|
||||||
const HISTORY: u64 = 1200;
|
/// The pruning constant -- how old blocks must be before we
|
||||||
|
/// assume finality of a given candidate.
|
||||||
|
pub const HISTORY: u64 = 1200;
|
||||||
|
|
||||||
/// Append a path element to the given path and return the string.
|
/// Append a path element to the given path and return the string.
|
||||||
pub fn append_path<P>(path: P, item: &str) -> String where P: AsRef<Path> {
|
pub fn append_path<P>(path: P, item: &str) -> String where P: AsRef<Path> {
|
||||||
|
@ -92,7 +92,8 @@ impl Account {
|
|||||||
|
|
||||||
let mut pairs = Vec::new();
|
let mut pairs = Vec::new();
|
||||||
|
|
||||||
for (k, v) in db.iter() {
|
for item in try!(db.iter()) {
|
||||||
|
let (k, v) = try!(item);
|
||||||
pairs.push((k, v));
|
pairs.push((k, v));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -358,7 +358,8 @@ pub fn chunk_state<'a>(db: &HashDB, root: &H256, writer: &Mutex<SnapshotWriter +
|
|||||||
let mut used_code = HashSet::new();
|
let mut used_code = HashSet::new();
|
||||||
|
|
||||||
// account_key here is the address' hash.
|
// account_key here is the address' hash.
|
||||||
for (account_key, account_data) in account_trie.iter() {
|
for item in try!(account_trie.iter()) {
|
||||||
|
let (account_key, account_data) = try!(item);
|
||||||
let account = Account::from_thin_rlp(account_data);
|
let account = Account::from_thin_rlp(account_data);
|
||||||
let account_key_hash = H256::from_slice(&account_key);
|
let account_key_hash = H256::from_slice(&account_key);
|
||||||
|
|
||||||
|
@ -27,7 +27,7 @@ use super::{ManifestData, StateRebuilder, BlockRebuilder, RestorationStatus, Sna
|
|||||||
use super::io::{SnapshotReader, LooseReader, SnapshotWriter, LooseWriter};
|
use super::io::{SnapshotReader, LooseReader, SnapshotWriter, LooseWriter};
|
||||||
|
|
||||||
use blockchain::BlockChain;
|
use blockchain::BlockChain;
|
||||||
use client::Client;
|
use client::{BlockChainClient, Client};
|
||||||
use engines::Engine;
|
use engines::Engine;
|
||||||
use error::Error;
|
use error::Error;
|
||||||
use ids::BlockID;
|
use ids::BlockID;
|
||||||
@ -345,7 +345,17 @@ impl Service {
|
|||||||
let res = client.take_snapshot(writer, BlockID::Number(num), &self.progress);
|
let res = client.take_snapshot(writer, BlockID::Number(num), &self.progress);
|
||||||
|
|
||||||
self.taking_snapshot.store(false, Ordering::SeqCst);
|
self.taking_snapshot.store(false, Ordering::SeqCst);
|
||||||
try!(res);
|
if let Err(e) = res {
|
||||||
|
if client.chain_info().best_block_number >= num + ::client::HISTORY {
|
||||||
|
// "Cancelled" is mincing words a bit -- what really happened
|
||||||
|
// is that the state we were snapshotting got pruned out
|
||||||
|
// before we could finish.
|
||||||
|
info!("Cancelled prematurely-started periodic snapshot.");
|
||||||
|
return Ok(())
|
||||||
|
} else {
|
||||||
|
return Err(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
info!("Finished taking snapshot at #{}", num);
|
info!("Finished taking snapshot at #{}", num);
|
||||||
|
|
||||||
|
@ -52,8 +52,9 @@ impl StateProducer {
|
|||||||
// modify existing accounts.
|
// modify existing accounts.
|
||||||
let mut accounts_to_modify: Vec<_> = {
|
let mut accounts_to_modify: Vec<_> = {
|
||||||
let trie = TrieDB::new(&*db, &self.state_root).unwrap();
|
let trie = TrieDB::new(&*db, &self.state_root).unwrap();
|
||||||
let temp = trie.iter() // binding required due to complicated lifetime stuff
|
let temp = trie.iter().unwrap() // binding required due to complicated lifetime stuff
|
||||||
.filter(|_| rng.gen::<f32>() < ACCOUNT_CHURN)
|
.filter(|_| rng.gen::<f32>() < ACCOUNT_CHURN)
|
||||||
|
.map(Result::unwrap)
|
||||||
.map(|(k, v)| (H256::from_slice(&k), v.to_owned()))
|
.map(|(k, v)| (H256::from_slice(&k), v.to_owned()))
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
|
@ -46,8 +46,8 @@ impl<'db> FatDB<'db> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'db> Trie for FatDB<'db> {
|
impl<'db> Trie for FatDB<'db> {
|
||||||
fn iter<'a>(&'a self) -> Box<Iterator<Item = TrieItem> + 'a> {
|
fn iter<'a>(&'a self) -> super::Result<Box<Iterator<Item = TrieItem> + 'a>> {
|
||||||
Box::new(FatDBIterator::new(&self.raw))
|
FatDBIterator::new(&self.raw).map(|iter| Box::new(iter) as Box<_>)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn root(&self) -> &H256 {
|
fn root(&self) -> &H256 {
|
||||||
@ -73,22 +73,24 @@ pub struct FatDBIterator<'db> {
|
|||||||
|
|
||||||
impl<'db> FatDBIterator<'db> {
|
impl<'db> FatDBIterator<'db> {
|
||||||
/// Creates new iterator.
|
/// Creates new iterator.
|
||||||
pub fn new(trie: &'db TrieDB) -> Self {
|
pub fn new(trie: &'db TrieDB) -> super::Result<Self> {
|
||||||
FatDBIterator {
|
Ok(FatDBIterator {
|
||||||
trie_iterator: TrieDBIterator::new(trie),
|
trie_iterator: try!(TrieDBIterator::new(trie)),
|
||||||
trie: trie,
|
trie: trie,
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'db> Iterator for FatDBIterator<'db> {
|
impl<'db> Iterator for FatDBIterator<'db> {
|
||||||
type Item = (Vec<u8>, &'db [u8]);
|
type Item = TrieItem<'db>;
|
||||||
|
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
self.trie_iterator.next()
|
self.trie_iterator.next()
|
||||||
.map(|(hash, value)| {
|
.map(|res|
|
||||||
|
res.map(|(hash, value)| {
|
||||||
(self.trie.db().get_aux(&hash).expect("Missing fatdb hash"), value)
|
(self.trie.db().get_aux(&hash).expect("Missing fatdb hash"), value)
|
||||||
})
|
})
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -105,5 +107,5 @@ fn fatdb_to_trie() {
|
|||||||
}
|
}
|
||||||
let t = FatDB::new(&memdb, &root).unwrap();
|
let t = FatDB::new(&memdb, &root).unwrap();
|
||||||
assert_eq!(t.get(&[0x01u8, 0x23]).unwrap().unwrap(), &[0x01u8, 0x23]);
|
assert_eq!(t.get(&[0x01u8, 0x23]).unwrap().unwrap(), &[0x01u8, 0x23]);
|
||||||
assert_eq!(t.iter().collect::<Vec<_>>(), vec![(vec![0x01u8, 0x23], &[0x01u8, 0x23] as &[u8])]);
|
assert_eq!(t.iter().unwrap().map(Result::unwrap).collect::<Vec<_>>(), vec![(vec![0x01u8, 0x23], &[0x01u8, 0x23] as &[u8])]);
|
||||||
}
|
}
|
||||||
|
@ -72,12 +72,12 @@ impl fmt::Display for TrieError {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Trie-Item type.
|
|
||||||
pub type TrieItem<'a> = (Vec<u8>, &'a [u8]);
|
|
||||||
|
|
||||||
/// Trie result type. Boxed to avoid copying around extra space for `H256`s on successful queries.
|
/// Trie result type. Boxed to avoid copying around extra space for `H256`s on successful queries.
|
||||||
pub type Result<T> = ::std::result::Result<T, Box<TrieError>>;
|
pub type Result<T> = ::std::result::Result<T, Box<TrieError>>;
|
||||||
|
|
||||||
|
/// Trie-Item type.
|
||||||
|
pub type TrieItem<'a> = Result<(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 {
|
||||||
/// Return the root of the trie.
|
/// Return the root of the trie.
|
||||||
@ -102,7 +102,7 @@ pub trait Trie {
|
|||||||
where 'a: 'b, R: Recorder;
|
where 'a: 'b, R: Recorder;
|
||||||
|
|
||||||
/// Returns an iterator over elements of trie.
|
/// Returns an iterator over elements of trie.
|
||||||
fn iter<'a>(&'a self) -> Box<Iterator<Item = TrieItem> + 'a>;
|
fn iter<'a>(&'a self) -> Result<Box<Iterator<Item = TrieItem> + 'a>>;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A key-value datastore implemented as a database-backed modified Merkle tree.
|
/// A key-value datastore implemented as a database-backed modified Merkle tree.
|
||||||
@ -193,7 +193,7 @@ impl<'db> Trie for TrieKinds<'db> {
|
|||||||
wrapper!(self, get_recorded, key, r)
|
wrapper!(self, get_recorded, key, r)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn iter<'a>(&'a self) -> Box<Iterator<Item = TrieItem> + 'a> {
|
fn iter<'a>(&'a self) -> Result<Box<Iterator<Item = TrieItem> + 'a>> {
|
||||||
wrapper!(self, iter,)
|
wrapper!(self, iter,)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -49,8 +49,8 @@ impl<'db> SecTrieDB<'db> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'db> Trie for SecTrieDB<'db> {
|
impl<'db> Trie for SecTrieDB<'db> {
|
||||||
fn iter<'a>(&'a self) -> Box<Iterator<Item = TrieItem> + 'a> {
|
fn iter<'a>(&'a self) -> super::Result<Box<Iterator<Item = TrieItem> + 'a>> {
|
||||||
Box::new(TrieDB::iter(&self.raw))
|
TrieDB::iter(&self.raw)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn root(&self) -> &H256 { self.raw.root() }
|
fn root(&self) -> &H256 { self.raw.root() }
|
||||||
|
@ -279,30 +279,38 @@ pub struct TrieDBIterator<'a> {
|
|||||||
|
|
||||||
impl<'a> TrieDBIterator<'a> {
|
impl<'a> TrieDBIterator<'a> {
|
||||||
/// Create a new iterator.
|
/// Create a new iterator.
|
||||||
pub fn new(db: &'a TrieDB) -> TrieDBIterator<'a> {
|
pub fn new(db: &'a TrieDB) -> super::Result<TrieDBIterator<'a>> {
|
||||||
let mut r = TrieDBIterator {
|
let mut r = TrieDBIterator {
|
||||||
db: db,
|
db: db,
|
||||||
trail: vec![],
|
trail: vec![],
|
||||||
key_nibbles: Vec::new(),
|
key_nibbles: Vec::new(),
|
||||||
};
|
};
|
||||||
r.descend(db.root_data(&mut NoOp).unwrap());
|
|
||||||
r
|
try!(db.root_data(&mut NoOp).and_then(|root| r.descend(root)));
|
||||||
|
Ok(r)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Descend into a payload.
|
/// Descend into a payload.
|
||||||
fn descend(&mut self, d: &'a [u8]) {
|
fn descend(&mut self, d: &'a [u8]) -> super::Result<()> {
|
||||||
self.trail.push(Crumb {
|
self.trail.push(Crumb {
|
||||||
status: Status::Entering,
|
status: Status::Entering,
|
||||||
node: self.db.get_node(d, &mut NoOp, 0).unwrap(),
|
node: try!(self.db.get_node(d, &mut NoOp, 0)),
|
||||||
});
|
});
|
||||||
match self.trail.last().unwrap().node {
|
match self.trail.last().unwrap().node {
|
||||||
Node::Leaf(n, _) | Node::Extension(n, _) => { self.key_nibbles.extend(n.iter()); },
|
Node::Leaf(n, _) | Node::Extension(n, _) => { self.key_nibbles.extend(n.iter()); },
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Descend into a payload and get the next item.
|
/// Descend into a payload and get the next item.
|
||||||
fn descend_next(&mut self, d: &'a [u8]) -> Option<(Bytes, &'a [u8])> { self.descend(d); self.next() }
|
fn descend_next(&mut self, d: &'a [u8]) -> Option<TrieItem<'a>> {
|
||||||
|
match self.descend(d) {
|
||||||
|
Ok(()) => self.next(),
|
||||||
|
Err(e) => Some(Err(e)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// The present key.
|
/// The present key.
|
||||||
fn key(&self) -> Bytes {
|
fn key(&self) -> Bytes {
|
||||||
@ -312,12 +320,12 @@ impl<'a> TrieDBIterator<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Iterator for TrieDBIterator<'a> {
|
impl<'a> Iterator for TrieDBIterator<'a> {
|
||||||
type Item = (Bytes, &'a [u8]);
|
type Item = TrieItem<'a>;
|
||||||
|
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
let b = match self.trail.last_mut() {
|
let b = match self.trail.last_mut() {
|
||||||
Some(mut b) => { b.increment(); b.clone() },
|
Some(mut b) => { b.increment(); b.clone() },
|
||||||
None => return None
|
None => return None,
|
||||||
};
|
};
|
||||||
match (b.status, b.node) {
|
match (b.status, b.node) {
|
||||||
(Status::Exiting, n) => {
|
(Status::Exiting, n) => {
|
||||||
@ -332,7 +340,7 @@ impl<'a> Iterator for TrieDBIterator<'a> {
|
|||||||
self.trail.pop();
|
self.trail.pop();
|
||||||
self.next()
|
self.next()
|
||||||
},
|
},
|
||||||
(Status::At, Node::Leaf(_, v)) | (Status::At, Node::Branch(_, Some(v))) => Some((self.key(), v)),
|
(Status::At, Node::Leaf(_, v)) | (Status::At, Node::Branch(_, Some(v))) => Some(Ok((self.key(), v))),
|
||||||
(Status::At, Node::Extension(_, d)) => self.descend_next(d),
|
(Status::At, Node::Extension(_, d)) => self.descend_next(d),
|
||||||
(Status::At, Node::Branch(_, _)) => self.next(),
|
(Status::At, Node::Branch(_, _)) => self.next(),
|
||||||
(Status::AtChild(i), Node::Branch(children, _)) if children[i].len() > 0 => {
|
(Status::AtChild(i), Node::Branch(children, _)) if children[i].len() > 0 => {
|
||||||
@ -352,8 +360,8 @@ impl<'a> Iterator for TrieDBIterator<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'db> Trie for TrieDB<'db> {
|
impl<'db> Trie for TrieDB<'db> {
|
||||||
fn iter<'a>(&'a self) -> Box<Iterator<Item = TrieItem> + 'a> {
|
fn iter<'a>(&'a self) -> super::Result<Box<Iterator<Item = TrieItem> + 'a>> {
|
||||||
Box::new(TrieDBIterator::new(self))
|
TrieDBIterator::new(self).map(|iter| Box::new(iter) as Box<_>)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn root(&self) -> &H256 { self.root }
|
fn root(&self) -> &H256 { self.root }
|
||||||
@ -392,6 +400,6 @@ fn iterator() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let t = TrieDB::new(&memdb, &root).unwrap();
|
let t = TrieDB::new(&memdb, &root).unwrap();
|
||||||
assert_eq!(d.iter().map(|i|i.to_vec()).collect::<Vec<_>>(), t.iter().map(|x|x.0).collect::<Vec<_>>());
|
assert_eq!(d.iter().map(|i|i.to_vec()).collect::<Vec<_>>(), t.iter().unwrap().map(|x| x.unwrap().0).collect::<Vec<_>>());
|
||||||
assert_eq!(d, t.iter().map(|x|x.1).collect::<Vec<_>>());
|
assert_eq!(d, t.iter().unwrap().map(|x| x.unwrap().1).collect::<Vec<_>>());
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user