mod allocator;
mod iter;
mod node;
use crate::engine::btreemap::iter::{IterInternal, KeysIter, ValuesIter};
use crate::engine::{
Memory, Storable,
storable::Bound as StorableBound,
types::{Address, NULL},
};
use allocator::Allocator;
pub use iter::{Iter, LazyEntry};
use node::{Entry, Node, NodeType, PageSize, Version};
use std::borrow::Cow;
use std::marker::PhantomData;
use std::ops::RangeBounds;
const MAGIC: &[u8; 3] = b"BTR";
const LAYOUT_VERSION_2: u8 = 2;
const PACKED_HEADER_SIZE: usize = 28;
const ALLOCATOR_OFFSET: usize = 52;
const DEFAULT_PAGE_SIZE: u32 = 1024;
const PAGE_SIZE_VALUE_MARKER: u32 = u32::MAX;
pub struct BTreeMap<K, V, M>
where
K: Storable + Ord + Clone,
V: Storable,
M: Memory,
{
root_addr: Address,
version: Version,
allocator: Allocator<M>,
length: u64,
_phantom: PhantomData<(K, V)>,
}
#[derive(PartialEq, Debug)]
struct BTreeHeader {
version: Version,
root_addr: Address,
length: u64,
}
impl<K, V, M> BTreeMap<K, V, M>
where
K: Storable + Ord + Clone,
V: Storable,
M: Memory,
{
pub fn new(memory: M) -> Self {
let page_size = match (K::BOUND, V::BOUND) {
(
StorableBound::Bounded {
max_size: max_key_size,
..
},
StorableBound::Bounded {
max_size: max_value_size,
..
},
) => {
let max_node_size = Node::<K>::max_size(max_key_size, max_value_size).get();
PageSize::Value(
u32::try_from(max_node_size * 3 / 4).expect("bounded node page size"),
)
}
_ => PageSize::Value(DEFAULT_PAGE_SIZE),
};
let btree = Self {
root_addr: NULL,
allocator: Allocator::new(
memory,
Address::from(ALLOCATOR_OFFSET as u64),
page_size.get().into(),
),
version: Version::V2(page_size),
length: 0,
_phantom: PhantomData,
};
btree.save_header();
btree
}
pub fn load(memory: M) -> Self {
let header = Self::read_header(&memory);
let allocator_addr = Address::from(ALLOCATOR_OFFSET as u64);
Self {
root_addr: header.root_addr,
allocator: Allocator::load(memory, allocator_addr),
version: header.version,
length: header.length,
_phantom: PhantomData,
}
}
fn read_header(memory: &M) -> BTreeHeader {
let mut buf = [0; PACKED_HEADER_SIZE];
memory.read(0, &mut buf);
assert_eq!(&buf[0..3], MAGIC, "Bad magic.");
match buf[3] {
LAYOUT_VERSION_2 => {
let page_size = {
let a = u32::from_le_bytes(buf[4..8].try_into().unwrap());
let b = u32::from_le_bytes(buf[8..12].try_into().unwrap());
assert_eq!(b, PAGE_SIZE_VALUE_MARKER, "Unsupported derived-page layout");
PageSize::Value(a)
};
BTreeHeader {
version: Version::V2(page_size),
root_addr: Address::from(u64::from_le_bytes(buf[12..20].try_into().unwrap())),
length: u64::from_le_bytes(buf[20..28].try_into().unwrap()),
}
}
version => {
panic!("Unsupported version: {version}.");
}
}
}
pub fn insert(&mut self, key: K, value: V) -> Option<V> {
let value = value.into_bytes_checked();
let root = if self.root_addr == NULL {
let node = self.allocate_node(NodeType::Leaf);
self.root_addr = node.address();
self.save_header();
node
} else {
let mut root = self.load_node(self.root_addr);
if let Ok(idx) = root.search(&key, self.memory()) {
return Some(V::from_bytes(Cow::Owned(
self.update_value(&mut root, idx, value),
)));
}
if root.is_full() {
let mut new_root = self.allocate_node(NodeType::Internal);
new_root.push_child(self.root_addr);
self.root_addr = new_root.address();
self.save_header();
self.split_child(&mut new_root, 0);
new_root
} else {
root
}
};
self.insert_nonfull(root, key, value)
.map(Cow::Owned)
.map(V::from_bytes)
}
fn insert_nonfull(&mut self, mut node: Node<K>, key: K, value: Vec<u8>) -> Option<Vec<u8>> {
assert!(!node.is_full());
match node.search(&key, self.memory()) {
Ok(idx) => {
Some(self.update_value(&mut node, idx, value))
}
Err(idx) => {
match node.node_type() {
NodeType::Leaf => {
node.insert_entry(idx, (key, value));
self.save_node(&mut node);
self.length += 1;
self.save_header();
None
}
NodeType::Internal => {
let mut child = self.load_node(node.child(idx));
if child.is_full() {
if let Ok(idx) = child.search(&key, self.memory()) {
return Some(self.update_value(&mut child, idx, value));
}
self.split_child(&mut node, idx);
let idx = node.search(&key, self.memory()).unwrap_or_else(|idx| idx);
child = self.load_node(node.child(idx));
}
assert!(!child.is_full());
self.insert_nonfull(child, key, value)
}
}
}
}
}
fn split_child(&mut self, node: &mut Node<K>, full_child_idx: usize) {
assert!(!node.is_full());
let mut full_child = self.load_node(node.child(full_child_idx));
assert!(full_child.is_full());
let mut sibling = self.allocate_node(full_child.node_type());
assert_eq!(sibling.node_type(), full_child.node_type());
node.insert_child(full_child_idx + 1, sibling.address());
let (median_key, median_value) = full_child.split(&mut sibling, self.memory());
node.insert_entry(full_child_idx, (median_key, median_value));
self.save_node(&mut sibling);
self.save_node(&mut full_child);
self.save_node(node);
}
pub fn get(&self, key: &K) -> Option<V> {
if self.root_addr == NULL {
return None;
}
self.traverse(self.root_addr, key, |node, idx| {
node.extract_entry_at(idx, self.memory()).1 })
.map(Cow::Owned)
.map(V::from_bytes)
}
pub fn contains_key(&self, key: &K) -> bool {
self.root_addr != NULL && self.traverse(self.root_addr, key, |_, _| ()).is_some()
}
fn traverse<F, R>(&self, node_addr: Address, key: &K, f: F) -> Option<R>
where
F: Fn(&mut Node<K>, usize) -> R,
{
let mut node = self.load_node(node_addr);
match node.search(key, self.memory()) {
Ok(idx) => Some(f(&mut node, idx)), Err(idx) => match node.node_type() {
NodeType::Leaf => None, NodeType::Internal => self.traverse(node.child(idx), key, f), },
}
}
pub const fn is_empty(&self) -> bool {
self.length == 0
}
pub const fn len(&self) -> u64 {
self.length
}
pub fn clear_new(&mut self) {
self.root_addr = NULL;
self.length = 0;
self.allocator.clear();
self.save_header();
}
pub fn first_key_value(&self) -> Option<(K, V)> {
if self.root_addr == NULL {
return None;
}
let root = self.load_node(self.root_addr);
let (k, encoded_v) = root.get_min(self.memory());
Some((k, V::from_bytes(Cow::Owned(encoded_v))))
}
pub fn last_key_value(&self) -> Option<(K, V)> {
if self.root_addr == NULL {
return None;
}
let root = self.load_node(self.root_addr);
let (k, encoded_v) = root.get_max(self.memory());
Some((k, V::from_bytes(Cow::Owned(encoded_v))))
}
pub(crate) const fn memory(&self) -> &M {
self.allocator.memory()
}
const fn allocator_mut(&mut self) -> &mut Allocator<M> {
&mut self.allocator
}
pub fn remove(&mut self, key: &K) -> Option<V> {
if self.root_addr == NULL {
return None;
}
let root_node = self.load_node(self.root_addr);
self.remove_helper(root_node, key)
.map(Cow::Owned)
.map(V::from_bytes)
}
#[expect(
clippy::too_many_lines,
reason = "Keep the upstream deletion algorithm intact for the baseline"
)]
fn remove_helper(&mut self, mut node: Node<K>, key: &K) -> Option<Vec<u8>> {
if node.address() != self.root_addr {
assert!(node.can_remove_entry_without_merging());
}
match node.node_type() {
NodeType::Leaf => {
match node.search(key, self.memory()) {
Ok(idx) => {
let value = node.remove_entry(idx, self.memory()).1;
self.length -= 1;
if node.entries_len() == 0 {
assert_eq!(
node.address(),
self.root_addr,
"Removal can only result in an empty leaf node if that node is the root"
);
self.deallocate_node(node);
self.root_addr = NULL;
} else {
self.save_node(&mut node);
}
self.save_header();
Some(value)
}
_ => None, }
}
NodeType::Internal => {
match node.search(key, self.memory()) {
Ok(idx) => {
let left_child = self.load_node(node.child(idx));
if left_child.can_remove_entry_without_merging() {
let predecessor = left_child.get_max(self.memory());
self.remove_helper(left_child, &predecessor.0)?;
let (_, old_value) = node.swap_entry(idx, predecessor, self.memory());
self.save_node(&mut node);
return Some(old_value);
}
let right_child = self.load_node(node.child(idx + 1));
if right_child.can_remove_entry_without_merging() {
let successor = right_child.get_min(self.memory());
self.remove_helper(right_child, &successor.0)?;
let (_, old_value) = node.swap_entry(idx, successor, self.memory());
self.save_node(&mut node);
return Some(old_value);
}
assert!(left_child.at_minimum());
assert!(right_child.at_minimum());
let mut new_child = self.merge(
right_child,
left_child,
node.remove_entry(idx, self.memory()),
);
node.remove_child(idx + 1);
if node.entries_len() == 0 {
assert_eq!(node.address(), self.root_addr);
assert_eq!(node.child(0), new_child.address());
assert_eq!(node.children_len(), 1);
self.root_addr = new_child.address();
self.deallocate_node(node);
self.save_header();
} else {
self.save_node(&mut node);
}
self.save_node(&mut new_child);
self.remove_helper(new_child, key)
}
Err(idx) => {
let mut child = self.load_node(node.child(idx));
if child.can_remove_entry_without_merging() {
return self.remove_helper(child, key);
}
let mut left_sibling = if idx > 0 {
Some(self.load_node(node.child(idx - 1)))
} else {
None
};
let mut right_sibling = if idx + 1 < node.children_len() {
Some(self.load_node(node.child(idx + 1)))
} else {
None
};
if let Some(ref mut left_sibling) = left_sibling
&& left_sibling.can_remove_entry_without_merging()
{
let (left_sibling_key, left_sibling_value) =
left_sibling.pop_entry(self.memory()).unwrap();
let (parent_key, parent_value) = node.swap_entry(
idx - 1,
(left_sibling_key, left_sibling_value),
self.memory(),
);
child.insert_entry(0, (parent_key, parent_value));
if let Some(last_child) = left_sibling.pop_child() {
assert_eq!(left_sibling.node_type(), NodeType::Internal);
assert_eq!(child.node_type(), NodeType::Internal);
child.insert_child(0, last_child);
} else {
assert_eq!(left_sibling.node_type(), NodeType::Leaf);
assert_eq!(child.node_type(), NodeType::Leaf);
}
self.save_node(left_sibling);
self.save_node(&mut child);
self.save_node(&mut node);
return self.remove_helper(child, key);
}
if let Some(right_sibling) = &mut right_sibling
&& right_sibling.can_remove_entry_without_merging()
{
let (right_sibling_key, right_sibling_value) =
right_sibling.remove_entry(0, self.memory());
let parent_entry = node.swap_entry(
idx,
(right_sibling_key, right_sibling_value),
self.memory(),
);
child.push_entry(parent_entry);
match right_sibling.node_type() {
NodeType::Internal => {
assert_eq!(child.node_type(), NodeType::Internal);
child.push_child(right_sibling.remove_child(0));
}
NodeType::Leaf => {
assert_eq!(child.node_type(), NodeType::Leaf);
}
}
self.save_node(right_sibling);
self.save_node(&mut child);
self.save_node(&mut node);
return self.remove_helper(child, key);
}
if let Some(left_sibling) = left_sibling {
assert!(left_sibling.at_minimum());
let left_sibling = self.merge(
child,
left_sibling,
node.remove_entry(idx - 1, self.memory()),
);
node.remove_child(idx);
if node.entries_len() == 0 {
let node_address = node.address();
self.deallocate_node(node);
if node_address == self.root_addr {
self.root_addr = left_sibling.address();
self.save_header();
}
} else {
self.save_node(&mut node);
}
return self.remove_helper(left_sibling, key);
}
if let Some(right_sibling) = right_sibling {
assert!(right_sibling.at_minimum());
let right_sibling = self.merge(
child,
right_sibling,
node.remove_entry(idx, self.memory()),
);
node.remove_child(idx);
if node.entries_len() == 0 {
let node_address = node.address();
self.deallocate_node(node);
if node_address == self.root_addr {
self.root_addr = right_sibling.address();
self.save_header();
}
} else {
self.save_node(&mut node);
}
return self.remove_helper(right_sibling, key);
}
unreachable!("At least one of the siblings must exist.");
}
}
}
}
}
pub fn iter(&self) -> Iter<'_, K, V, M> {
self.iter_internal().into()
}
pub fn range(&self, key_range: impl RangeBounds<K>) -> Iter<'_, K, V, M> {
self.range_internal(key_range).into()
}
pub fn keys(&self) -> KeysIter<'_, K, V, M> {
self.iter_internal().into()
}
pub fn keys_range(&self, key_range: impl RangeBounds<K>) -> KeysIter<'_, K, V, M> {
self.range_internal(key_range).into()
}
pub fn values(&self) -> ValuesIter<'_, K, V, M> {
self.iter_internal().into()
}
const fn iter_internal(&self) -> IterInternal<'_, K, V, M> {
IterInternal::new(self)
}
fn range_internal(&self, key_range: impl RangeBounds<K>) -> IterInternal<'_, K, V, M> {
if self.root_addr == NULL {
return IterInternal::null(self);
}
let range = (
key_range.start_bound().cloned(),
key_range.end_bound().cloned(),
);
IterInternal::new_in_range(self, range)
}
fn merge(&mut self, source: Node<K>, mut into: Node<K>, median: Entry<K>) -> Node<K> {
into.merge(source, median, &mut self.allocator);
into
}
fn allocate_node(&mut self, node_type: NodeType) -> Node<K> {
match self.version {
Version::V2(page_size) => Node::new_v2(self.allocator.allocate(), node_type, page_size),
}
}
#[inline]
fn deallocate_node(&mut self, node: Node<K>) {
node.deallocate(self.allocator_mut());
}
#[inline]
fn load_node(&self, address: Address) -> Node<K> {
Node::load(address, self.version.page_size(), self.memory())
}
#[inline]
fn save_node(&mut self, node: &mut Node<K>) {
node.save(self.allocator_mut());
}
fn update_value(&mut self, node: &mut Node<K>, idx: usize, new_value: Vec<u8>) -> Vec<u8> {
let old_value = node.swap_value(idx, new_value, self.memory());
self.save_node(node);
old_value
}
fn save_header(&self) {
let header = BTreeHeader {
version: self.version,
root_addr: self.root_addr,
length: self.length,
};
Self::write_header(&header, self.memory());
}
fn write_header(header: &BTreeHeader, memory: &M) {
let mut buf = [0; PACKED_HEADER_SIZE];
buf[0..3].copy_from_slice(MAGIC.as_slice());
match header.version {
Version::V2(PageSize::Value(page_size)) => {
buf[3] = LAYOUT_VERSION_2;
buf[4..8].copy_from_slice(&page_size.to_le_bytes());
buf[8..12].copy_from_slice(&PAGE_SIZE_VALUE_MARKER.to_le_bytes());
}
}
buf[12..20].copy_from_slice(&header.root_addr.get().to_le_bytes());
buf[20..28].copy_from_slice(&header.length.to_le_bytes());
crate::engine::write(memory, 0, &buf);
}
}