diff --git a/mast/src/node.rs b/mast/src/node.rs index f579db4..de901a2 100644 --- a/mast/src/node.rs +++ b/mast/src/node.rs @@ -106,20 +106,20 @@ impl Node { } /// Set the left child, save the updated node, and return the new hash. - pub(crate) fn set_left_child(&mut self, child: Option<&mut Node>) -> &mut Self { + pub(crate) fn set_left_child(&mut self, child: Option) -> &mut Self { self.set_child(Branch::Left, child) } /// Set the right child, save the updated node, and return the new hash. - pub(crate) fn set_right_child(&mut self, child: Option<&mut Node>) -> &mut Self { + pub(crate) fn set_right_child(&mut self, child: Option) -> &mut Self { self.set_child(Branch::Right, child) } /// Set the child, update its ref_count, save the updated node and return it. - fn set_child(&mut self, branch: Branch, new_child: Option<&mut Node>) -> &mut Self { + fn set_child(&mut self, branch: Branch, new_child: Option) -> &mut Self { match branch { - Branch::Left => self.left = new_child.as_ref().map(|n| n.hash()), - Branch::Right => self.right = new_child.as_ref().map(|n| n.hash()), + Branch::Left => self.left = new_child, + Branch::Right => self.right = new_child, }; self @@ -150,6 +150,7 @@ impl Node { self } + /// Saves the node to the nodes table by its hash. pub(crate) fn save(&mut self, table: &mut Table<&[u8], (u64, &[u8])>) -> &mut Self { // TODO: keep data in encoded in a bytes field. let encoded = self.canonical_encode(); diff --git a/mast/src/operations/insert.rs b/mast/src/operations/insert.rs index 8a689e4..cc24318 100644 --- a/mast/src/operations/insert.rs +++ b/mast/src/operations/insert.rs @@ -1,6 +1,7 @@ use std::cmp::Ordering; use crate::node::{hash, Branch, Node}; +use blake3::Hash; use redb::Table; // Watch this [video](https://youtu.be/NxRXhBur6Xs?si=GNwaUOfuGwr_tBKI&t=1763) for a good explanation of the unzipping algorithm. @@ -88,39 +89,37 @@ pub fn insert( ) -> Node { let mut path = binary_search_path(nodes_table, root, key); - let mut unzip_left_root: Option<&mut Node> = None; - let mut unzip_right_root: Option<&mut Node> = None; + let mut unzip_left_root: Option = None; + let mut unzip_right_root: Option = None; // Unzip the lower path to get left and right children of the inserted node. for (node, branch) in path.unzip_path.iter_mut().rev() { + // Decrement the old version. node.decrement_ref_count().save(nodes_table); match branch { Branch::Right => { - node.set_right_child(unzip_left_root) - .increment_ref_count() - .save(nodes_table); - - unzip_left_root = Some(node); + node.set_right_child(unzip_left_root); + unzip_left_root = Some(node.hash()); } Branch::Left => { - node.set_left_child(unzip_right_root) - .increment_ref_count() - .save(nodes_table); - - unzip_right_root = Some(node); + node.set_left_child(unzip_right_root); + unzip_right_root = Some(node.hash()); } } + + node.increment_ref_count().save(nodes_table); } - let mut root = path.existing; + let mut root; - if let Some(mut existing) = root { + if let Some(mut existing) = path.existing { if existing.value() == value { // There is really nothing to update. Skip traversing upwards. return path.upper_path.pop().map(|(n, _)| n).unwrap_or(existing); } + // Decrement the old version. existing.decrement_ref_count().save(nodes_table); // Else, update the value and rehashe the node so that we can update the hashes upwards. @@ -129,18 +128,17 @@ pub fn insert( .increment_ref_count() .save(nodes_table); - root = Some(existing) + root = existing } else { // Insert the new node. let mut node = Node::new(key, value); - // TODO: we do hash the node twice here, can we do better? node.set_left_child(unzip_left_root) .set_right_child(unzip_right_root) .increment_ref_count() .save(nodes_table); - root = Some(node); + root = node }; let mut upper_path = path.upper_path; @@ -150,17 +148,17 @@ pub fn insert( node.decrement_ref_count().save(nodes_table); match branch { - Branch::Left => node.set_left_child(root.as_mut()), - Branch::Right => node.set_right_child(root.as_mut()), + Branch::Left => node.set_left_child(Some(root.hash())), + Branch::Right => node.set_right_child(Some(root.hash())), }; node.increment_ref_count().save(nodes_table); - root = Some(node); + root = node; } // Finally return the new root to be set to the root. - root.expect("Root should be set by now") + root } #[derive(Debug)]