Skip to content

Commit

Permalink
feat: add btree deletion
Browse files Browse the repository at this point in the history
  • Loading branch information
peeeuzin committed Dec 5, 2024
1 parent cd0ec3e commit cc1a137
Show file tree
Hide file tree
Showing 6 changed files with 87 additions and 29 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@ Cargo.lock

# Test folders
/test_data
/example
1 change: 0 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ serde = { version = "1.0", features = ["derive"] }
bloomfilter = "1.0"
fs2 = "0.4.3"
bincode = "1.3.3"
rand = "0.8.5"

[build-dependencies]
hooky-rs = "1.0.0"
55 changes: 36 additions & 19 deletions src/btree/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -248,16 +248,19 @@ impl<

let mut results = Vec::new();

for index in 0..=node.page.len() {
for index in 0..node.page.len() {
let child = node.child(index)?;

if node.page.len() / 2 == index {
results.extend(node.page.values()?);
}

if let Some(child) = child {
results.extend(self.cells_from_subtree(child)?)
}

results.extend(node.page.read(index)?);
}

let right = node.child(node.page.len())?;
if let Some(right) = right {
results.extend(self.cells_from_subtree(right)?)
}

Ok(results)
Expand Down Expand Up @@ -290,10 +293,10 @@ impl<
let page = node.page.compact()?;

self.io
.write_page(page_number.into(), &page)
.write_page(search.page.into(), &page)
.map_err(Error::IoError)?;

self.borrow_if_needed(page_number, parents, key)
self.borrow_if_needed(search.page, parents, key)
}

fn borrow_if_needed(
Expand Down Expand Up @@ -326,42 +329,56 @@ impl<
Either::Left(index) => index,
Either::Right(index) => index,
};
let sibling_index = match index > 0 {
false => index + 1,
true => index - 1,
};

let sibling_index = if index > 0 { index - 1 } else { index + 1 };
let mut cell = parent.page.read(sibling_index)?.unwrap();
let sibling_page_index = parent.child(sibling_index)?.unwrap();

let sibling: BTreeNode<K, V> = self
.io
.read_page(cell.left_child.unwrap().into())
.read_page(sibling_page_index.into())
.map_err(Error::IoError)?
.try_into()?;
let merged_node_idx = cmp::min(index, sibling_index);

let mut merged_node = node.merge(sibling)?;

cell.left_child = merged_node.header.right_child;
let merged_node_idx = cmp::min(index, sibling_index);

parent.page.delete(sibling_index)?;
let cell = parent.page.read(merged_node_idx)?.unwrap();
parent.page.delete(merged_node_idx)?;
let mut parent: BTreeNode<K, V> = parent.page.compact()?.try_into()?;

merged_node.page.insert(merged_node_idx, cell)?;
let mut merged_node = node.merge(sibling, cell)?;

let merged_page_index = self
.io
.write_new_page(&merged_node.page)
.map_err(Error::IoError)?;

if parent.header.kind == PageType::Root && parent.page.is_empty() {
if parent.is_root() && parent.page.is_empty() {
merged_node.header.kind = PageType::Root;
merged_node
.page
.write_special(&merged_node.header.to_bytes())?;

self.io
.write_page(merged_page_index.into(), &merged_node.page)
.map_err(Error::IoError)?;

self.root = merged_page_index
} else {
parent.set_child(sibling_index, merged_page_index)?;
parent.set_child(merged_node_idx, merged_page_index)?;
}

self.io
.write_page(parent_index.into(), &parent.page)
.map_err(Error::IoError)?;

self.borrow_if_needed(parents.pop().unwrap(), parents, key)
if let Some(parent) = parents.pop() {
self.borrow_if_needed(parent, parents, key)?;
}

Ok(())
}
}

Expand Down
53 changes: 47 additions & 6 deletions src/btree/node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,10 @@ impl<
}
}

pub fn is_root(&self) -> bool {
self.header.kind == PageType::Root
}

pub fn split(mut self, b: u16) -> Result<BTreeNodeSplited<K, V>> {
// split page cells at the middle
let mut sibling_cells = self.page.split_off(b - 1)?;
Expand Down Expand Up @@ -94,15 +98,52 @@ impl<
Ok(())
}

pub fn merge(mut self, mut node: Self) -> Result<Self> {
let node_values = node.page.values()?;
self.page.write_all(node_values)?;
pub fn max_key(&mut self) -> Result<Option<K>> {
if self.page.is_empty() {
return Ok(None);
}

Ok(self.page.read(self.page.len() - 1)?.map(|e| e.key))
}

pub fn min_key(&mut self) -> Result<Option<K>> {
if self.page.is_empty() {
return Ok(None);
}

Ok(self.page.read(0)?.map(|e| e.key))
}

pub fn merge(mut self, mut other: Self, mut cell: BTreeCell<K, V>) -> Result<Self> {
let new_page_header = BTreePageHeader::new(self.header.kind, None);
match self.min_key()? >= other.min_key()? {
// merge with left sibling node
true => {
cell.left_child = other.header.right_child;
}
// merge with right sibling node
false => {
cell.left_child = self.header.right_child;
self.header.right_child = other.header.right_child
}
};

let node_values = self.page.values()?.into_iter();
let other_values = other.page.values()?.into_iter();

let mut merged_values = node_values
.chain(other_values)
.collect::<Vec<BTreeCell<K, V>>>();

merged_values.push(cell);

self.header.right_child = node.header.right_child;
merged_values.sort_by(|a, b| a.key.cmp(&b.key));

self.page.write_special(&self.header.to_bytes())?;
let mut page: Page<BTreeCell<K, V>> = Page::create(self.page.special_size())?;
page.write_all(merged_values)?;
page.write_special(&new_page_header.to_bytes())?;

Ok(self)
page.try_into()
}
}

Expand Down
4 changes: 2 additions & 2 deletions src/btree/spec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,13 @@ pub struct BTreeCell<K, V> {

pub const BTREE_PAGE_HEADER_SIZE: u16 = 9;

#[derive(Serialize, Deserialize, Debug)]
#[derive(Serialize, Deserialize, Debug, PartialEq, PartialOrd)]
pub struct BTreePageHeader {
pub kind: PageType,
pub right_child: Option<PageNumber>,
}

#[derive(Debug, PartialEq, Eq, Serialize, Deserialize, Copy, Clone)]
#[derive(Debug, PartialEq, Eq, Serialize, Deserialize, Copy, Clone, PartialOrd, Ord)]
pub enum PageType {
Leaf = 0,
Internal = 1,
Expand Down
2 changes: 1 addition & 1 deletion src/page.rs
Original file line number Diff line number Diff line change
Expand Up @@ -437,7 +437,7 @@ impl<T: Serialize + DeserializeOwned + PartialOrd + Ord + Clone> Page<T> {
PAGE_HEADER_SIZE
}

fn special_size(&self) -> u16 {
pub fn special_size(&self) -> u16 {
PAGE_SIZE - self.header.special
}

Expand Down

0 comments on commit cc1a137

Please sign in to comment.