use crate::*;
#[doc(hidden)]
pub mod cursor;
pub use cursor::{iter, rev_iter, Cursor, Iter, RevIter};
pub mod del;
pub use del::del;
pub mod put;
pub use put::put;
pub mod page;
pub mod page_unsized;
pub trait BTreePage<K: ?Sized, V: ?Sized>: Sized {
type Cursor: Clone + Copy + core::fmt::Debug;
fn is_empty(c: &Self::Cursor) -> bool;
fn is_init(c: &Self::Cursor) -> bool;
fn cursor_before(p: &CowPage) -> Self::Cursor;
fn cursor_first(p: &CowPage) -> Self::Cursor {
let mut c = Self::cursor_before(p);
Self::move_next(&mut c);
c
}
fn cursor_after(p: &CowPage) -> Self::Cursor;
fn cursor_last(p: &CowPage) -> Self::Cursor {
let mut c = Self::cursor_after(p);
Self::move_prev(&mut c);
c
}
fn next<'b, T: LoadPage>(
txn: &T,
p: Page<'b>,
c: &mut Self::Cursor,
) -> Option<(&'b K, &'b V, u64)> {
if let Some((k, v, r)) = Self::current(txn, p, c) {
Self::move_next(c);
Some((k, v, r))
} else {
None
}
}
fn prev<'b, T: LoadPage>(
txn: &T,
p: Page<'b>,
c: &mut Self::Cursor,
) -> Option<(&'b K, &'b V, u64)> {
if Self::move_prev(c) {
Self::current(txn, p, c)
} else {
None
}
}
fn move_next(c: &mut Self::Cursor) -> bool;
fn move_prev(c: &mut Self::Cursor) -> bool;
fn current<'a, T: LoadPage>(
txn: &T,
p: Page<'a>,
c: &Self::Cursor,
) -> Option<(&'a K, &'a V, u64)>;
fn left_child(p: Page, c: &Self::Cursor) -> u64;
fn right_child(p: Page, c: &Self::Cursor) -> u64;
fn set_cursor<'a, T: LoadPage>(
txn: &'a T,
page: Page,
c: &mut Self::Cursor,
k0: &K,
v0: Option<&V>,
) -> Result<(&'a K, &'a V, u64), usize>;
fn split_at(c: &Self::Cursor) -> (Self::Cursor, Self::Cursor);
}
pub struct PageIterator<'a, T: LoadPage, K: ?Sized, V: ?Sized, P: BTreePage<K, V>> {
cursor: P::Cursor,
txn: &'a T,
page: Page<'a>,
}
impl<'a, T: LoadPage, K: ?Sized + 'a, V: ?Sized + 'a, P: BTreePage<K, V>> Iterator
for PageIterator<'a, T, K, V, P>
{
type Item = (&'a K, &'a V, u64);
fn next(&mut self) -> Option<Self::Item> {
P::next(self.txn, self.page, &mut self.cursor)
}
}
pub trait BTreeMutPage<K: ?Sized, V: ?Sized>: BTreePage<K, V> + core::fmt::Debug {
fn init(page: &mut MutPage);
fn put<'a, T: AllocPage>(
txn: &mut T,
page: CowPage,
mutable: bool,
replace: bool,
c: &Self::Cursor,
k0: &'a K,
v0: &'a V,
k1v1: Option<(&'a K, &'a V)>,
l: u64,
r: u64,
) -> Result<crate::btree::put::Put<'a, K, V>, T::Error>;
fn update_left_child<T: AllocPage>(
txn: &mut T,
page: CowPage,
mutable: bool,
c: &Self::Cursor,
r: u64,
) -> Result<crate::btree::put::Ok, T::Error>;
type Saved;
fn save_deleted_leaf_entry(k: &K, v: &V) -> Self::Saved;
unsafe fn from_saved<'a>(s: &Self::Saved) -> (&'a K, &'a V);
fn del<T: AllocPage>(
txn: &mut T,
page: CowPage,
mutable: bool,
c: &Self::Cursor,
l: u64,
) -> Result<(MutPage, u64), T::Error>;
fn merge_or_rebalance<'a, 'b, T: AllocPage>(
txn: &mut T,
m: del::Concat<'a, K, V, Self>,
) -> Result<del::Op<'a, T, K, V>, T::Error>;
}
#[derive(Debug)]
pub struct Db_<K: ?Sized, V: ?Sized, P: BTreePage<K, V>> {
pub db: u64,
pub k: core::marker::PhantomData<K>,
pub v: core::marker::PhantomData<V>,
pub p: core::marker::PhantomData<P>,
}
pub type Db<K, V> = Db_<K, V, page::Page<K, V>>;
pub type UDb<K, V> = Db_<K, V, page_unsized::Page<K, V>>;
impl<K: ?Sized, V: ?Sized, P: BTreePage<K, V>> Db_<K, V, P> {
pub fn from_page(db: u64) -> Self {
Db_ {
db,
k: core::marker::PhantomData,
v: core::marker::PhantomData,
p: core::marker::PhantomData,
}
}
}
pub fn create_db_<T: AllocPage, K: ?Sized, V: ?Sized, P: BTreeMutPage<K, V>>(
txn: &mut T,
) -> Result<Db_<K, V, P>, T::Error> {
let mut page = txn.alloc_page()?;
P::init(&mut page);
Ok(Db_ {
db: page.0.offset,
k: core::marker::PhantomData,
v: core::marker::PhantomData,
p: core::marker::PhantomData,
})
}
pub fn create_db<T: AllocPage, K: Storable, V: Storable>(
txn: &mut T,
) -> Result<Db_<K, V, page::Page<K, V>>, T::Error> {
create_db_(txn)
}
pub fn fork_db<T: AllocPage, K: Storable + ?Sized, V: Storable + ?Sized, P: BTreeMutPage<K, V>>(
txn: &mut T,
db: &Db_<K, V, P>,
) -> Result<Db_<K, V, P>, T::Error> {
txn.incr_rc(db.db)?;
Ok(Db_ {
db: db.db,
k: core::marker::PhantomData,
v: core::marker::PhantomData,
p: core::marker::PhantomData,
})
}
pub fn get<'a, T: LoadPage, K: Storable + ?Sized, V: Storable + ?Sized, P: BTreePage<K, V>>(
txn: &'a T,
db: &Db_<K, V, P>,
k: &K,
v: Option<&V>,
) -> Result<Option<(&'a K, &'a V)>, T::Error> {
let mut last_match = None;
let mut page = txn.load_page(db.db)?;
for _ in 0..cursor::N_CURSORS {
let mut cursor = P::cursor_before(&page);
if let Ok((kk, vv, _)) = P::set_cursor(txn, page.as_page(), &mut cursor, k, v) {
if v.is_some() {
return Ok(Some((kk, vv)));
}
last_match = Some((kk, vv));
} else if let Some((k, v, _)) = P::current(txn, page.as_page(), &cursor) {
unsafe { last_match = Some((core::mem::transmute(k), core::mem::transmute(v))) }
}
let next_page = P::left_child(page.as_page(), &cursor);
if next_page > 0 {
page = txn.load_page(next_page)?;
} else {
break;
}
}
Ok(last_match)
}
pub fn drop<T: AllocPage, K: Storable + ?Sized, V: Storable + ?Sized, P: BTreePage<K, V>>(
txn: &mut T,
db: Db_<K, V, P>,
) -> Result<(), T::Error> {
use core::mem::MaybeUninit;
let mut stack: [MaybeUninit<cursor::PageCursor<K, V, P>>; cursor::N_CURSORS] = [
MaybeUninit::uninit(),
MaybeUninit::uninit(),
MaybeUninit::uninit(),
MaybeUninit::uninit(),
MaybeUninit::uninit(),
MaybeUninit::uninit(),
MaybeUninit::uninit(),
MaybeUninit::uninit(),
MaybeUninit::uninit(),
MaybeUninit::uninit(),
MaybeUninit::uninit(),
MaybeUninit::uninit(),
MaybeUninit::uninit(),
MaybeUninit::uninit(),
MaybeUninit::uninit(),
MaybeUninit::uninit(),
MaybeUninit::uninit(),
MaybeUninit::uninit(),
MaybeUninit::uninit(),
MaybeUninit::uninit(),
MaybeUninit::uninit(),
MaybeUninit::uninit(),
MaybeUninit::uninit(),
MaybeUninit::uninit(),
MaybeUninit::uninit(),
MaybeUninit::uninit(),
MaybeUninit::uninit(),
MaybeUninit::uninit(),
MaybeUninit::uninit(),
MaybeUninit::uninit(),
MaybeUninit::uninit(),
MaybeUninit::uninit(),
MaybeUninit::uninit(),
];
let mut ptr = 0;
let page = txn.load_page(db.db)?;
stack[0] = MaybeUninit::new(cursor::PageCursor {
cursor: P::cursor_before(&page),
page,
});
loop {
let cur = unsafe { &mut *stack[ptr].as_mut_ptr() };
let rc = txn.rc(cur.page.offset)?;
if rc <= 1 {
if let Some((k, v, _)) = P::current(txn, cur.page.as_page(), &cur.cursor) {
for o in k.page_references().chain(v.page_references()) {
txn.decr_rc(o)?;
}
}
if P::move_next(&mut cur.cursor) {
let r = P::left_child(cur.page.as_page(), &cur.cursor);
if r > 0 {
ptr += 1;
let page = txn.load_page(r)?;
stack[ptr] = MaybeUninit::new(cursor::PageCursor {
cursor: P::cursor_before(&page),
page,
})
}
continue;
}
}
if cur.page.is_dirty() {
txn.decr_rc_owned(cur.page.offset)?;
} else {
txn.decr_rc(cur.page.offset)?;
}
if ptr == 0 {
break;
} else {
ptr -= 1;
}
}
Ok(())
}