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"
|
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 = "*"
|
||||||
|
|
|
@ -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,
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)| {
|
||||||
TreeItem::Chunk(chunk) => Some((item, chunk)),
|
log::debug!("{:?}", item);
|
||||||
_ => None,
|
match v {
|
||||||
|
TreeItem::Chunk(chunk) => Some((item, chunk)),
|
||||||
|
_ => 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:#?}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue