-
Notifications
You must be signed in to change notification settings - Fork 14
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Delegate branch-storage logic to the branch mod #373
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||||
---|---|---|---|---|---|---|---|---|---|---|
|
@@ -4,14 +4,21 @@ | |||||||||
use super::{Data, Encoded, Node}; | ||||||||||
use crate::{ | ||||||||||
merkle::{PartialPath, TRIE_HASH_LEN}, | ||||||||||
shale::DiskAddress, | ||||||||||
shale::ShaleStore, | ||||||||||
shale::{DiskAddress, Storable}, | ||||||||||
}; | ||||||||||
use bincode::{Error, Options}; | ||||||||||
use std::fmt::{Debug, Error as FmtError, Formatter}; | ||||||||||
use std::{ | ||||||||||
fmt::{Debug, Error as FmtError, Formatter}, | ||||||||||
io::{Cursor, Write}, | ||||||||||
mem::size_of, | ||||||||||
ops::Deref, | ||||||||||
}; | ||||||||||
|
||||||||||
pub type DataLen = u32; | ||||||||||
pub type EncodedChildLen = u8; | ||||||||||
|
||||||||||
pub const MAX_CHILDREN: usize = 16; | ||||||||||
pub const SIZE: usize = MAX_CHILDREN + 1; | ||||||||||
const MAX_CHILDREN: usize = 16; | ||||||||||
|
||||||||||
#[derive(PartialEq, Eq, Clone)] | ||||||||||
pub struct BranchNode { | ||||||||||
|
@@ -50,11 +57,14 @@ impl Debug for BranchNode { | |||||||||
} | ||||||||||
|
||||||||||
impl BranchNode { | ||||||||||
pub const MAX_CHILDREN: usize = MAX_CHILDREN; | ||||||||||
pub const MSIZE: usize = Self::MAX_CHILDREN + 1; | ||||||||||
|
||||||||||
pub fn new( | ||||||||||
_path: PartialPath, | ||||||||||
chd: [Option<DiskAddress>; MAX_CHILDREN], | ||||||||||
chd: [Option<DiskAddress>; Self::MAX_CHILDREN], | ||||||||||
value: Option<Vec<u8>>, | ||||||||||
chd_encoded: [Option<Vec<u8>>; MAX_CHILDREN], | ||||||||||
chd_encoded: [Option<Vec<u8>>; Self::MAX_CHILDREN], | ||||||||||
) -> Self { | ||||||||||
BranchNode { | ||||||||||
// path, | ||||||||||
|
@@ -68,19 +78,19 @@ impl BranchNode { | |||||||||
&self.value | ||||||||||
} | ||||||||||
|
||||||||||
pub fn chd(&self) -> &[Option<DiskAddress>; MAX_CHILDREN] { | ||||||||||
pub fn chd(&self) -> &[Option<DiskAddress>; Self::MAX_CHILDREN] { | ||||||||||
&self.children | ||||||||||
} | ||||||||||
|
||||||||||
pub fn chd_mut(&mut self) -> &mut [Option<DiskAddress>; MAX_CHILDREN] { | ||||||||||
pub fn chd_mut(&mut self) -> &mut [Option<DiskAddress>; Self::MAX_CHILDREN] { | ||||||||||
&mut self.children | ||||||||||
} | ||||||||||
|
||||||||||
pub fn chd_encode(&self) -> &[Option<Vec<u8>>; MAX_CHILDREN] { | ||||||||||
pub fn chd_encode(&self) -> &[Option<Vec<u8>>; Self::MAX_CHILDREN] { | ||||||||||
&self.children_encoded | ||||||||||
} | ||||||||||
|
||||||||||
pub fn chd_encoded_mut(&mut self) -> &mut [Option<Vec<u8>>; MAX_CHILDREN] { | ||||||||||
pub fn chd_encoded_mut(&mut self) -> &mut [Option<Vec<u8>>; Self::MAX_CHILDREN] { | ||||||||||
&mut self.children_encoded | ||||||||||
} | ||||||||||
|
||||||||||
|
@@ -109,7 +119,7 @@ impl BranchNode { | |||||||||
let value = Some(data).filter(|data| !data.is_empty()); | ||||||||||
|
||||||||||
// encode all children. | ||||||||||
let mut chd_encoded: [Option<Vec<u8>>; MAX_CHILDREN] = Default::default(); | ||||||||||
let mut chd_encoded: [Option<Vec<u8>>; Self::MAX_CHILDREN] = Default::default(); | ||||||||||
|
||||||||||
// we popped the last element, so their should only be NBRANCH items left | ||||||||||
for (i, chd) in items.into_iter().enumerate() { | ||||||||||
|
@@ -122,15 +132,15 @@ impl BranchNode { | |||||||||
|
||||||||||
Ok(BranchNode::new( | ||||||||||
path, | ||||||||||
[None; MAX_CHILDREN], | ||||||||||
[None; Self::MAX_CHILDREN], | ||||||||||
value, | ||||||||||
chd_encoded, | ||||||||||
)) | ||||||||||
} | ||||||||||
|
||||||||||
pub(super) fn encode<S: ShaleStore<Node>>(&self, store: &S) -> Vec<u8> { | ||||||||||
// TODO: add path to encoded node | ||||||||||
let mut list = <[Encoded<Vec<u8>>; MAX_CHILDREN + 1]>::default(); | ||||||||||
let mut list = <[Encoded<Vec<u8>>; Self::MAX_CHILDREN + 1]>::default(); | ||||||||||
|
||||||||||
for (i, c) in self.children.iter().enumerate() { | ||||||||||
match c { | ||||||||||
|
@@ -170,7 +180,7 @@ impl BranchNode { | |||||||||
} | ||||||||||
|
||||||||||
if let Some(Data(val)) = &self.value { | ||||||||||
list[MAX_CHILDREN] = | ||||||||||
list[Self::MAX_CHILDREN] = | ||||||||||
Encoded::Data(bincode::DefaultOptions::new().serialize(val).unwrap()); | ||||||||||
} | ||||||||||
|
||||||||||
|
@@ -179,3 +189,59 @@ impl BranchNode { | |||||||||
.unwrap() | ||||||||||
} | ||||||||||
} | ||||||||||
|
||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I will have to review this later to verify it didn't change. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You actually do not have to verify that it didn't change. What you have to verify is that we have tests that make sure that things that we serialize can also be deserialized since we have no burden of backward compatibility (yet). There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||||||||||
impl Storable for BranchNode { | ||||||||||
fn serialized_len(&self) -> u64 { | ||||||||||
let children_len = Self::MAX_CHILDREN as u64 * DiskAddress::MSIZE; | ||||||||||
let data_len = optional_data_len::<DataLen, _>(self.value.as_deref()); | ||||||||||
let children_encoded_len = self.children_encoded.iter().fold(0, |len, child| { | ||||||||||
len + optional_data_len::<EncodedChildLen, _>(child.as_ref()) | ||||||||||
Comment on lines
+197
to
+198
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit: readability:
Suggested change
|
||||||||||
}); | ||||||||||
|
||||||||||
children_len + data_len + children_encoded_len | ||||||||||
} | ||||||||||
|
||||||||||
fn serialize(&self, to: &mut [u8]) -> Result<(), crate::shale::ShaleError> { | ||||||||||
let mut cursor = Cursor::new(to); | ||||||||||
|
||||||||||
for child in &self.children { | ||||||||||
let bytes = child.map(|addr| addr.to_le_bytes()).unwrap_or_default(); | ||||||||||
cursor.write_all(&bytes)?; | ||||||||||
} | ||||||||||
|
||||||||||
let (value_len, value) = self | ||||||||||
.value | ||||||||||
.as_ref() | ||||||||||
.map(|val| (val.len() as DataLen, val.deref())) | ||||||||||
.unwrap_or((DataLen::MAX, &[])); | ||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit: This needs a new const somewhere (with a comment) since this isn't actually MAX. Maybe |
||||||||||
|
||||||||||
cursor.write_all(&value_len.to_le_bytes())?; | ||||||||||
cursor.write_all(value)?; | ||||||||||
|
||||||||||
for child_encoded in &self.children_encoded { | ||||||||||
let (child_len, child) = child_encoded | ||||||||||
.as_ref() | ||||||||||
.map(|child| (child.len() as EncodedChildLen, child.as_slice())) | ||||||||||
.unwrap_or((EncodedChildLen::MIN, &[])); | ||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. similar comment. Using MAX and MIN is magics reduces readability |
||||||||||
|
||||||||||
cursor.write_all(&child_len.to_le_bytes())?; | ||||||||||
cursor.write_all(child)?; | ||||||||||
} | ||||||||||
|
||||||||||
Ok(()) | ||||||||||
} | ||||||||||
|
||||||||||
fn deserialize<T: crate::shale::CachedStore>( | ||||||||||
_addr: usize, | ||||||||||
_mem: &T, | ||||||||||
) -> Result<Self, crate::shale::ShaleError> | ||||||||||
where | ||||||||||
Self: Sized, | ||||||||||
{ | ||||||||||
todo!() | ||||||||||
} | ||||||||||
} | ||||||||||
|
||||||||||
fn optional_data_len<Len, T: AsRef<[u8]>>(data: Option<T>) -> u64 { | ||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This method needs a comment that describes what it does, and maybe better names, so if you mouse over it you can see what it does:
Suggested change
I'm also not convinced this is any more readable than either (a) just inlining the |
||||||||||
size_of::<Len>() as u64 + data.as_ref().map_or(0, |data| data.as_ref().len() as u64) | ||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Remove unnecessary as_ref(), which is just changing Option to Option<&T>:
Suggested change
I wonder why clippy doesn't care about this. |
||||||||||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
😆