diff --git a/.gitignore b/.gitignore index edd7a91..4f32027 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,4 @@ Cargo.lock # Test folders /test_data +/example diff --git a/Cargo.toml b/Cargo.toml index 5033738..776edc4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -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" diff --git a/src/btree/mod.rs b/src/btree/mod.rs index 020a710..332047c 100644 --- a/src/btree/mod.rs +++ b/src/btree/mod.rs @@ -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) @@ -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( @@ -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 = 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 = 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(()) } } diff --git a/src/btree/node.rs b/src/btree/node.rs index e5401c8..4eb8dc9 100644 --- a/src/btree/node.rs +++ b/src/btree/node.rs @@ -37,6 +37,10 @@ impl< } } + pub fn is_root(&self) -> bool { + self.header.kind == PageType::Root + } + pub fn split(mut self, b: u16) -> Result> { // split page cells at the middle let mut sibling_cells = self.page.split_off(b - 1)?; @@ -94,15 +98,52 @@ impl< Ok(()) } - pub fn merge(mut self, mut node: Self) -> Result { - let node_values = node.page.values()?; - self.page.write_all(node_values)?; + pub fn max_key(&mut self) -> Result> { + 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> { + 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) -> Result { + 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::>>(); + + 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> = Page::create(self.page.special_size())?; + page.write_all(merged_values)?; + page.write_special(&new_page_header.to_bytes())?; - Ok(self) + page.try_into() } } diff --git a/src/btree/spec.rs b/src/btree/spec.rs index 2cb8c45..de6b00b 100644 --- a/src/btree/spec.rs +++ b/src/btree/spec.rs @@ -11,13 +11,13 @@ pub struct BTreeCell { 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, } -#[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, diff --git a/src/page.rs b/src/page.rs index e944fd7..1e66312 100644 --- a/src/page.rs +++ b/src/page.rs @@ -437,7 +437,7 @@ impl Page { PAGE_HEADER_SIZE } - fn special_size(&self) -> u16 { + pub fn special_size(&self) -> u16 { PAGE_SIZE - self.header.special }