mod allocator;
mod iter;
mod node;
use crate::btreemap::iter::{IterInternal, KeysIter, ValuesIter};
use crate::{
storable::Bound as StorableBound,
types::{Address, NULL},
Memory, Storable,
};
use allocator::Allocator;
pub use iter::Iter;
use node::{DerivedPageSize, Entry, Node, NodeType, PageSize, Version};
use std::borrow::Cow;
use std::marker::PhantomData;
use std::ops::{Bound, RangeBounds};
#[cfg(test)]
mod proptests;
const MAGIC: &[u8; 3] = b"BTR";
const LAYOUT_VERSION: u8 = 1;
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 init(memory: M) -> Self {
if memory.size() == 0 {
return BTreeMap::new(memory);
}
let mut dst = vec![0; 3];
memory.read(0, &mut dst);
if dst != MAGIC {
BTreeMap::new(memory)
} else {
BTreeMap::load(memory)
}
}
#[cfg(test)]
pub fn init_v1(memory: M) -> Self {
if memory.size() == 0 {
return BTreeMap::new_v1(memory);
}
let mut dst = vec![0; 3];
memory.read(0, &mut dst);
if dst != MAGIC {
BTreeMap::new_v1(memory)
} else {
BTreeMap::load_helper(memory, false)
}
}
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((max_node_size * 3 / 4) as u32)
}
_ => 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
}
#[cfg(test)]
pub fn new_v1(memory: M) -> Self {
let max_key_size = K::BOUND.max_size();
let max_value_size = V::BOUND.max_size();
let btree = Self {
root_addr: NULL,
allocator: Allocator::new(
memory,
Address::from(ALLOCATOR_OFFSET as u64),
Node::<K>::max_size(max_key_size, max_value_size),
),
version: Version::V1(DerivedPageSize {
max_key_size,
max_value_size,
}),
length: 0,
_phantom: PhantomData,
};
btree.save_header();
btree
}
pub fn load(memory: M) -> Self {
Self::load_helper(memory, true)
}
fn load_helper(memory: M, migrate_to_v2: bool) -> Self {
let header = Self::read_header(&memory);
let version = match header.version {
Version::V1(derived_page_size) => {
if migrate_to_v2 {
Version::V2(PageSize::Derived(derived_page_size))
} else {
let max_key_size = derived_page_size.max_key_size;
let max_value_size = derived_page_size.max_value_size;
assert!(
K::BOUND.max_size() <= max_key_size,
"max_key_size must be <= {max_key_size}",
);
assert!(
V::BOUND.max_size() <= max_value_size,
"max_value_size must be <= {max_value_size}"
);
Version::V1(derived_page_size)
}
}
other => other,
};
let allocator_addr = Address::from(ALLOCATOR_OFFSET as u64);
Self {
root_addr: header.root_addr,
allocator: Allocator::load(memory, allocator_addr),
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 => {
BTreeHeader {
version: Version::V1(DerivedPageSize {
max_key_size: u32::from_le_bytes(buf[4..8].try_into().unwrap()),
max_value_size: u32::from_le_bytes(buf[8..12].try_into().unwrap()),
}),
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()),
}
}
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());
if b == PAGE_SIZE_VALUE_MARKER {
PageSize::Value(a)
} else {
PageSize::Derived(DerivedPageSize {
max_key_size: a,
max_value_size: b,
})
}
};
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 fn is_empty(&self) -> bool {
self.length == 0
}
pub fn len(&self) -> u64 {
self.length
}
pub fn into_memory(self) -> M {
self.allocator.into_memory()
}
#[deprecated(since = "0.6.3", note = "please use `clear_new` instead")]
pub fn clear(self) -> Self {
let mem = self.allocator.into_memory();
Self::new(mem)
}
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))))
}
fn memory(&self) -> &M {
self.allocator.memory()
}
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)
}
pub fn pop_last(&mut self) -> Option<(K, V)> {
if self.root_addr == NULL {
return None;
}
let root = self.load_node(self.root_addr);
let (max_key, _) = root.get_max(self.memory());
self.remove_helper(root, &max_key)
.map(|v| (max_key, V::from_bytes(Cow::Owned(v))))
}
pub fn pop_first(&mut self) -> Option<(K, V)> {
if self.root_addr == NULL {
return None;
}
let root = self.load_node(self.root_addr);
let (min_key, _) = root.get_min(self.memory());
self.remove_helper(root, &min_key)
.map(|v| (min_key, V::from_bytes(Cow::Owned(v))))
}
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 {
if 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 {
if 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 iter_from_prev_key(&self, bound: &K) -> Iter<'_, K, V, M> {
if let Some(entry) = self.range(..bound).next_back() {
let start_key = entry.key().clone();
IterInternal::new_in_range(self, (Bound::Included(start_key), Bound::Unbounded)).into()
} else {
IterInternal::null(self).into()
}
}
#[deprecated(note = "use `iter_from_prev_key` instead")]
pub fn iter_upper_bound(&self, bound: &K) -> Iter<'_, K, V, M> {
self.iter_from_prev_key(bound)
}
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()
}
pub fn values_range(&self, key_range: impl RangeBounds<K>) -> ValuesIter<'_, K, V, M> {
self.range_internal(key_range).into()
}
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::V1(page_size) => Node::new_v1(self.allocator.allocate(), node_type, page_size),
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::V1(DerivedPageSize {
max_key_size,
max_value_size,
})
| Version::V2(PageSize::Derived(DerivedPageSize {
max_key_size,
max_value_size,
})) => {
buf[3] = LAYOUT_VERSION;
buf[4..8].copy_from_slice(&max_key_size.to_le_bytes());
buf[8..12].copy_from_slice(&max_value_size.to_le_bytes());
}
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::write(memory, 0, &buf);
}
}
#[cfg(test)]
mod test {
use super::*;
use crate::{
btreemap::iter::LazyEntry,
storable::{Blob, Bound as StorableBound},
VectorMemory,
};
use std::cell::RefCell;
use std::convert::TryFrom;
use std::rc::Rc;
fn collect_kv<'a, K: Clone + 'a, V: Clone + 'a>(
iter: impl Iterator<Item = (&'a K, &'a V)>,
) -> Vec<(K, V)> {
iter.map(|(k, v)| (k.clone(), v.clone())).collect()
}
fn collect<K: Clone, V: Clone>(it: impl Iterator<Item = (K, V)>) -> Vec<(K, V)> {
it.collect()
}
fn collect_entry<'a, K, V, M>(it: impl Iterator<Item = LazyEntry<'a, K, V, M>>) -> Vec<(K, V)>
where
K: Storable + Ord + Clone + 'a,
V: Storable + 'a,
M: Memory + 'a,
{
it.map(|entry| entry.into_pair()).collect()
}
fn monotonic_buffer<const N: usize>(i: u32) -> [u8; N] {
let mut buf = [0u8; N];
let bytes = i.to_be_bytes();
buf[N - bytes.len()..].copy_from_slice(&bytes);
buf
}
#[test]
fn test_monotonic_buffer() {
let cases: &[(u32, [u8; 4])] = &[
(1, [0, 0, 0, 1]),
(2, [0, 0, 0, 2]),
((1 << 8) - 1, [0, 0, 0, 255]),
((1 << 8), [0, 0, 1, 0]),
((1 << 16) - 1, [0, 0, 255, 255]),
(1 << 16, [0, 1, 0, 0]),
((1 << 24) - 1, [0, 255, 255, 255]),
(1 << 24, [1, 0, 0, 0]),
];
for &(input, expected) in cases {
let output = monotonic_buffer::<4>(input);
assert_eq!(
output, expected,
"monotonic_buffer::<4>({}) returned {:?}, expected {:?}",
input, output, expected
);
}
}
trait Builder {
fn build(i: u32) -> Self;
fn empty() -> Self;
}
impl Builder for () {
fn build(_i: u32) -> Self {}
fn empty() -> Self {}
}
impl Builder for u32 {
fn build(i: u32) -> Self {
i
}
fn empty() -> Self {
0
}
}
impl<const N: usize> Builder for Blob<N> {
fn build(i: u32) -> Self {
Blob::try_from(&monotonic_buffer::<N>(i)[..]).unwrap()
}
fn empty() -> Self {
Blob::try_from(&[][..]).unwrap()
}
}
type MonotonicVec32 = Vec<u8>;
impl Builder for MonotonicVec32 {
fn build(i: u32) -> Self {
monotonic_buffer::<32>(i).to_vec()
}
fn empty() -> Self {
Vec::new()
}
}
type MonotonicString32 = String;
impl Builder for MonotonicString32 {
fn build(i: u32) -> Self {
format!("{i:0>32}")
}
fn empty() -> Self {
String::new()
}
}
fn encode<T: Storable>(object: T) -> Vec<u8> {
object.into_bytes_checked()
}
pub(crate) fn b(x: &[u8]) -> Blob<10> {
Blob::<10>::try_from(x).unwrap()
}
pub(crate) fn make_memory() -> Rc<RefCell<Vec<u8>>> {
Rc::new(RefCell::new(Vec::new()))
}
pub fn run_btree_test<K, V, R, F>(f: F)
where
K: Storable + Ord + Clone,
V: Storable,
F: Fn(BTreeMap<K, V, VectorMemory>) -> R,
{
if K::BOUND != StorableBound::Unbounded && V::BOUND != StorableBound::Unbounded {
let mem = make_memory();
let tree_v1 = BTreeMap::new_v1(mem);
f(tree_v1);
let mem = make_memory();
let tree_v1: BTreeMap<K, V, _> = BTreeMap::new_v1(mem);
let tree_v2_migrated = BTreeMap::load_helper(tree_v1.into_memory(), true);
f(tree_v2_migrated);
}
let mem = make_memory();
let tree_v2 = BTreeMap::new(mem);
f(tree_v2);
}
fn verify_monotonic<T: Builder + PartialOrd>() {
for shift_bits in [8, 16, 24] {
let i = (1 << shift_bits) - 1;
assert!(
T::build(i) < T::build(i + 1),
"Monotonicity failed at i: {i}",
);
}
}
macro_rules! assert_bounded {
($ty:ty) => {
assert_ne!(<$ty>::BOUND, StorableBound::Unbounded, "Must be Bounded");
};
}
macro_rules! assert_unbounded {
($ty:ty) => {
assert_eq!(<$ty>::BOUND, StorableBound::Unbounded, "Must be Unbounded");
};
}
macro_rules! run_with_key {
($runner:ident, $K:ty) => {{
verify_monotonic::<$K>();
$runner::<$K, ()>();
assert_bounded!(u32);
$runner::<$K, u32>();
assert_bounded!(Blob<20>);
$runner::<$K, Blob<20>>();
assert_unbounded!(MonotonicVec32);
$runner::<$K, MonotonicVec32>();
assert_unbounded!(MonotonicString32);
$runner::<$K, MonotonicString32>();
}};
}
macro_rules! btree_test {
($name:ident, $runner:ident) => {
#[test]
fn $name() {
assert_bounded!(u32);
run_with_key!($runner, u32);
assert_bounded!(Blob<10>);
run_with_key!($runner, Blob<10>);
assert_unbounded!(MonotonicVec32);
run_with_key!($runner, MonotonicVec32);
assert_unbounded!(MonotonicString32);
run_with_key!($runner, MonotonicString32);
}
};
}
trait TestKey: Storable + Ord + Clone + Builder + std::fmt::Debug {}
impl<T> TestKey for T where T: Storable + Ord + Clone + Builder + std::fmt::Debug {}
trait TestValue: Storable + Clone + Builder + std::fmt::Debug + PartialEq {}
impl<T> TestValue for T where T: Storable + Clone + Builder + std::fmt::Debug + PartialEq {}
fn insert_get_init_preserves_data<K: TestKey, V: TestValue>() {
let (key, value) = (K::build, V::build);
run_btree_test(|mut btree| {
let n = 1_000;
for i in 0..n {
assert_eq!(btree.insert(key(i), value(i)), None);
assert_eq!(btree.get(&key(i)), Some(value(i)));
}
let btree = BTreeMap::<K, V, VectorMemory>::init(btree.into_memory());
for i in 0..n {
assert_eq!(btree.get(&key(i)), Some(value(i)));
}
});
}
btree_test!(
test_insert_get_init_preserves_data,
insert_get_init_preserves_data
);
fn insert_overwrites_previous_value<K: TestKey, V: TestValue>() {
let (key, value) = (K::build, V::build);
run_btree_test(|mut btree| {
let n = 1_000;
for i in 0..n {
assert_eq!(btree.insert(key(i), value(i)), None);
assert_eq!(btree.insert(key(i), value(i + 1)), Some(value(i)));
assert_eq!(btree.get(&key(i)), Some(value(i + 1)));
}
});
}
btree_test!(
test_insert_overwrites_previous_value,
insert_overwrites_previous_value
);
fn insert_same_key_many<K: TestKey, V: TestValue>() {
let (key, value) = (K::build, V::build);
run_btree_test(|mut btree| {
let n = 1_000;
assert_eq!(btree.insert(key(1), value(2)), None);
for i in 2..n {
assert_eq!(btree.insert(key(1), value(i + 1)), Some(value(i)));
}
assert_eq!(btree.get(&key(1)), Some(value(n)));
});
}
btree_test!(test_insert_same_key_many, insert_same_key_many);
fn insert_overwrite_median_key_in_full_child_node<K: TestKey, V: TestValue>() {
let (key, value) = (K::build, V::build);
run_btree_test(|mut btree| {
for i in 1..=17 {
assert_eq!(btree.insert(key(i), value(0)), None);
}
let root = btree.load_node(btree.root_addr);
assert_eq!(root.node_type(), NodeType::Internal);
assert_eq!(
root.entries(btree.memory()),
vec![(key(6), encode(value(0)))]
);
assert_eq!(root.children_len(), 2);
let right_child = btree.load_node(root.child(1));
assert!(right_child.is_full());
let median_index = right_child.entries_len() / 2;
let median_key = key(12);
assert_eq!(right_child.key(median_index, btree.memory()), &median_key);
assert_eq!(btree.insert(median_key.clone(), value(123)), Some(value(0)));
assert_eq!(btree.get(&median_key), Some(value(123)));
let right_child = btree.load_node(root.child(1));
assert_eq!(right_child.node_type(), NodeType::Leaf);
assert!(right_child.is_full());
});
}
btree_test!(
test_insert_overwrite_median_key_in_full_child_node,
insert_overwrite_median_key_in_full_child_node
);
fn insert_overwrite_key_in_full_root_node<K: TestKey, V: TestValue>() {
let (key, value) = (K::build, V::build);
run_btree_test(|mut btree| {
for i in 1..=11 {
assert_eq!(btree.insert(key(i), value(0)), None);
}
let root = btree.load_node(btree.root_addr);
assert!(root.is_full());
assert_eq!(btree.insert(key(6), value(456)), Some(value(0)));
let root = btree.load_node(btree.root_addr);
assert_eq!(root.node_type(), NodeType::Leaf);
assert_eq!(btree.get(&key(6)), Some(value(456)));
assert_eq!(root.entries_len(), 11);
});
}
btree_test!(
test_insert_overwrite_key_in_full_root_node,
insert_overwrite_key_in_full_root_node
);
fn allocations_without_split<K: TestKey, V: TestValue>() {
let key = K::build;
run_btree_test(|mut btree| {
assert_eq!(btree.allocator.num_allocated_chunks(), 0);
assert_eq!(btree.insert(key(1), V::empty()), None);
assert_eq!(btree.allocator.num_allocated_chunks(), 1);
assert_eq!(btree.remove(&key(1)), Some(V::empty()));
assert_eq!(btree.allocator.num_allocated_chunks(), 0);
});
}
btree_test!(test_allocations_without_split, allocations_without_split);
fn allocations_with_split<K: TestKey, V: TestValue>() {
let key = K::build;
run_btree_test(|mut btree| {
let mut i = 0;
loop {
assert_eq!(btree.insert(key(i), V::empty()), None);
let root = btree.load_node(btree.root_addr);
if root.is_full() {
break;
}
i += 1;
}
assert_eq!(btree.allocator.num_allocated_chunks(), 1);
assert_eq!(btree.insert(key(255), V::empty()), None);
assert_eq!(btree.allocator.num_allocated_chunks(), 3);
});
}
btree_test!(test_allocations_with_split, allocations_with_split);
fn insert_split_node<K: TestKey, V: TestValue>() {
let (key, value) = (K::build, V::build);
run_btree_test(|mut btree| {
for i in 1..=11 {
assert_eq!(btree.insert(key(i), value(i)), None);
}
let root = btree.load_node(btree.root_addr);
assert!(root.is_full());
assert_eq!(btree.insert(key(12), value(12)), None);
for i in 1..=12 {
assert_eq!(btree.get(&key(i)), Some(value(i)));
}
});
}
btree_test!(test_insert_split_node, insert_split_node);
fn insert_split_multiple_nodes<K: TestKey, V: TestValue>() {
let key = K::build;
let e = |i: u32| (key(i), encode(V::empty()));
run_btree_test(|mut btree| {
for i in 1..=11 {
assert_eq!(btree.insert(key(i), V::empty()), None);
}
assert_eq!(btree.insert(key(12), V::empty()), None);
let root = btree.load_node(btree.root_addr);
assert_eq!(root.node_type(), NodeType::Internal);
assert_eq!(root.entries(btree.memory()), vec![e(6)]);
assert_eq!(root.children_len(), 2);
let child_0 = btree.load_node(root.child(0));
assert_eq!(child_0.node_type(), NodeType::Leaf);
assert_eq!(
child_0.entries(btree.memory()),
vec![e(1), e(2), e(3), e(4), e(5)]
);
let child_1 = btree.load_node(root.child(1));
assert_eq!(child_1.node_type(), NodeType::Leaf);
assert_eq!(
child_1.entries(btree.memory()),
vec![e(7), e(8), e(9), e(10), e(11), e(12)]
);
for i in 1..=12 {
assert_eq!(btree.get(&key(i)), Some(V::empty()));
}
assert_eq!(btree.insert(key(13), V::empty()), None);
assert_eq!(btree.insert(key(14), V::empty()), None);
assert_eq!(btree.insert(key(15), V::empty()), None);
assert_eq!(btree.insert(key(16), V::empty()), None);
assert_eq!(btree.insert(key(17), V::empty()), None);
assert_eq!(btree.insert(key(18), V::empty()), None);
for i in 1..=18 {
assert_eq!(btree.get(&key(i)), Some(V::empty()));
}
let root = btree.load_node(btree.root_addr);
assert_eq!(root.node_type(), NodeType::Internal);
assert_eq!(root.entries(btree.memory()), vec![e(6), e(12)],);
assert_eq!(root.children_len(), 3);
let child_0 = btree.load_node(root.child(0));
assert_eq!(child_0.node_type(), NodeType::Leaf);
assert_eq!(
child_0.entries(btree.memory()),
vec![e(1), e(2), e(3), e(4), e(5)]
);
let child_1 = btree.load_node(root.child(1));
assert_eq!(child_1.node_type(), NodeType::Leaf);
assert_eq!(
child_1.entries(btree.memory()),
vec![e(7), e(8), e(9), e(10), e(11)]
);
let child_2 = btree.load_node(root.child(2));
assert_eq!(child_2.node_type(), NodeType::Leaf);
assert_eq!(
child_2.entries(btree.memory()),
vec![e(13), e(14), e(15), e(16), e(17), e(18)]
);
assert_eq!(btree.allocator.num_allocated_chunks(), 4);
});
}
btree_test!(
test_insert_split_multiple_nodes,
insert_split_multiple_nodes
);
fn first_key_value<K: TestKey, V: TestValue>() {
let (key, value) = (K::build, V::build);
run_btree_test(|mut btree: BTreeMap<K, V, _>| {
assert_eq!(btree.first_key_value(), None);
let n = 1_000;
for i in (0..n).rev() {
assert_eq!(btree.insert(key(i), value(i)), None);
assert_eq!(btree.first_key_value(), Some((key(i), value(i))));
}
for i in 0..n {
assert_eq!(btree.remove(&key(i)), Some(value(i)));
if !btree.is_empty() {
assert_eq!(btree.first_key_value(), Some((key(i + 1), value(i + 1))));
}
}
assert_eq!(btree.first_key_value(), None);
});
}
btree_test!(test_first_key_value, first_key_value);
fn last_key_value<K: TestKey, V: TestValue>() {
let (key, value) = (K::build, V::build);
run_btree_test(|mut btree: BTreeMap<K, V, _>| {
assert_eq!(btree.last_key_value(), None);
let n = 1_000;
for i in 0..n {
assert_eq!(btree.insert(key(i), value(i)), None);
assert_eq!(btree.last_key_value(), Some((key(i), value(i))));
}
for i in (0..n).rev() {
assert_eq!(btree.remove(&key(i)), Some(value(i)));
if !btree.is_empty() {
assert_eq!(btree.last_key_value(), Some((key(i - 1), value(i - 1))));
}
}
assert_eq!(btree.last_key_value(), None);
});
}
btree_test!(test_last_key_value, last_key_value);
fn pop_first_single_entry<K: TestKey, V: TestValue>() {
let key = K::build;
run_btree_test(|mut btree| {
assert_eq!(btree.allocator.num_allocated_chunks(), 0);
assert_eq!(btree.insert(key(1), V::empty()), None);
assert!(!btree.is_empty());
assert_eq!(btree.allocator.num_allocated_chunks(), 1);
assert_eq!(btree.pop_first(), Some((key(1), V::empty())));
assert!(btree.is_empty());
assert_eq!(btree.allocator.num_allocated_chunks(), 0);
});
}
btree_test!(test_pop_first_single_entry, pop_first_single_entry);
fn pop_last_single_entry<K: TestKey, V: TestValue>() {
let (key, value) = (K::build, V::build);
run_btree_test(|mut btree| {
assert_eq!(btree.allocator.num_allocated_chunks(), 0);
assert_eq!(btree.insert(key(1), value(1)), None);
assert!(!btree.is_empty());
assert_eq!(btree.allocator.num_allocated_chunks(), 1);
assert_eq!(btree.pop_last(), Some((key(1), value(1))));
assert!(btree.is_empty());
assert_eq!(btree.allocator.num_allocated_chunks(), 0);
});
}
btree_test!(test_pop_last_single_entry, pop_last_single_entry);
fn remove_case_2a_and_2c<K: TestKey, V: TestValue>() {
let key = K::build;
let e = |i: u32| (key(i), encode(V::empty()));
run_btree_test(|mut btree| {
for i in 1..=11 {
assert_eq!(btree.insert(key(i), V::empty()), None);
}
assert_eq!(btree.insert(key(0), V::empty()), None);
for i in 0..=11 {
assert_eq!(btree.get(&key(i)), Some(V::empty()));
}
assert_eq!(btree.remove(&key(6)), Some(V::empty()));
let root = btree.load_node(btree.root_addr);
assert_eq!(root.node_type(), NodeType::Internal);
assert_eq!(root.entries(btree.memory()), vec![e(5)]);
assert_eq!(root.children_len(), 2);
let child_0 = btree.load_node(root.child(0));
assert_eq!(child_0.node_type(), NodeType::Leaf);
assert_eq!(
child_0.entries(btree.memory()),
vec![e(0), e(1), e(2), e(3), e(4)]
);
let child_1 = btree.load_node(root.child(1));
assert_eq!(child_1.node_type(), NodeType::Leaf);
assert_eq!(
child_1.entries(btree.memory()),
vec![e(7), e(8), e(9), e(10), e(11)]
);
assert_eq!(btree.allocator.num_allocated_chunks(), 3);
assert_eq!(btree.remove(&key(5)), Some(V::empty()));
let btree = BTreeMap::<K, V, _>::load(btree.into_memory());
let root = btree.load_node(btree.root_addr);
assert_eq!(
root.entries(btree.memory()),
vec![e(0), e(1), e(2), e(3), e(4), e(7), e(8), e(9), e(10), e(11)]
);
assert_eq!(btree.allocator.num_allocated_chunks(), 1);
});
}
btree_test!(test_remove_case_2a_and_2c, remove_case_2a_and_2c);
fn remove_case_2b<K: TestKey, V: TestValue>() {
let key = K::build;
let e = |i: u32| (key(i), encode(V::empty()));
run_btree_test(|mut btree| {
for i in 1..=11 {
assert_eq!(btree.insert(key(i), V::empty()), None);
}
assert_eq!(btree.insert(key(12), V::empty()), None);
for i in 1..=12 {
assert_eq!(btree.get(&key(i)), Some(V::empty()));
}
assert_eq!(btree.remove(&key(6)), Some(V::empty()));
let root = btree.load_node(btree.root_addr);
assert_eq!(root.node_type(), NodeType::Internal);
assert_eq!(root.entries(btree.memory()), vec![e(7)]);
assert_eq!(root.children_len(), 2);
let child_0 = btree.load_node(root.child(0));
assert_eq!(child_0.node_type(), NodeType::Leaf);
assert_eq!(
child_0.entries(btree.memory()),
vec![e(1), e(2), e(3), e(4), e(5)]
);
let child_1 = btree.load_node(root.child(1));
assert_eq!(child_1.node_type(), NodeType::Leaf);
assert_eq!(
child_1.entries(btree.memory()),
vec![e(8), e(9), e(10), e(11), e(12)]
);
assert_eq!(btree.remove(&key(7)), Some(V::empty()));
let root = btree.load_node(btree.root_addr);
assert_eq!(root.node_type(), NodeType::Leaf);
assert_eq!(
root.entries(btree.memory()),
collect([1, 2, 3, 4, 5, 8, 9, 10, 11, 12].into_iter().map(e))
);
assert_eq!(btree.allocator.num_allocated_chunks(), 1);
});
}
btree_test!(test_remove_case_2b, remove_case_2b);
fn remove_case_3a_right<K: TestKey, V: TestValue>() {
let key = K::build;
let e = |i: u32| (key(i), encode(V::empty()));
run_btree_test(|mut btree| {
for i in 1..=11 {
assert_eq!(btree.insert(key(i), V::empty()), None);
}
assert_eq!(btree.insert(key(12), V::empty()), None);
assert_eq!(btree.remove(&key(3)), Some(V::empty()));
let root = btree.load_node(btree.root_addr);
assert_eq!(root.node_type(), NodeType::Internal);
assert_eq!(root.entries(btree.memory()), vec![e(7)]);
assert_eq!(root.children_len(), 2);
let child_0 = btree.load_node(root.child(0));
assert_eq!(child_0.node_type(), NodeType::Leaf);
assert_eq!(
child_0.entries(btree.memory()),
vec![e(1), e(2), e(4), e(5), e(6)]
);
let child_1 = btree.load_node(root.child(1));
assert_eq!(child_1.node_type(), NodeType::Leaf);
assert_eq!(
child_1.entries(btree.memory()),
vec![e(8), e(9), e(10), e(11), e(12)]
);
assert_eq!(btree.allocator.num_allocated_chunks(), 3);
});
}
btree_test!(test_remove_case_3a_right, remove_case_3a_right);
fn remove_case_3a_left<K: TestKey, V: TestValue>() {
let key = K::build;
let e = |i: u32| (key(i), encode(V::empty()));
run_btree_test(|mut btree| {
for i in 1..=11 {
assert_eq!(btree.insert(key(i), V::empty()), None);
}
assert_eq!(btree.insert(key(0), V::empty()), None);
assert_eq!(btree.remove(&key(8)), Some(V::empty()));
let root = btree.load_node(btree.root_addr);
assert_eq!(root.node_type(), NodeType::Internal);
assert_eq!(root.entries(btree.memory()), vec![e(5)]);
assert_eq!(root.children_len(), 2);
let child_0 = btree.load_node(root.child(0));
assert_eq!(child_0.node_type(), NodeType::Leaf);
assert_eq!(
child_0.entries(btree.memory()),
vec![e(0), e(1), e(2), e(3), e(4)]
);
let child_1 = btree.load_node(root.child(1));
assert_eq!(child_1.node_type(), NodeType::Leaf);
assert_eq!(
child_1.entries(btree.memory()),
vec![e(6), e(7), e(9), e(10), e(11)]
);
assert_eq!(btree.allocator.num_allocated_chunks(), 3);
});
}
btree_test!(test_remove_case_3a_left, remove_case_3a_left);
fn remove_case_3b_merge_into_right<K: TestKey, V: TestValue>() {
let key = K::build;
let e = |i: u32| (key(i), encode(V::empty()));
run_btree_test(|mut btree| {
for i in 1..=11 {
assert_eq!(btree.insert(key(i), V::empty()), None);
}
assert_eq!(btree.insert(key(12), V::empty()), None);
for i in 1..=12 {
assert_eq!(btree.get(&key(i)), Some(V::empty()));
}
assert_eq!(btree.remove(&key(6)), Some(V::empty()));
let root = btree.load_node(btree.root_addr);
assert_eq!(root.node_type(), NodeType::Internal);
assert_eq!(root.entries(btree.memory()), vec![e(7)]);
assert_eq!(root.children_len(), 2);
let child_0 = btree.load_node(root.child(0));
assert_eq!(child_0.node_type(), NodeType::Leaf);
assert_eq!(
child_0.entries(btree.memory()),
vec![e(1), e(2), e(3), e(4), e(5)]
);
let child_1 = btree.load_node(root.child(1));
assert_eq!(child_1.node_type(), NodeType::Leaf);
assert_eq!(
child_1.entries(btree.memory()),
vec![e(8), e(9), e(10), e(11), e(12)]
);
assert_eq!(btree.allocator.num_allocated_chunks(), 3);
assert_eq!(btree.remove(&key(3)), Some(V::empty()));
let btree = BTreeMap::<K, V, _>::load(btree.into_memory());
let root = btree.load_node(btree.root_addr);
assert_eq!(root.node_type(), NodeType::Leaf);
assert_eq!(
root.entries(btree.memory()),
collect([1, 2, 4, 5, 7, 8, 9, 10, 11, 12].into_iter().map(e))
);
assert_eq!(btree.allocator.num_allocated_chunks(), 1);
});
}
btree_test!(
test_remove_case_3b_merge_into_right,
remove_case_3b_merge_into_right
);
fn remove_case_3b_merge_into_left<K: TestKey, V: TestValue>() {
let key = K::build;
let e = |i: u32| (key(i), encode(V::empty()));
run_btree_test(|mut btree| {
for i in 1..=11 {
assert_eq!(btree.insert(key(i), V::empty()), None);
}
assert_eq!(btree.insert(key(12), V::empty()), None);
for i in 1..=12 {
assert_eq!(btree.get(&key(i)), Some(V::empty()));
}
assert_eq!(btree.remove(&key(6)), Some(V::empty()));
let root = btree.load_node(btree.root_addr);
assert_eq!(root.node_type(), NodeType::Internal);
assert_eq!(root.entries(btree.memory()), vec![e(7)]);
assert_eq!(root.children_len(), 2);
let child_0 = btree.load_node(root.child(0));
assert_eq!(child_0.node_type(), NodeType::Leaf);
assert_eq!(
child_0.entries(btree.memory()),
vec![e(1), e(2), e(3), e(4), e(5)]
);
let child_1 = btree.load_node(root.child(1));
assert_eq!(child_1.node_type(), NodeType::Leaf);
assert_eq!(
child_1.entries(btree.memory()),
vec![e(8), e(9), e(10), e(11), e(12)]
);
assert_eq!(btree.allocator.num_allocated_chunks(), 3);
assert_eq!(btree.remove(&key(10)), Some(V::empty()));
let btree = BTreeMap::<K, V, _>::load(btree.into_memory());
let root = btree.load_node(btree.root_addr);
assert_eq!(root.node_type(), NodeType::Leaf);
assert_eq!(
root.entries(btree.memory()),
vec![e(1), e(2), e(3), e(4), e(5), e(7), e(8), e(9), e(11), e(12)]
);
assert_eq!(btree.allocator.num_allocated_chunks(), 1);
});
}
btree_test!(
test_remove_case_3b_merge_into_left,
remove_case_3b_merge_into_left
);
fn insert_remove_many<K: TestKey, V: TestValue>() {
let (key, value) = (K::build, V::build);
run_btree_test(|mut btree| {
let n = 10_000;
for i in 0..n {
assert_eq!(btree.insert(key(i), value(i)), None);
assert_eq!(btree.get(&key(i)), Some(value(i)));
}
let mut btree = BTreeMap::<K, V, _>::load(btree.into_memory());
for i in 0..n {
assert_eq!(btree.remove(&key(i)), Some(value(i)));
assert_eq!(btree.get(&key(i)), None);
}
assert_eq!(btree.allocator.num_allocated_chunks(), 0);
});
}
btree_test!(test_insert_remove_many, insert_remove_many);
fn pop_first_many<K: TestKey, V: TestValue>() {
let (key, value) = (K::build, V::build);
run_btree_test(|mut btree| {
let n = 10_000;
assert!(btree.is_empty());
assert_eq!(btree.pop_first(), None);
for i in 0..n {
assert_eq!(btree.insert(key(i), value(i)), None);
}
assert_eq!(btree.len(), n as u64);
let mut btree = BTreeMap::<K, V, _>::load(btree.into_memory());
for i in 0..n {
assert_eq!(btree.pop_first(), Some((key(i), value(i))));
assert_eq!(btree.get(&key(i)), None);
}
assert!(btree.is_empty());
assert_eq!(btree.allocator.num_allocated_chunks(), 0);
});
}
btree_test!(test_pop_first_many, pop_first_many);
fn pop_last_many<K: TestKey, V: TestValue>() {
let (key, value) = (K::build, V::build);
run_btree_test(|mut btree| {
let n = 10_000;
assert!(btree.is_empty());
assert_eq!(btree.pop_last(), None);
for i in 0..n {
assert_eq!(btree.insert(key(i), value(i)), None);
}
assert_eq!(btree.len(), n as u64);
let mut btree = BTreeMap::<K, V, _>::load(btree.into_memory());
for i in (0..n).rev() {
assert_eq!(btree.pop_last(), Some((key(i), value(i))));
assert_eq!(btree.get(&key(i)), None);
}
assert!(btree.is_empty());
assert_eq!(btree.allocator.num_allocated_chunks(), 0);
});
}
btree_test!(test_pop_last_many, pop_last_many);
fn reloading<K: TestKey, V: TestValue>() {
let (key, value) = (K::build, V::build);
run_btree_test(|mut btree| {
let n = 1_000;
for i in 0..n {
assert_eq!(btree.insert(key(i), value(i)), None);
assert_eq!(btree.get(&key(i)), Some(value(i)));
}
assert_eq!(btree.len(), n as u64);
let mut btree = BTreeMap::<K, V, VectorMemory>::load(btree.into_memory());
assert_eq!(btree.len(), n as u64);
for i in 0..n {
assert_eq!(btree.get(&key(i)), Some(value(i)));
}
for i in 0..n {
assert_eq!(btree.remove(&key(i)), Some(value(i)));
}
assert_eq!(btree.len(), 0);
let btree = BTreeMap::<K, V, VectorMemory>::load(btree.into_memory());
assert_eq!(btree.len(), 0);
});
}
btree_test!(test_reloading, reloading);
fn len<K: TestKey, V: TestValue>() {
let (key, value) = (K::build, V::build);
run_btree_test(|mut btree| {
let n = 1_000;
for i in 0..n {
assert_eq!(btree.insert(key(i), value(i)), None);
}
assert_eq!(btree.len(), n as u64);
assert!(!btree.is_empty());
for i in 0..n {
assert_eq!(btree.remove(&key(i)), Some(value(i)));
}
assert_eq!(btree.len(), 0);
assert!(btree.is_empty());
});
}
btree_test!(test_len, len);
fn contains_key<K: TestKey, V: TestValue>() {
let (key, value) = (K::build, V::build);
run_btree_test(|mut btree| {
let n = 1_000;
for i in (0..n).step_by(2) {
assert_eq!(btree.insert(key(i), value(i)), None);
}
for i in 0..n {
assert_eq!(btree.contains_key(&key(i)), i % 2 == 0);
}
});
}
btree_test!(test_contains_key, contains_key);
fn range_empty<K: TestKey, V: TestValue>() {
let key = K::build;
run_btree_test(|btree: BTreeMap<K, V, _>| {
assert_eq!(collect_entry(btree.range(key(0)..)), vec![]);
assert_eq!(collect_entry(btree.range(key(10)..)), vec![]);
assert_eq!(collect_entry(btree.range(key(100)..)), vec![]);
});
}
btree_test!(test_range_empty, range_empty);
fn range_leaf_prefix_greater_than_all_entries<K: TestKey, V: TestValue>() {
let (key, value) = (K::build, V::build);
run_btree_test(|mut btree| {
btree.insert(key(0), value(0));
assert_eq!(collect_entry(btree.range(key(1)..)), vec![]);
});
}
btree_test!(
test_range_leaf_prefix_greater_than_all_entries,
range_leaf_prefix_greater_than_all_entries
);
fn range_internal_prefix_greater_than_all_entries<K: TestKey, V: TestValue>() {
let (key, value) = (K::build, V::build);
run_btree_test(|mut btree| {
for i in 1..=12 {
assert_eq!(btree.insert(key(i), value(i)), None);
}
assert_eq!(
collect_entry(btree.range(key(7)..key(8))),
vec![(key(7), value(7))]
);
});
}
btree_test!(
test_range_internal_prefix_greater_than_all_entries,
range_internal_prefix_greater_than_all_entries
);
fn range_various_prefixes<K: TestKey, V: TestValue>() {
let (key, value) = (K::build, V::build);
run_btree_test(|mut btree| {
btree.insert(key(1), value(100));
btree.insert(key(2), value(200));
btree.insert(key(3), value(300));
btree.insert(key(4), value(400));
btree.insert(key(11), value(500));
btree.insert(key(12), value(600));
btree.insert(key(13), value(700));
btree.insert(key(14), value(800));
btree.insert(key(21), value(900));
btree.insert(key(22), value(1_000));
btree.insert(key(23), value(1_100));
btree.insert(key(24), value(1_200));
let root = btree.load_node(btree.root_addr);
assert_eq!(root.node_type(), NodeType::Internal);
assert_eq!(
root.entries(btree.memory()),
vec![(key(12), encode(value(600)))]
);
assert_eq!(root.children_len(), 2);
assert_eq!(
collect_entry(btree.range(key(0)..key(11))),
vec![
(key(1), value(100)),
(key(2), value(200)),
(key(3), value(300)),
(key(4), value(400)),
]
);
assert_eq!(
collect_entry(btree.range(key(10)..key(20))),
vec![
(key(11), value(500)),
(key(12), value(600)),
(key(13), value(700)),
(key(14), value(800)),
]
);
assert_eq!(
collect_entry(btree.range(key(20)..key(30))),
vec![
(key(21), value(900)),
(key(22), value(1_000)),
(key(23), value(1_100)),
(key(24), value(1_200)),
]
);
});
}
btree_test!(test_range_various_prefixes, range_various_prefixes);
fn range_various_prefixes_2<K: TestKey, V: TestValue>() {
let (key, value) = (K::build, V::build);
run_btree_test(|mut btree| {
btree.insert(key(1), value(100));
btree.insert(key(2), value(200));
btree.insert(key(3), value(300));
btree.insert(key(4), value(400));
btree.insert(key(12), value(500));
btree.insert(key(14), value(600));
btree.insert(key(16), value(700));
btree.insert(key(18), value(800));
btree.insert(key(19), value(900));
btree.insert(key(21), value(1000));
btree.insert(key(22), value(1100));
btree.insert(key(23), value(1200));
btree.insert(key(24), value(1300));
btree.insert(key(25), value(1400));
btree.insert(key(26), value(1500));
btree.insert(key(27), value(1600));
btree.insert(key(28), value(1700));
btree.insert(key(29), value(1800));
let root = btree.load_node(btree.root_addr);
assert_eq!(root.node_type(), NodeType::Internal);
assert_eq!(
root.entries(btree.memory()),
vec![
(key(14), encode(value(600))),
(key(23), encode(value(1200)))
]
);
assert_eq!(root.children_len(), 3);
let child_0 = btree.load_node(root.child(0));
assert_eq!(child_0.node_type(), NodeType::Leaf);
assert_eq!(
child_0.entries(btree.memory()),
vec![
(key(1), encode(value(100))),
(key(2), encode(value(200))),
(key(3), encode(value(300))),
(key(4), encode(value(400))),
(key(12), encode(value(500))),
]
);
let child_1 = btree.load_node(root.child(1));
assert_eq!(child_1.node_type(), NodeType::Leaf);
assert_eq!(
child_1.entries(btree.memory()),
vec![
(key(16), encode(value(700))),
(key(18), encode(value(800))),
(key(19), encode(value(900))),
(key(21), encode(value(1000))),
(key(22), encode(value(1100))),
]
);
let child_2 = btree.load_node(root.child(2));
assert_eq!(
child_2.entries(btree.memory()),
vec![
(key(24), encode(value(1300))),
(key(25), encode(value(1400))),
(key(26), encode(value(1500))),
(key(27), encode(value(1600))),
(key(28), encode(value(1700))),
(key(29), encode(value(1800))),
]
);
assert_eq!(collect_entry(btree.range(key(15)..key(16))), vec![]);
assert_eq!(
collect_entry(btree.range(key(15)..=key(26))),
vec![
(key(16), value(700)),
(key(18), value(800)),
(key(19), value(900)),
(key(21), value(1000)),
(key(22), value(1100)),
(key(23), value(1200)),
(key(24), value(1300)),
(key(25), value(1400)),
(key(26), value(1500)),
]
);
assert_eq!(
collect_entry(btree.range(key(10)..key(20))),
vec![
(key(12), value(500)),
(key(14), value(600)),
(key(16), value(700)),
(key(18), value(800)),
(key(19), value(900)),
]
);
assert_eq!(
collect_entry(btree.range(key(20)..key(30))),
vec![
(key(21), value(1000)),
(key(22), value(1100)),
(key(23), value(1200)),
(key(24), value(1300)),
(key(25), value(1400)),
(key(26), value(1500)),
(key(27), value(1600)),
(key(28), value(1700)),
(key(29), value(1800)),
]
);
});
}
btree_test!(test_range_various_prefixes_2, range_various_prefixes_2);
fn range_large<K: TestKey, V: TestValue>() {
let (key, value) = (K::build, V::build);
run_btree_test(|mut btree| {
const TOTAL: u32 = 2_000;
const MID: u32 = TOTAL / 2;
for i in 0..TOTAL {
assert_eq!(btree.insert(key(i), value(i)), None);
}
let keys: Vec<_> = btree.range(key(0)..key(MID)).collect();
assert_eq!(keys.len(), MID as usize);
for (i, entry) in keys.into_iter().enumerate() {
let j = i as u32;
assert_eq!(*entry.key(), key(j));
assert_eq!(entry.value(), value(j));
}
let keys: Vec<_> = btree.range(key(MID)..).collect();
assert_eq!(keys.len(), (TOTAL - MID) as usize);
for (i, entry) in keys.into_iter().enumerate() {
let j = MID + i as u32;
assert_eq!(*entry.key(), key(j));
assert_eq!(entry.value(), value(j));
}
});
}
btree_test!(test_range_large, range_large);
fn range_various_prefixes_with_offset<K: TestKey, V: TestValue>() {
let (key, value) = (K::build, V::build);
run_btree_test(|mut btree| {
btree.insert(key(1), value(100));
btree.insert(key(2), value(200));
btree.insert(key(3), value(300));
btree.insert(key(4), value(400));
btree.insert(key(11), value(500));
btree.insert(key(12), value(600));
btree.insert(key(13), value(700));
btree.insert(key(14), value(800));
btree.insert(key(21), value(900));
btree.insert(key(22), value(1000));
btree.insert(key(23), value(1100));
btree.insert(key(24), value(1200));
let root = btree.load_node(btree.root_addr);
assert_eq!(root.node_type(), NodeType::Internal);
assert_eq!(
root.entries(btree.memory()),
vec![(key(12), encode(value(600)))]
);
assert_eq!(root.children_len(), 2);
assert_eq!(
collect_entry(btree.range(key(0)..key(10))),
vec![
(key(1), value(100)),
(key(2), value(200)),
(key(3), value(300)),
(key(4), value(400)),
]
);
assert_eq!(
collect_entry(btree.range(key(13)..key(20))),
vec![(key(13), value(700)), (key(14), value(800))]
);
assert_eq!(collect_entry(btree.range(key(25)..)), vec![]);
});
}
btree_test!(
test_range_various_prefixes_with_offset,
range_various_prefixes_with_offset
);
fn range_various_prefixes_with_offset_2<K: TestKey, V: TestValue>() {
let (key, value) = (K::build, V::build);
run_btree_test(|mut btree| {
btree.insert(key(1), value(0));
btree.insert(key(2), value(0));
btree.insert(key(3), value(0));
btree.insert(key(4), value(0));
btree.insert(key(12), value(0));
btree.insert(key(14), value(0));
btree.insert(key(16), value(0));
btree.insert(key(18), value(0));
btree.insert(key(19), value(0));
btree.insert(key(21), value(0));
btree.insert(key(22), value(0));
btree.insert(key(23), value(0));
btree.insert(key(24), value(0));
btree.insert(key(25), value(0));
btree.insert(key(26), value(0));
btree.insert(key(27), value(0));
btree.insert(key(28), value(0));
btree.insert(key(29), value(0));
let root = btree.load_node(btree.root_addr);
assert_eq!(root.node_type(), NodeType::Internal);
assert_eq!(
root.entries(btree.memory()),
vec![(key(14), encode(value(0))), (key(23), encode(value(0)))]
);
assert_eq!(root.children_len(), 3);
let child_0 = btree.load_node(root.child(0));
assert_eq!(child_0.node_type(), NodeType::Leaf);
assert_eq!(
child_0.entries(btree.memory()),
vec![
(key(1), encode(value(0))),
(key(2), encode(value(0))),
(key(3), encode(value(0))),
(key(4), encode(value(0))),
(key(12), encode(value(0))),
]
);
let child_1 = btree.load_node(root.child(1));
assert_eq!(child_1.node_type(), NodeType::Leaf);
assert_eq!(
child_1.entries(btree.memory()),
vec![
(key(16), encode(value(0))),
(key(18), encode(value(0))),
(key(19), encode(value(0))),
(key(21), encode(value(0))),
(key(22), encode(value(0))),
]
);
let child_2 = btree.load_node(root.child(2));
assert_eq!(
child_2.entries(btree.memory()),
vec![
(key(24), encode(value(0))),
(key(25), encode(value(0))),
(key(26), encode(value(0))),
(key(27), encode(value(0))),
(key(28), encode(value(0))),
(key(29), encode(value(0))),
]
);
assert_eq!(
collect_entry(btree.range(key(14)..key(20))),
vec![
(key(14), value(0)),
(key(16), value(0)),
(key(18), value(0)),
(key(19), value(0)),
]
);
assert_eq!(
collect_entry(btree.range(key(22)..key(30))),
vec![
(key(22), value(0)),
(key(23), value(0)),
(key(24), value(0)),
(key(25), value(0)),
(key(26), value(0)),
(key(27), value(0)),
(key(28), value(0)),
(key(29), value(0)),
]
);
});
}
btree_test!(
test_range_various_prefixes_with_offset_2,
range_various_prefixes_with_offset_2
);
#[test]
#[should_panic(expected = "max_key_size must be <= 4")]
fn v1_rejects_increases_in_max_key_size() {
let mem = make_memory();
let btree: BTreeMap<Blob<4>, Blob<3>, _> = BTreeMap::init_v1(mem);
let _btree: BTreeMap<Blob<5>, Blob<3>, _> = BTreeMap::init_v1(btree.into_memory());
}
#[test]
fn v2_handles_increases_in_max_key_size_and_max_value_size() {
let mem = make_memory();
let mut btree: BTreeMap<Blob<4>, Blob<4>, _> = BTreeMap::init(mem);
btree.insert(
[1u8; 4].as_slice().try_into().unwrap(),
[1u8; 4].as_slice().try_into().unwrap(),
);
let mut btree: BTreeMap<Blob<5>, Blob<5>, _> = BTreeMap::init(btree.into_memory());
btree.insert(
[2u8; 5].as_slice().try_into().unwrap(),
[2u8; 5].as_slice().try_into().unwrap(),
);
assert_eq!(
btree.get(&([1u8; 4].as_slice().try_into().unwrap())),
Some([1u8; 4].as_slice().try_into().unwrap())
);
assert_eq!(
btree.get(&([2u8; 5].as_slice().try_into().unwrap())),
Some([2u8; 5].as_slice().try_into().unwrap())
);
}
#[test]
fn accepts_small_or_equal_key_sizes() {
let mem = make_memory();
let btree: BTreeMap<Blob<4>, Blob<3>, _> = BTreeMap::init(mem);
let btree: BTreeMap<Blob<3>, Blob<3>, _> = BTreeMap::init(btree.into_memory());
let _btree: BTreeMap<Blob<4>, Blob<3>, _> = BTreeMap::init(btree.into_memory());
}
#[test]
#[should_panic(expected = "max_value_size must be <= 3")]
fn v1_rejects_larger_value_sizes() {
let mem = make_memory();
let btree: BTreeMap<Blob<4>, Blob<3>, _> = BTreeMap::init_v1(mem);
let _btree: BTreeMap<Blob<4>, Blob<4>, _> = BTreeMap::init_v1(btree.into_memory());
}
#[test]
fn accepts_small_or_equal_value_sizes() {
let mem = make_memory();
let btree: BTreeMap<Blob<4>, Blob<3>, _> = BTreeMap::init(mem);
let btree: BTreeMap<Blob<4>, Blob<2>, _> = BTreeMap::init(btree.into_memory());
let _btree: BTreeMap<Blob<4>, Blob<3>, _> = BTreeMap::init(btree.into_memory());
}
fn bruteforce_range_search<K: TestKey, V: TestValue>() {
let (key, value) = (K::build, V::build);
run_btree_test(|mut stable_map| {
use std::collections::BTreeMap;
const NKEYS: u32 = 60;
let mut std_map = BTreeMap::new();
for i in 0..NKEYS {
std_map.insert(key(i), value(i));
stable_map.insert(key(i), value(i));
}
assert_eq!(
collect_kv(std_map.range(..)),
collect_entry(stable_map.range(..))
);
for l in 0..=NKEYS {
assert_eq!(
collect_kv(std_map.range(key(l)..)),
collect_entry(stable_map.range(key(l)..))
);
assert_eq!(
collect_kv(std_map.range(..key(l))),
collect_entry(stable_map.range(..key(l)))
);
assert_eq!(
collect_kv(std_map.range(..=key(l))),
collect_entry(stable_map.range(..=key(l)))
);
for r in l + 1..=NKEYS {
for lbound in [Bound::Included(key(l)), Bound::Excluded(key(l))] {
for rbound in [Bound::Included(key(r)), Bound::Excluded(key(r))] {
let range = (lbound.clone(), rbound);
assert_eq!(
collect_kv(std_map.range(range.clone())),
collect_entry(stable_map.range(range.clone())),
"range: {range:?}"
);
}
}
}
}
});
}
btree_test!(test_bruteforce_range_search, bruteforce_range_search);
fn test_iter_from_prev_key<K: TestKey, V: TestValue>() {
let (key, value) = (K::build, V::build);
run_btree_test(|mut btree| {
for j in 0..100 {
btree.insert(key(j), value(j));
for i in 0..=j {
assert_eq!(
btree
.iter_from_prev_key(&key(i + 1))
.next()
.map(|entry| entry.into_pair()),
Some((key(i), value(i))),
"failed to get an upper bound for key({})",
i + 1
);
}
assert_eq!(
btree
.iter_from_prev_key(&key(0))
.next()
.map(|entry| entry.into_pair()),
None,
"key(0) must not have an upper bound"
);
}
});
}
btree_test!(test_test_iter_from_prev_key, test_iter_from_prev_key);
#[derive(Clone, Ord, PartialOrd, Eq, PartialEq)]
struct BuggyStruct;
impl crate::Storable for BuggyStruct {
fn to_bytes(&self) -> Cow<'_, [u8]> {
Cow::Borrowed(&[1, 2, 3, 4])
}
fn into_bytes(self) -> Vec<u8> {
self.to_bytes().into_owned()
}
fn from_bytes(_: Cow<[u8]>) -> Self {
unimplemented!();
}
const BOUND: StorableBound = StorableBound::Bounded {
max_size: 1,
is_fixed_size: false,
};
}
#[test]
#[should_panic(expected = "expected an element with length <= 1 bytes, but found 4")]
fn v1_panics_if_key_is_bigger_than_max_size() {
let mut btree = BTreeMap::init_v1(make_memory());
btree.insert(BuggyStruct, ());
}
#[test]
#[should_panic(expected = "expected an element with length <= 1 bytes, but found 4")]
fn v2_panics_if_key_is_bigger_than_max_size() {
let mut btree = BTreeMap::init(make_memory());
btree.insert(BuggyStruct, ());
}
#[test]
#[should_panic(expected = "expected an element with length <= 1 bytes, but found 4")]
fn v1_panics_if_value_is_bigger_than_max_size() {
let mut btree = BTreeMap::init(make_memory());
btree.insert((), BuggyStruct);
}
#[test]
#[should_panic(expected = "expected an element with length <= 1 bytes, but found 4")]
fn v2_panics_if_value_is_bigger_than_max_size() {
let mut btree = BTreeMap::init(make_memory());
btree.insert((), BuggyStruct);
}
#[test]
#[ignore]
fn create_btreemap_dump_file() {
let mem = make_memory();
let mut btree = BTreeMap::init_v1(mem.clone());
let key = b(&[1, 2, 3]);
let value = b(&[4, 5, 6]);
assert_eq!(btree.insert(key, value), None);
assert_eq!(btree.get(&key), Some(value));
use std::io::prelude::*;
let mut file =
std::fs::File::create(format!("dumps/btreemap_v{LAYOUT_VERSION}.dump")).unwrap();
file.write_all(&mem.borrow()).unwrap();
}
#[test]
fn produces_layout_identical_to_layout_version_1_with_packed_headers() {
let mem = make_memory();
let mut btree = BTreeMap::init_v1(mem.clone());
let key = b(&[1, 2, 3]);
let value = b(&[4, 5, 6]);
assert_eq!(btree.insert(key, value), None);
assert_eq!(btree.get(&key), Some(value));
let btreemap_v1 = include_bytes!("../dumps/btreemap_v1_packed_headers.dump");
assert_eq!(*mem.borrow(), btreemap_v1);
}
#[test]
fn read_write_header_is_identical_to_read_write_struct() {
#[repr(C, packed)]
struct BTreePackedHeader {
magic: [u8; 3],
version: u8,
max_key_size: u32,
max_value_size: u32,
root_addr: Address,
length: u64,
_buffer: [u8; 24],
}
let packed_header = BTreePackedHeader {
magic: *MAGIC,
version: LAYOUT_VERSION,
root_addr: Address::from(0xDEADBEEF),
max_key_size: 0x12345678,
max_value_size: 0x87654321,
length: 0xA1B2D3C4,
_buffer: [0; 24],
};
let packed_mem = make_memory();
crate::write_struct(&packed_header, Address::from(0), &packed_mem);
let v1_header = BTreeHeader {
version: Version::V1(DerivedPageSize {
max_key_size: 0x12345678,
max_value_size: 0x87654321,
}),
root_addr: Address::from(0xDEADBEEF),
length: 0xA1B2D3C4,
};
let v1_mem = make_memory();
BTreeMap::<Vec<_>, Vec<_>, RefCell<Vec<_>>>::write_header(&v1_header, &v1_mem);
assert_eq!(packed_mem, v1_mem);
let packed_header: BTreePackedHeader = crate::read_struct(Address::from(0), &v1_mem);
let v1_header = BTreeMap::<Vec<_>, Vec<_>, RefCell<Vec<_>>>::read_header(&v1_mem);
assert!(packed_header.magic == *MAGIC);
assert!(packed_header.version == LAYOUT_VERSION);
match v1_header.version {
Version::V1(DerivedPageSize {
max_key_size,
max_value_size,
}) => {
assert!(packed_header.max_key_size == max_key_size);
assert!(packed_header.max_value_size == max_value_size);
}
_ => unreachable!("version must be v1"),
};
assert!(packed_header.root_addr == v1_header.root_addr);
assert!(packed_header.length == v1_header.length);
}
#[test]
fn migrate_from_bounded_to_unbounded_and_back() {
#[derive(PartialOrd, Ord, Clone, Eq, PartialEq, Debug)]
struct T;
impl Storable for T {
fn to_bytes(&self) -> Cow<'_, [u8]> {
Cow::Borrowed(&[1, 2, 3])
}
fn into_bytes(self) -> Vec<u8> {
self.to_bytes().into_owned()
}
fn from_bytes(bytes: Cow<[u8]>) -> Self {
assert_eq!(bytes.to_vec(), vec![1, 2, 3]);
T
}
const BOUND: StorableBound = StorableBound::Bounded {
max_size: 3,
is_fixed_size: true,
};
}
#[derive(PartialOrd, Ord, Clone, Eq, PartialEq, Debug)]
struct T2;
impl Storable for T2 {
fn to_bytes(&self) -> Cow<'_, [u8]> {
Cow::Owned(vec![1, 2, 3])
}
fn into_bytes(self) -> Vec<u8> {
self.to_bytes().into_owned()
}
fn from_bytes(bytes: Cow<[u8]>) -> Self {
assert_eq!(bytes.to_vec(), vec![1, 2, 3]);
T2
}
const BOUND: StorableBound = StorableBound::Unbounded;
}
let mem = make_memory();
let mut btree: BTreeMap<T, T, _> = BTreeMap::new_v1(mem);
btree.insert(T, T);
let btree: BTreeMap<T2, T2, _> = BTreeMap::init(btree.into_memory());
btree.save_header();
let btree: BTreeMap<T2, T2, _> = BTreeMap::init(btree.into_memory());
assert_eq!(btree.get(&T2), Some(T2));
let btree: BTreeMap<T, T, _> = BTreeMap::init(btree.into_memory());
assert_eq!(btree.get(&T), Some(T));
}
#[test]
fn test_clear_new_bounded_type() {
let mem = make_memory();
let mut btree: BTreeMap<Blob<4>, Blob<4>, _> = BTreeMap::new(mem.clone());
btree.insert(
[1u8; 4].as_slice().try_into().unwrap(),
[1u8; 4].as_slice().try_into().unwrap(),
);
assert_ne!(btree.len(), 0);
assert_ne!(btree.allocator.num_allocated_chunks(), 0);
assert_ne!(btree.root_addr, NULL);
btree.clear_new();
let header_actual = BTreeMap::<Blob<4>, Blob<4>, _>::read_header(&mem);
BTreeMap::<Blob<4>, Blob<4>, _>::new(mem.clone());
let header_expected = BTreeMap::<Blob<4>, Blob<4>, _>::read_header(&mem);
assert_eq!(header_actual, header_expected);
}
#[test]
fn test_clear_new_unbounded_type() {
let mem = make_memory();
let mut btree: BTreeMap<String, String, _> = BTreeMap::new(mem.clone());
btree.insert("asd".into(), "bce".into());
assert_ne!(btree.len(), 0);
assert_ne!(btree.allocator.num_allocated_chunks(), 0);
assert_ne!(btree.root_addr, NULL);
btree.clear_new();
let header_actual = BTreeMap::<String, String, _>::read_header(&mem);
BTreeMap::<String, String, _>::new(mem.clone());
let header_expected = BTreeMap::<String, String, _>::read_header(&mem);
assert_eq!(header_actual, header_expected);
}
#[test]
fn deallocating_node_with_overflows() {
let mem = make_memory();
let mut btree: BTreeMap<Vec<u8>, Vec<u8>, _> = BTreeMap::new(mem.clone());
assert_eq!(btree.allocator.num_allocated_chunks(), 0);
btree.insert(vec![0; 10_000], vec![]);
assert!(btree.allocator.num_allocated_chunks() >= 2);
btree.remove(&vec![0; 10_000]);
assert_eq!(btree.allocator.num_allocated_chunks(), 0);
}
#[test]
fn repeatedly_deallocating_nodes_with_overflows() {
let mem = make_memory();
let mut btree: BTreeMap<Vec<u8>, Vec<u8>, _> = BTreeMap::new(mem.clone());
assert_eq!(btree.allocator.num_allocated_chunks(), 0);
for _ in 0..100 {
for i in 0..100 {
btree.insert(vec![i; 10_000], vec![]);
}
for i in 0..100 {
btree.remove(&vec![i; 10_000]);
}
}
assert_eq!(btree.allocator.num_allocated_chunks(), 0);
}
#[test]
fn deallocating_root_does_not_leak_memory() {
let mem = make_memory();
let mut btree: BTreeMap<Vec<u8>, _, _> = BTreeMap::new(mem.clone());
for i in 1..=11 {
assert_eq!(btree.insert(vec![i; 10_000], ()), None);
}
assert_eq!(btree.insert(vec![0; 10_000], ()), None);
let root = btree.load_node(btree.root_addr);
assert_eq!(root.node_type(), NodeType::Internal);
assert_eq!(root.keys(btree.memory()), vec![&[6; 10_000]]);
assert_eq!(root.children_len(), 2);
btree.remove(&vec![6; 10_000]);
let root = btree.load_node(btree.root_addr);
assert_eq!(root.node_type(), NodeType::Internal);
assert_eq!(root.keys(btree.memory()), vec![&[5; 10_000]]);
assert_eq!(root.children_len(), 2);
btree.remove(&vec![5; 10_000]);
let root = btree.load_node(btree.root_addr);
assert_eq!(root.node_type(), NodeType::Leaf);
assert_eq!(
root.keys(btree.memory()),
vec![
&[0; 10_000],
&[1; 10_000],
&[2; 10_000],
&[3; 10_000],
&[4; 10_000],
&[7; 10_000],
&[8; 10_000],
&[9; 10_000],
&[10; 10_000],
&[11; 10_000],
]
);
for i in 0..=11 {
btree.remove(&vec![i; 10_000]);
}
assert_eq!(btree.allocator.num_allocated_chunks(), 0);
}
}