Skip to content

Commit

Permalink
wip: step closer to finishing insert
Browse files Browse the repository at this point in the history
  • Loading branch information
Nuhvi committed Dec 20, 2023
1 parent 2c29d02 commit 9e8a483
Show file tree
Hide file tree
Showing 5 changed files with 181 additions and 192 deletions.
153 changes: 73 additions & 80 deletions mast/src/node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,55 +37,42 @@ enum RefCountDiff {
}

impl Node {
pub fn new(key: &[u8], value: &[u8]) -> Self {
Self {
pub(crate) fn open<'a>(
table: &'a impl ReadableTable<&'static [u8], (u64, &'static [u8])>,
hash: Hash,
) -> Option<Node> {
let mut existing = table.get(hash.as_bytes().as_slice()).unwrap();

existing.map(|existing| {
let (ref_count, bytes) = {
let (r, v) = existing.value();
(r, v.to_vec())
};
drop(existing);

decode_node((ref_count, &bytes))
})
}

pub(crate) fn insert(table: &mut Table<&[u8], (u64, &[u8])>, key: &[u8], value: &[u8]) -> Hash {
let node = Self {
key: key.into(),
value: value.into(),
left: None,
right: None,

ref_count: 0,
}
}

pub fn decode(data: (u64, &[u8])) -> Node {
let (ref_count, encoded_node) = data;

let (key, rest) = decode(encoded_node);
let (value, rest) = decode(rest);

let (left, rest) = decode(rest);
let left = match left.len() {
0 => None,
32 => {
let bytes: [u8; HASH_LEN] = left.try_into().unwrap();
Some(Hash::from_bytes(bytes))
}
_ => {
panic!("invalid hash length!")
}
ref_count: 1,
};

let (right, _) = decode(rest);
let right = match right.len() {
0 => None,
32 => {
let bytes: [u8; HASH_LEN] = right.try_into().unwrap();
Some(Hash::from_bytes(bytes))
}
_ => {
panic!("invalid hash length!")
}
};
let encoded = node.canonical_encode();
let hash = hash(&encoded);

Node {
key: key.into(),
value: value.into(),
left,
right,
table.insert(
hash.as_bytes().as_slice(),
(node.ref_count, encoded.as_slice()),
);

ref_count,
}
hash
}

// === Getters ===
Expand Down Expand Up @@ -117,20 +104,16 @@ impl Node {
hash(&self.canonical_encode())
}

pub(crate) fn decrement_ref_count(&self, table: &mut Table<&[u8], (u64, &[u8])>) {}

pub(crate) fn save(&self, table: &mut Table<&[u8], (u64, &[u8])>) {
let encoded = self.canonical_encode();
let hash = hash(&encoded);

table.insert(
hash.as_bytes().as_slice(),
(self.ref_count, encoded.as_slice()),
);
pub(crate) fn decrement_ref_count(&self, table: &mut Table<&[u8], (u64, &[u8])>) {
self.update_ref_count(table, RefCountDiff::Decrement)
}

// === Private Methods ===

fn increment_ref_count(&self, table: &mut Table<&[u8], (u64, &[u8])>) {
self.update_ref_count(table, RefCountDiff::Increment)
}

fn update_ref_count(&self, table: &mut Table<&[u8], (u64, &[u8])>, diff: RefCountDiff) {
let ref_count = match diff {
RefCountDiff::Increment => self.ref_count + 1,
Expand Down Expand Up @@ -175,36 +158,6 @@ pub(crate) fn rank(key: &[u8]) -> Hash {
hash(key)
}

/// Returns the node for a given hash.
pub(crate) fn get_node<'a>(
table: &'a impl ReadableTable<&'static [u8], (u64, &'static [u8])>,
hash: &[u8],
) -> Option<Node> {
let existing = table.get(hash).unwrap();

if existing.is_none() {
return None;
}
let data = existing.unwrap();

Some(Node::decode(data.value()))
}

/// Returns the root hash for a given table.
pub(crate) fn get_root_hash<'a>(
table: &'a impl ReadableTable<&'static [u8], &'static [u8]>,
name: &str,
) -> Option<Hash> {
let existing = table.get(name.as_bytes()).unwrap();
if existing.is_none() {
return None;
}
let hash = existing.unwrap();

let hash: [u8; HASH_LEN] = hash.value().try_into().expect("Invalid root hash");
Some(Hash::from_bytes(hash))
}

fn encode(bytes: &[u8], out: &mut Vec<u8>) {
// TODO: find a better way to reserve bytes.
let current_len = out.len();
Expand All @@ -230,3 +183,43 @@ fn hash(bytes: &[u8]) -> Hash {

hasher.finalize()
}

pub fn decode_node(data: (u64, &[u8])) -> Node {
let (ref_count, encoded_node) = data;

let (key, rest) = decode(encoded_node);
let (value, rest) = decode(rest);

let (left, rest) = decode(rest);
let left = match left.len() {
0 => None,
32 => {
let bytes: [u8; HASH_LEN] = left.try_into().unwrap();
Some(Hash::from_bytes(bytes))
}
_ => {
panic!("invalid hash length!")
}
};

let (right, _) = decode(rest);
let right = match right.len() {
0 => None,
32 => {
let bytes: [u8; HASH_LEN] = right.try_into().unwrap();
Some(Hash::from_bytes(bytes))
}
_ => {
panic!("invalid hash length!")
}
};

Node {
key: key.into(),
value: value.into(),
left,
right,

ref_count,
}
}
56 changes: 0 additions & 56 deletions mast/src/operations/gc.rs

This file was deleted.

100 changes: 61 additions & 39 deletions mast/src/operations/insert.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::node::{get_node, get_root_hash, rank, Branch, Node};
use crate::node::{rank, Branch, Node};
use crate::treap::{HashTreap, NODES_TABLE, ROOTS_TABLE};
use crate::HASH_LEN;
use blake3::Hash;
Expand Down Expand Up @@ -81,61 +81,83 @@ use redb::{Database, ReadTransaction, ReadableTable, Table, TableDefinition, Wri
// The simplest way to do so, is to decrement all the nodes in the search path, and then increment
// all then new nodes (in both the upper and lower paths) before comitting the write transaction.

impl<'treap> HashTreap<'treap> {
pub fn insert(&mut self, key: &[u8], value: &[u8]) {
// TODO: validate key and value length.

let write_txn = self.db.begin_write().unwrap();

'transaction: {
let roots_table = write_txn.open_table(ROOTS_TABLE).unwrap();
let mut nodes_table = write_txn.open_table(NODES_TABLE).unwrap();

let root = get_root_hash(&roots_table, &self.name);
pub fn insert<'a>(
table: &'a mut Table<&'static [u8], (u64, &'static [u8])>,
root: Option<Hash>,
key: &[u8],
value: &[u8],
) {
let mut path = binary_search_path(table, root, key);

let mut path = upper_path(key, root, &nodes_table);
path.iter_mut()
.for_each(|(node, _)| node.decrement_ref_count(table));

path.iter_mut()
.for_each(|node| node.decrement_ref_count(&mut nodes_table))
let mut unzipped_left: Option<Hash> = None;
let mut unzipped_right: Option<Hash> = None;
let mut upper_path: Option<Hash> = None;

// if path.
};
let rank = rank(key);

// Finally commit the changes to the storage.
write_txn.commit().unwrap();
for (node, branch) in path.iter().rev() {
match node.rank().as_bytes().cmp(&rank.as_bytes()) {
std::cmp::Ordering::Equal => {
// We found an exact match, we update the value and proceed.

upper_path = Some(Node::insert(table, key, value))
}
std::cmp::Ordering::Less => {
// previous_hash = *current_node.left();
//
// path.push((current_node, Branch::Left));
}
std::cmp::Ordering::Greater => {
// previous_hash = *current_node.right();
//
// path.push((current_node, Branch::Right));
}
}
}

// if let Some((node, _)) = path.last_mut() {
// // If the last node is an exact match
// } else {
// // handle lower path
// }
}

/// Returns the current nodes from the root to the insertion point on the binary search path.
fn upper_path<'a>(
key: &[u8],
root: Option<Hash>,
fn binary_search_path<'a>(
nodes_table: &'a impl ReadableTable<&'static [u8], (u64, &'static [u8])>,
) -> Vec<Node> {
let rank = rank(key);

let mut path: Vec<Node> = Vec::new();
root: Option<Hash>,
key: &[u8],
) -> Vec<(Node, Branch)> {
let mut path: Vec<(Node, Branch)> = Vec::new();

let mut previous_hash = root;

while let Some(current_hash) = previous_hash {
let current_node = get_node(nodes_table, current_hash.as_bytes()).expect("Node not found!");
let current_node = Node::open(nodes_table, current_hash).expect("Node not found!");

let current_key = current_node.key();

if key == current_key {
// We found an exact match, we don't need to unzip the rest.
path.push(current_node);
break;
}

if key < current_key {
previous_hash = *current_node.left();
} else {
previous_hash = *current_node.right();
match key.cmp(current_key) {
std::cmp::Ordering::Equal => {
// We found an exact match, we don't need to unzip the rest.
// Branch here doesn't matter
path.push((current_node, Branch::Left));
break;
}
std::cmp::Ordering::Less => {
previous_hash = *current_node.left();

path.push((current_node, Branch::Left));
}
std::cmp::Ordering::Greater => {
previous_hash = *current_node.right();

path.push((current_node, Branch::Right));
}
}

path.push(current_node);
}

path
Expand Down
3 changes: 1 addition & 2 deletions mast/src/operations/mod.rs
Original file line number Diff line number Diff line change
@@ -1,2 +1 @@
pub mod gc;
mod insert;
pub mod insert;
Loading

0 comments on commit 9e8a483

Please sign in to comment.