added parents to nodehandle
This commit is contained in:
parent
6a462422a8
commit
cc0b4b817f
|
@ -21,6 +21,7 @@ zerocopy = "0.6.1"
|
|||
crc = "3.0.1"
|
||||
thiserror = { version = "1.0", package = "thiserror-core", default-features = false }
|
||||
num_enum = {version = "0.5.11", default-features = false}
|
||||
replace_with = "0.1.7"
|
||||
|
||||
[dev-dependencies]
|
||||
env_logger = "*"
|
||||
|
|
|
@ -60,10 +60,12 @@ type BoxedNode = Rc<Node>;
|
|||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct NodeHandle {
|
||||
parents: Vec<(BoxedNode, u32)>,
|
||||
node: BoxedNode,
|
||||
idx: u32,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Range<R: super::Read> {
|
||||
volume: Rc<Volume<R>>,
|
||||
parents: Vec<NodeHandle>,
|
||||
|
@ -271,6 +273,65 @@ impl RootOrEdge {
|
|||
.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 {
|
||||
match self {
|
||||
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 {
|
||||
match &self.inner {
|
||||
BTreeNode::Internal(node) => {
|
||||
|
@ -327,12 +389,14 @@ impl Node {
|
|||
match key.partial_cmp(&child.key) {
|
||||
Some(core::cmp::Ordering::Less) => {
|
||||
return SearchResult::Edge(NodeHandle {
|
||||
parents: Default::default(),
|
||||
node: self.clone(),
|
||||
idx: if i == 0 { 0 } else { i as u32 - 1 },
|
||||
});
|
||||
}
|
||||
Some(core::cmp::Ordering::Equal) | None => {
|
||||
return SearchResult::Edge(NodeHandle {
|
||||
parents: Default::default(),
|
||||
node: self.clone(),
|
||||
idx: i as u32,
|
||||
});
|
||||
|
@ -342,6 +406,7 @@ impl Node {
|
|||
}
|
||||
|
||||
SearchResult::Edge(NodeHandle {
|
||||
parents: Default::default(),
|
||||
node: self.clone(),
|
||||
idx: node.children.len() as u32 - 1,
|
||||
})
|
||||
|
@ -356,6 +421,7 @@ impl Node {
|
|||
// } else
|
||||
if key.eq(&child.key) {
|
||||
return SearchResult::Leaf(NodeHandle {
|
||||
parents: Default::default(),
|
||||
node: self.clone(),
|
||||
idx: i as u32,
|
||||
});
|
||||
|
@ -364,6 +430,7 @@ impl Node {
|
|||
|
||||
log::debug!("key definitely not found!");
|
||||
SearchResult::Edge(NodeHandle {
|
||||
parents: Default::default(),
|
||||
node: self.clone(),
|
||||
idx: node.items.len() as u32 - 1,
|
||||
})
|
||||
|
@ -484,29 +551,53 @@ where
|
|||
type Item = (Item, TreeItem);
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
let handle = match &self.start {
|
||||
RootOrEdge::Root(_) => {
|
||||
self.init_start().expect("error");
|
||||
match &self.start.node.inner {
|
||||
BTreeNode::Internal(_) => None,
|
||||
BTreeNode::Leaf(_) => Some(self.start.into_handle()),
|
||||
if !self.is_empty() {
|
||||
replace_with::replace_with_or_abort(&mut self.start, |start| {
|
||||
match start.into_next_leaf(&self.volume) {
|
||||
Ok(next) => next,
|
||||
Err(next) => next,
|
||||
}
|
||||
}
|
||||
RootOrEdge::Edge(_) => self
|
||||
.advance()
|
||||
.expect("cant advance range")
|
||||
.map(|_| self.start.into_handle()),
|
||||
};
|
||||
});
|
||||
|
||||
handle
|
||||
.map(|handle| handle.parse_item())?
|
||||
.expect("failed to parse item")
|
||||
let item = self.start.as_handle().parse_item().expect("range 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 {
|
||||
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)>> {
|
||||
|
@ -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
|
||||
pub fn advance_down(self) -> NodeHandleAdvanceResult {
|
||||
let header = self.node.inner.header();
|
||||
|
@ -548,7 +756,9 @@ impl NodeHandle {
|
|||
}
|
||||
|
||||
pub fn end(node: BoxedNode) -> Self {
|
||||
let parents = Vec::with_capacity(node.inner.header().level as usize);
|
||||
Self {
|
||||
parents,
|
||||
idx: node.inner.header().nritems.get() - 1,
|
||||
node,
|
||||
}
|
||||
|
|
|
@ -117,6 +117,7 @@ impl<R: super::Read> Volume<R> {
|
|||
}
|
||||
|
||||
fn parse_chunk_tree(mut self) -> Result<Self> {
|
||||
log::debug!("parsing chunk tree");
|
||||
let this = Rc::new(self);
|
||||
|
||||
let chunk_tree =
|
||||
|
@ -124,9 +125,12 @@ impl<R: super::Read> Volume<R> {
|
|||
|
||||
let chunks = chunk_tree
|
||||
.iter()
|
||||
.filter_map(|(item, v)| match v {
|
||||
TreeItem::Chunk(chunk) => Some((item, chunk)),
|
||||
_ => None,
|
||||
.filter_map(|(item, v)| {
|
||||
log::debug!("{:?}", item);
|
||||
match v {
|
||||
TreeItem::Chunk(chunk) => Some((item, chunk)),
|
||||
_ => None,
|
||||
}
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
|
@ -366,6 +370,7 @@ mod tests {
|
|||
let vol = Volume::new(file).expect("volume");
|
||||
let v2 = vol.into_volume2().expect("volume2");
|
||||
|
||||
log::info!("roots:");
|
||||
for (id, v) in v2.roots.iter() {
|
||||
log::info!("[{id:?}] {v:#?}");
|
||||
}
|
||||
|
@ -378,8 +383,12 @@ mod tests {
|
|||
let v2 = vol.into_volume2().expect("volume2");
|
||||
let fs = v2.default_subvolume().expect("default subvol");
|
||||
|
||||
for (id, entry) in fs.fs_root.iter() {
|
||||
log::info!("[{id:?}] {entry:#?}");
|
||||
log::info!("fs_root:");
|
||||
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:#?}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue