use std::os::unix::fs::MetadataExt;
use crate::{value::Value, Db, PAGE_SIZE};
mod cache;
mod cell;
mod rangeiter;
use anyhow::{bail, Context, Result};
use encoding::{decode_page, Page};
pub use rangeiter::*;
use write_op::{write_op, BTreeWriteOp};
mod append;
mod encoding;
mod free;
mod tx;
mod write_op;
impl Db {
pub(super) fn recover(&mut self) -> Result<()> {
self.cached_pages.clear();
self.write_pages.clear();
self.free_list.clear();
(
self.main_tree_root,
self.this_tx_id,
self.next_freelist_ptr,
self.previous_main_root,
self.page_count,
) = if self.file.is_some()
&& self.file.as_ref().unwrap().metadata()?.size() / PAGE_SIZE as u64 > 0
{
let wpc = self.file.as_ref().unwrap().metadata()?.size() / PAGE_SIZE as u64;
let mut range = (0..wpc).rev();
loop {
let page_idx = range.next().unwrap();
match decode_page(&self.get_page(page_idx)?)? {
Page::Footer(root, tx_id, next_freelist, free_pages) => {
self.free_list.extend(free_pages);
self.file
.as_mut()
.unwrap()
.set_len((page_idx + 1) * PAGE_SIZE as u64)
.context("failed setting database file size after recovering")?;
break (root, tx_id + 1, next_freelist, Some(root), wpc);
}
_ => {}
};
if page_idx == 0 {
bail!("failed to find a valid footer page in database file")
}
}
} else {
self.add_header()?;
(
self.append_leaf(Vec::new())?,
1,
None,
None,
self.page_count,
)
};
self.has_recovered = true;
Ok(())
}
pub(super) fn tree_root(&self) -> u64 {
self.main_tree_root
}
pub(super) fn new_tree(&mut self) -> Result<u64> {
self.append_leaf(Vec::new())
}
pub(super) fn delete_tree(&mut self, tree: u64) -> Result<()> {
write_op(self, tree, BTreeWriteOp::DeleteTree)?;
Ok(())
}
pub(super) fn set_value(
&mut self,
tree: u64,
key: Vec<Value>,
value: Vec<Value>,
) -> Result<Option<u64>> {
write_op(self, tree, BTreeWriteOp::Set(key, value))
}
pub(super) fn set_value_root(&mut self, key: Vec<Value>, value: Vec<Value>) -> Result<()> {
if let Some(new_root) = write_op(self, self.main_tree_root, BTreeWriteOp::Set(key, value))?
{
self.main_tree_root = new_root;
}
Ok(())
}
pub(super) fn delete_pair(&mut self, tree: u64, key: Vec<Value>) -> Result<Option<u64>> {
write_op(self, tree, BTreeWriteOp::Delete(key))
}
pub(super) fn delete_pair_root(&mut self, key: Vec<Value>) -> Result<()> {
if let Some(new_root) = write_op(self, self.main_tree_root, BTreeWriteOp::Delete(key))? {
self.main_tree_root = new_root;
}
Ok(())
}
}