#![forbid(unsafe_code)]
pub mod delete;
pub mod insert;
pub mod node;
pub mod range;
pub use crate::btree::range::{RangeIter, SnapshotRangeIter};
use crate::error::{Error, Result};
use crate::pager::page::PageId;
use crate::pager::Pager;
use crate::platform::{FileBackend, FileHandle};
use heapless::Vec as HeaplessVec;
pub const MAX_BTREE_DEPTH: usize = 32;
pub const MAX_RANGE_NODES: usize = 1_000_000;
pub use crate::btree::node::{
decode_node, encode_node, max_inline_value, max_key_len, validate_node, ChildEntry,
DecodedNode, InternalEntry, LeafEntry, NodeKind, NODE_HEADER_SIZE,
};
#[derive(Debug)]
pub struct BTree<F: FileBackend = FileHandle> {
root: PageId,
_phantom: std::marker::PhantomData<fn() -> F>,
}
impl<F: FileBackend> BTree<F> {
pub fn open(_pager: &Pager<F>, root: PageId) -> Result<Self> {
Ok(Self {
root,
_phantom: std::marker::PhantomData,
})
}
pub fn empty(pager: &mut Pager<F>) -> Result<Self> {
let root = pager.alloc_page()?;
let mut page = crate::pager::page::Page::zeroed();
encode_node(
&DecodedNode {
kind: NodeKind::Leaf,
level: 0,
next_sibling: 0,
children: Vec::new(),
leaves: Vec::new(),
internals: Vec::new(),
},
&mut page,
)?;
pager.write_page(root, &page)?;
Ok(Self {
root,
_phantom: std::marker::PhantomData,
})
}
#[must_use]
pub fn root(&self) -> PageId {
self.root
}
pub fn get(&self, pager: &mut Pager<F>, key: &[u8]) -> Result<Option<Vec<u8>>> {
let leaf_id = descend_to_leaf(pager, self.root, key)?;
let page_ref = pager.read_page(leaf_id)?;
node::decode_node_find(page_ref.as_bytes(), key)
}
pub fn get_via_snapshot(
pager: &Pager<F>,
snapshot: &crate::pager::ReaderSnapshot<F>,
root: PageId,
key: &[u8],
) -> Result<Option<Vec<u8>>> {
let mut path: HeaplessVec<PageId, MAX_BTREE_DEPTH> = HeaplessVec::new();
let mut current = root;
loop {
if path.push(current).is_err() {
return Err(Error::BTreeDepthExceeded {
limit: MAX_BTREE_DEPTH,
});
}
let page = snapshot.read_page(pager, current)?;
match node::peek_node_kind(page.as_bytes())? {
NodeKind::Leaf => return node::decode_node_find(page.as_bytes(), key),
NodeKind::Internal => {
let decoded = decode_node(page.as_bytes())?;
current = choose_child(&decoded, key)?;
}
}
}
}
}
pub(crate) fn descend_to_leaf<F: FileBackend>(
pager: &mut Pager<F>,
root: PageId,
key: &[u8],
) -> Result<PageId> {
let mut path: HeaplessVec<PageId, MAX_BTREE_DEPTH> = HeaplessVec::new();
let mut current = root;
loop {
if path.push(current).is_err() {
return Err(Error::BTreeDepthExceeded {
limit: MAX_BTREE_DEPTH,
});
}
let page_ref = pager.read_page(current)?;
let decoded = decode_node(page_ref.as_bytes())?;
match decoded.kind {
NodeKind::Leaf => return Ok(current),
NodeKind::Internal => {
current = choose_child(&decoded, key)?;
}
}
}
}
pub(crate) fn choose_child(node: &DecodedNode, key: &[u8]) -> Result<PageId> {
debug_assert!(matches!(node.kind, NodeKind::Internal));
debug_assert_eq!(node.children.len(), node.internals.len() + 1);
if node.children.is_empty() {
return Err(Error::BTreeInvariantViolated {
reason: "internal node with zero children",
});
}
let mut idx = node.internals.len();
for (i, pivot) in node.internals.iter().enumerate() {
if pivot.key.as_slice() > key {
idx = i;
break;
}
}
let raw = node.children[idx];
PageId::new(raw).ok_or(Error::BTreeInvariantViolated {
reason: "internal node had zero child page-id",
})
}
#[cfg(test)]
mod tests;