use crate::bplustree::NodeView;
use crate::bplustree::node_view::NodeId;
use crate::bplustree::tree::TreeError;
use crate::storage::NodeStorage;
use crate::storage::epoch::{EpochManager, ReaderGuard};
use std::sync::Arc;
struct TraversalFrame {
node_id: NodeId,
child_index: usize,
}
pub struct BPlusTreeIter<'a, S: NodeStorage> {
storage: &'a S,
stack: Vec<TraversalFrame>,
leaf: Option<NodeView>,
pos: usize,
end: Option<Vec<u8>>,
done: bool,
_guard: ReaderGuard,
}
impl<'a, S: NodeStorage> BPlusTreeIter<'a, S> {
pub fn new(
storage: &'a S,
root_id: NodeId,
epoch_mgr: &Arc<EpochManager>,
start: &[u8],
end: Option<&[u8]>,
) -> Result<Self, TreeError> {
let guard = epoch_mgr.pin();
let mut iter = Self {
storage,
stack: Vec::new(),
leaf: None,
pos: 0,
end: end.map(|e| e.to_vec()),
done: false,
_guard: guard,
};
iter.seek_to_start(root_id, start)?;
Ok(iter)
}
fn seek_to_start(&mut self, node_id: NodeId, start: &[u8]) -> Result<(), TreeError> {
let mut current_id = node_id;
loop {
let node = self
.storage
.read_node_view(current_id)?
.ok_or(TreeError::Invariant("node not found during range scan"))?;
if node.is_internal() {
let child_idx = match node.lower_bound(start) {
Ok(i) => i + 1,
Err(i) => i,
};
self.stack.push(TraversalFrame {
node_id: current_id,
child_index: child_idx,
});
current_id = node.child_ptr_at(child_idx)?;
} else {
let pos = match node.lower_bound(start) {
Ok(i) => i,
Err(i) => i,
};
if pos < node.keys_len() {
self.leaf = Some(node);
self.pos = pos;
} else {
self.advance_leaf()?;
}
return Ok(());
}
}
}
fn advance_leaf(&mut self) -> Result<(), TreeError> {
self.leaf = None;
loop {
let frame = match self.stack.pop() {
Some(f) => f,
None => {
self.done = true;
return Ok(());
}
};
let node = self
.storage
.read_node_view(frame.node_id)?
.ok_or(TreeError::Invariant("parent not found during range scan"))?;
let next_child = frame.child_index + 1;
let num_children = node.keys_len() + 1;
if next_child < num_children {
self.stack.push(TraversalFrame {
node_id: frame.node_id,
child_index: next_child,
});
let child_id = node.child_ptr_at(next_child)?;
self.descend_leftmost(child_id)?;
return Ok(());
}
}
}
fn descend_leftmost(&mut self, node_id: NodeId) -> Result<(), TreeError> {
let mut current_id = node_id;
loop {
let node = self
.storage
.read_node_view(current_id)?
.ok_or(TreeError::Invariant("node not found during range scan"))?;
if node.is_internal() {
self.stack.push(TraversalFrame {
node_id: current_id,
child_index: 0,
});
current_id = node.child_ptr_at(0)?;
} else {
if node.keys_len() > 0 {
self.leaf = Some(node);
self.pos = 0;
} else {
self.advance_leaf()?;
}
return Ok(());
}
}
}
}
impl<'a, S: NodeStorage> Iterator for BPlusTreeIter<'a, S> {
type Item = Result<(Vec<u8>, Vec<u8>), TreeError>;
fn next(&mut self) -> Option<Self::Item> {
if self.done {
return None;
}
let leaf = self.leaf.as_ref()?;
let key = match leaf.key_at(self.pos) {
Ok(k) => k,
Err(e) => return Some(Err(e.into())),
};
if let Some(end) = &self.end {
if key.as_slice() >= end.as_slice() {
self.done = true;
return None;
}
}
let value = match leaf.value_at(self.pos) {
Ok(v) => v,
Err(e) => return Some(Err(e.into())),
};
self.pos += 1;
if self.pos >= leaf.keys_len() {
if let Err(_e) = self.advance_leaf() {
self.done = true;
}
}
Some(Ok((key, value)))
}
}