added parents to nodehandle

This commit is contained in:
Janis 2023-03-30 17:33:26 +02:00
parent 6a462422a8
commit cc0b4b817f
3 changed files with 241 additions and 21 deletions

View file

@ -21,6 +21,7 @@ zerocopy = "0.6.1"
crc = "3.0.1" crc = "3.0.1"
thiserror = { version = "1.0", package = "thiserror-core", default-features = false } thiserror = { version = "1.0", package = "thiserror-core", default-features = false }
num_enum = {version = "0.5.11", default-features = false} num_enum = {version = "0.5.11", default-features = false}
replace_with = "0.1.7"
[dev-dependencies] [dev-dependencies]
env_logger = "*" env_logger = "*"

View file

@ -60,10 +60,12 @@ type BoxedNode = Rc<Node>;
#[derive(Debug, Clone, PartialEq, Eq)] #[derive(Debug, Clone, PartialEq, Eq)]
pub struct NodeHandle { pub struct NodeHandle {
parents: Vec<(BoxedNode, u32)>,
node: BoxedNode, node: BoxedNode,
idx: u32, idx: u32,
} }
#[derive(Debug)]
pub struct Range<R: super::Read> { pub struct Range<R: super::Read> {
volume: Rc<Volume<R>>, volume: Rc<Volume<R>>,
parents: Vec<NodeHandle>, parents: Vec<NodeHandle>,
@ -271,6 +273,65 @@ impl RootOrEdge {
.clone() .clone()
} }
pub fn into_next_leaf_any<R, F>(
self,
volume: &super::volume::Volume<R>,
f: F,
) -> core::result::Result<Self, Self>
where
F: Fn(
NodeHandle,
&super::volume::Volume<R>,
) -> core::result::Result<NodeHandle, NodeHandle>,
R: super::Read,
{
let mut node = match self {
RootOrEdge::Root(root) => {
// use self if is leaf already, otherwise forward to next leaf
if root.node.inner.is_leaf() {
return Ok(Self::Edge(root));
} else {
root
}
}
RootOrEdge::Edge(edge) => edge,
};
let leaf = loop {
match f(node, volume) {
Ok(next) => {
if next.node.inner.is_leaf() {
break Ok(next);
} else {
node = next;
}
}
Err(last) => {
break Err(Self::Edge(last));
}
}
};
// turn leaf into Self::Edge
leaf.map(|leaf| Self::Edge(leaf))
}
/// returns the next RootOrEdge, or the end of the tree as Err
pub fn into_next_leaf<R: super::Read>(
self,
volume: &super::volume::Volume<R>,
) -> core::result::Result<Self, Self> {
self.into_next_leaf_any(volume, NodeHandle::into_next)
}
/// returns the next RootOrEdge, or the end of the tree as Err, in reverse direction
pub fn into_next_back_leaf<R: super::Read>(
self,
volume: &super::volume::Volume<R>,
) -> core::result::Result<Self, Self> {
self.into_next_leaf_any(volume, NodeHandle::into_next_back)
}
pub fn as_handle(&self) -> &NodeHandle { pub fn as_handle(&self) -> &NodeHandle {
match self { match self {
RootOrEdge::Root(handle) => handle, RootOrEdge::Root(handle) => handle,
@ -320,6 +381,7 @@ impl Node {
} }
} }
// TODO: move this to nodehandle
pub fn find_key<K: PartialEq<Key> + PartialOrd<Key>>(self: &Rc<Self>, key: &K) -> SearchResult { pub fn find_key<K: PartialEq<Key> + PartialOrd<Key>>(self: &Rc<Self>, key: &K) -> SearchResult {
match &self.inner { match &self.inner {
BTreeNode::Internal(node) => { BTreeNode::Internal(node) => {
@ -327,12 +389,14 @@ impl Node {
match key.partial_cmp(&child.key) { match key.partial_cmp(&child.key) {
Some(core::cmp::Ordering::Less) => { Some(core::cmp::Ordering::Less) => {
return SearchResult::Edge(NodeHandle { return SearchResult::Edge(NodeHandle {
parents: Default::default(),
node: self.clone(), node: self.clone(),
idx: if i == 0 { 0 } else { i as u32 - 1 }, idx: if i == 0 { 0 } else { i as u32 - 1 },
}); });
} }
Some(core::cmp::Ordering::Equal) | None => { Some(core::cmp::Ordering::Equal) | None => {
return SearchResult::Edge(NodeHandle { return SearchResult::Edge(NodeHandle {
parents: Default::default(),
node: self.clone(), node: self.clone(),
idx: i as u32, idx: i as u32,
}); });
@ -342,6 +406,7 @@ impl Node {
} }
SearchResult::Edge(NodeHandle { SearchResult::Edge(NodeHandle {
parents: Default::default(),
node: self.clone(), node: self.clone(),
idx: node.children.len() as u32 - 1, idx: node.children.len() as u32 - 1,
}) })
@ -356,6 +421,7 @@ impl Node {
// } else // } else
if key.eq(&child.key) { if key.eq(&child.key) {
return SearchResult::Leaf(NodeHandle { return SearchResult::Leaf(NodeHandle {
parents: Default::default(),
node: self.clone(), node: self.clone(),
idx: i as u32, idx: i as u32,
}); });
@ -364,6 +430,7 @@ impl Node {
log::debug!("key definitely not found!"); log::debug!("key definitely not found!");
SearchResult::Edge(NodeHandle { SearchResult::Edge(NodeHandle {
parents: Default::default(),
node: self.clone(), node: self.clone(),
idx: node.items.len() as u32 - 1, idx: node.items.len() as u32 - 1,
}) })
@ -484,29 +551,53 @@ where
type Item = (Item, TreeItem); type Item = (Item, TreeItem);
fn next(&mut self) -> Option<Self::Item> { fn next(&mut self) -> Option<Self::Item> {
let handle = match &self.start { if !self.is_empty() {
RootOrEdge::Root(_) => { replace_with::replace_with_or_abort(&mut self.start, |start| {
self.init_start().expect("error"); match start.into_next_leaf(&self.volume) {
match &self.start.node.inner { Ok(next) => next,
BTreeNode::Internal(_) => None, Err(next) => next,
BTreeNode::Leaf(_) => Some(self.start.into_handle()),
} }
} });
RootOrEdge::Edge(_) => self
.advance()
.expect("cant advance range")
.map(|_| self.start.into_handle()),
};
handle let item = self.start.as_handle().parse_item().expect("range item");
.map(|handle| handle.parse_item())?
.expect("failed to parse item") item
} else {
None
}
}
}
impl<R> DoubleEndedIterator for Range<R>
where
R: super::Read,
{
fn next_back(&mut self) -> Option<Self::Item> {
if !self.is_empty() {
replace_with::replace_with_or_abort(&mut self.end, |end| {
match end.into_next_back_leaf(&self.volume) {
Ok(next) => next,
Err(next) => next,
}
});
let item = self.start.as_handle().parse_item().expect("range item");
item
} else {
None
}
} }
} }
impl NodeHandle { impl NodeHandle {
pub fn start(node: BoxedNode) -> Self { pub fn start(node: BoxedNode) -> Self {
Self { node, idx: 0 } let parents = Vec::with_capacity(node.inner.header().level as usize);
Self {
node,
parents,
idx: 0,
}
} }
pub fn parse_item(&self) -> Result<Option<(Item, TreeItem)>> { pub fn parse_item(&self) -> Result<Option<(Item, TreeItem)>> {
@ -528,6 +619,123 @@ impl NodeHandle {
} }
} }
// needs reference to volume to be able to read children key_ptrs
// this is a live reference so if in the future I want to have a &mut to something in Volume
// greppable: volume ref
pub fn into_next_back<R: super::Read>(
self,
volume: &super::volume::Volume<R>,
) -> core::result::Result<Self, Self> {
let Self {
mut parents,
node,
idx,
} = self;
if idx < 1 {
// go up
match parents.pop() {
Some((node, idx)) => Self { node, idx, parents }.into_next_back(volume),
None => Err(Self { node, idx, parents }),
}
} else {
match &node.inner {
BTreeNode::Internal(internal) => {
let child_ptr = *internal
.children
.get(idx as usize)
.expect("no children in node");
let node = match volume
.read_keyptr(&child_ptr)
.and_then(|bytes| Node::from_bytes(bytes))
.map(|node| Rc::new(node))
{
Ok(child) => {
parents.push((node, idx));
Ok(Self {
parents,
idx: child.inner.header().nritems.get() - 1,
node: child,
})
}
Err(_) => Err(Self { parents, node, idx }),
};
// TODO: better error or panic here? this would return self, indicating the end of the tree, even though we simply failed to retrieve the next node
node
}
BTreeNode::Leaf(_) => Ok(Self {
idx: idx - 1,
parents,
node,
}),
}
}
}
// needs reference to volume to be able to read children key_ptrs
// this is a live reference so if in the future I want to have a &mut to something in Volume
// greppable: volume ref
/// returns Ok(next) or Err(self) if self is already the last node
pub fn into_next<R: super::Read>(
self,
volume: &super::volume::Volume<R>,
) -> core::result::Result<Self, Self> {
let Self {
mut parents,
node,
idx,
} = self;
let header = node.inner.header();
if idx + 1 >= header.nritems.get() {
// go up
match parents.pop() {
Some((node, idx)) => Self {
node,
idx: idx + 1,
parents,
}
.into_next(volume),
None => Err(Self { node, idx, parents }),
}
} else {
match &node.inner {
BTreeNode::Internal(internal) => {
let child_ptr = *internal
.children
.get(idx as usize)
.expect("no children in node");
let node = match volume
.read_keyptr(&child_ptr)
.and_then(|bytes| Node::from_bytes(bytes))
.map(|node| Rc::new(node))
{
Ok(child) => {
parents.push((node, idx));
Ok(Self {
parents,
idx: 0,
node: child,
})
}
Err(_) => Err(Self { parents, node, idx }),
};
// TODO: better error or panic here? this would return self, indicating the end of the tree, even though we simply failed to retrieve the next node
node
}
BTreeNode::Leaf(_) => Ok(Self {
idx: idx + 1,
parents,
node,
}),
}
}
}
// returns the next node in ascending sequential order // returns the next node in ascending sequential order
pub fn advance_down(self) -> NodeHandleAdvanceResult { pub fn advance_down(self) -> NodeHandleAdvanceResult {
let header = self.node.inner.header(); let header = self.node.inner.header();
@ -548,7 +756,9 @@ impl NodeHandle {
} }
pub fn end(node: BoxedNode) -> Self { pub fn end(node: BoxedNode) -> Self {
let parents = Vec::with_capacity(node.inner.header().level as usize);
Self { Self {
parents,
idx: node.inner.header().nritems.get() - 1, idx: node.inner.header().nritems.get() - 1,
node, node,
} }

View file

@ -117,6 +117,7 @@ impl<R: super::Read> Volume<R> {
} }
fn parse_chunk_tree(mut self) -> Result<Self> { fn parse_chunk_tree(mut self) -> Result<Self> {
log::debug!("parsing chunk tree");
let this = Rc::new(self); let this = Rc::new(self);
let chunk_tree = let chunk_tree =
@ -124,9 +125,12 @@ impl<R: super::Read> Volume<R> {
let chunks = chunk_tree let chunks = chunk_tree
.iter() .iter()
.filter_map(|(item, v)| match v { .filter_map(|(item, v)| {
log::debug!("{:?}", item);
match v {
TreeItem::Chunk(chunk) => Some((item, chunk)), TreeItem::Chunk(chunk) => Some((item, chunk)),
_ => None, _ => None,
}
}) })
.collect::<Vec<_>>(); .collect::<Vec<_>>();
@ -366,6 +370,7 @@ mod tests {
let vol = Volume::new(file).expect("volume"); let vol = Volume::new(file).expect("volume");
let v2 = vol.into_volume2().expect("volume2"); let v2 = vol.into_volume2().expect("volume2");
log::info!("roots:");
for (id, v) in v2.roots.iter() { for (id, v) in v2.roots.iter() {
log::info!("[{id:?}] {v:#?}"); log::info!("[{id:?}] {v:#?}");
} }
@ -378,8 +383,12 @@ mod tests {
let v2 = vol.into_volume2().expect("volume2"); let v2 = vol.into_volume2().expect("volume2");
let fs = v2.default_subvolume().expect("default subvol"); let fs = v2.default_subvolume().expect("default subvol");
for (id, entry) in fs.fs_root.iter() { log::info!("fs_root:");
log::info!("[{id:?}] {entry:#?}"); for (_id, entry) in fs.fs_root.iter() {
if let Some(dir) = entry.as_dir_index() {
log::info!("{}", dir.name_as_string_lossy());
}
// log::info!("[{id:?}] {entry:#?}");
} }
} }
} }