Optimize trie iter by avoiding redundant copying

This commit is contained in:
debris 2017-08-21 18:35:39 +02:00
parent 6f03c2bfd1
commit 6c00dc71c1

View File

@ -275,9 +275,15 @@ impl<'a> TrieDBIterator<'a> {
/// Descend into a payload. /// Descend into a payload.
fn descend(&mut self, d: &[u8]) -> super::Result<()> { fn descend(&mut self, d: &[u8]) -> super::Result<()> {
let node = Node::decoded(&self.db.get_raw_or_lookup(d)?).into();
Ok(self.descend_into_node(node))
}
/// Descend into a payload.
fn descend_into_node(&mut self, node: OwnedNode) {
self.trail.push(Crumb { self.trail.push(Crumb {
status: Status::Entering, status: Status::Entering,
node: Node::decoded(&self.db.get_raw_or_lookup(d)?).into(), node: node,
}); });
match &self.trail.last().expect("just pushed item; qed").node { match &self.trail.last().expect("just pushed item; qed").node {
&OwnedNode::Leaf(ref n, _) | &OwnedNode::Extension(ref n, _) => { &OwnedNode::Leaf(ref n, _) | &OwnedNode::Extension(ref n, _) => {
@ -285,8 +291,6 @@ impl<'a> TrieDBIterator<'a> {
}, },
_ => {} _ => {}
} }
Ok(())
} }
/// The present key. /// The present key.
@ -318,53 +322,68 @@ impl<'a> Iterator for TrieDBIterator<'a> {
type Item = TrieItem<'a>; type Item = TrieItem<'a>;
fn next(&mut self) -> Option<Self::Item> { fn next(&mut self) -> Option<Self::Item> {
enum IterStep {
Continue,
PopTrail,
Descend(super::Result<DBValue>),
}
loop { loop {
let b = match self.trail.last_mut() { let iter_step = {
Some(mut b) => { b.increment(); b.clone() }, match self.trail.last_mut() {
Some(b) => { b.increment(); },
None => return None, None => return None,
}; }
match (b.status, b.node) {
let b = self.trail.last().expect("trail.last_mut().is_some(); qed");
match (b.status.clone(), &b.node) {
(Status::Exiting, n) => { (Status::Exiting, n) => {
match n { match *n {
OwnedNode::Leaf(n, _) | OwnedNode::Extension(n, _) => { OwnedNode::Leaf(ref n, _) | OwnedNode::Extension(ref n, _) => {
let l = self.key_nibbles.len(); let l = self.key_nibbles.len();
self.key_nibbles.truncate(l - n.len()); self.key_nibbles.truncate(l - n.len());
}, },
OwnedNode::Branch(_, _) => { self.key_nibbles.pop(); }, OwnedNode::Branch(_, _) => { self.key_nibbles.pop(); },
_ => {} _ => {}
} }
self.trail.pop(); IterStep::PopTrail
// continue
}, },
(Status::At, OwnedNode::Leaf(_, v)) | (Status::At, OwnedNode::Branch(_, Some(v))) => { (Status::At, &OwnedNode::Leaf(_, ref v)) | (Status::At, &OwnedNode::Branch(_, Some(ref v))) => {
return Some(Ok((self.key(), v))); return Some(Ok((self.key(), v.clone())));
}, },
(Status::At, OwnedNode::Extension(_, d)) => { (Status::At, &OwnedNode::Extension(_, ref d)) => IterStep::Descend(self.db.get_raw_or_lookup(&*d)),
if let Err(e) = self.descend(&*d) { (Status::At, &OwnedNode::Branch(_, _)) => IterStep::Continue,
return Some(Err(e)); (Status::AtChild(i), &OwnedNode::Branch(ref children, _)) if children[i].len() > 0 => {
}
// continue
},
(Status::At, OwnedNode::Branch(_, _)) => {},
(Status::AtChild(i), OwnedNode::Branch(ref children, _)) if children[i].len() > 0 => {
match i { match i {
0 => self.key_nibbles.push(0), 0 => self.key_nibbles.push(0),
i => *self.key_nibbles.last_mut() i => *self.key_nibbles.last_mut()
.expect("pushed as 0; moves sequentially; removed afterwards; qed") = i as u8, .expect("pushed as 0; moves sequentially; removed afterwards; qed") = i as u8,
} }
if let Err(e) = self.descend(&*children[i]) { IterStep::Descend(self.db.get_raw_or_lookup(&*children[i]))
return Some(Err(e));
}
// continue
}, },
(Status::AtChild(i), OwnedNode::Branch(_, _)) => { (Status::AtChild(i), &OwnedNode::Branch(_, _)) => {
if i == 0 { if i == 0 {
self.key_nibbles.push(0); self.key_nibbles.push(0);
} }
// continue IterStep::Continue
}, },
_ => panic!() // Should never see Entering or AtChild without a Branch here. _ => panic!() // Should never see Entering or AtChild without a Branch here.
} }
};
match iter_step {
IterStep::PopTrail => {
self.trail.pop();
},
IterStep::Descend(Ok(d)) => {
self.descend_into_node(Node::decoded(&d).into())
},
IterStep::Descend(Err(e)) => {
return Some(Err(e))
}
IterStep::Continue => {},
}
} }
} }
} }