stuff
- outofbounds error - caching btrees with rc<node>s after reading from disk/file
This commit is contained in:
parent
9602b399e0
commit
03997b78e7
|
@ -1,5 +1,5 @@
|
|||
//#![allow(dead_code)]
|
||||
#![feature(error_in_core)]
|
||||
#![allow(dead_code)]
|
||||
#![feature(error_in_core, cell_update)]
|
||||
#![cfg_attr(not(any(feature = "std", test)), no_std)]
|
||||
|
||||
use core::{
|
||||
|
@ -22,7 +22,6 @@ use tree::Tree;
|
|||
extern crate alloc;
|
||||
|
||||
pub mod crc32c;
|
||||
pub mod files;
|
||||
pub mod path;
|
||||
pub mod structs;
|
||||
pub mod tree;
|
||||
|
@ -30,7 +29,7 @@ pub mod v2;
|
|||
|
||||
#[cfg(feature = "std")]
|
||||
pub mod std_io {
|
||||
use std::io::{Cursor, Read, Seek};
|
||||
use std::io::{Read, Seek};
|
||||
|
||||
use crate::{Error, VolumeIo};
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use alloc::{collections::VecDeque, vec::Vec};
|
||||
use alloc::collections::VecDeque;
|
||||
|
||||
const SEPERATOR: u8 = b'/';
|
||||
|
||||
|
|
|
@ -23,6 +23,11 @@ pub mod error {
|
|||
NoDefaultSubvolFsRoot,
|
||||
#[error("INode could not be found in FsTree")]
|
||||
INodeNotFound,
|
||||
#[error("attempted to access item out of bounds")]
|
||||
OutOfBounds {
|
||||
range: core::ops::Range<usize>,
|
||||
index: usize,
|
||||
},
|
||||
#[error("Invalid checksum: expected {expected:#?} but got {actual:#?}")]
|
||||
InvalidChecksum {
|
||||
expected: [u8; 32],
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
use core::cell::Cell;
|
||||
use core::fmt::Display;
|
||||
use core::mem::size_of;
|
||||
use core::ops::Deref;
|
||||
|
@ -20,11 +21,98 @@ pub struct BTreeLeafNode {
|
|||
pub items: Vec<Item>,
|
||||
}
|
||||
|
||||
/// An internal node in a btrfs tree, containing `KeyPtr`s to other internal nodes or leaf nodes.
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum NodePtr {
|
||||
Unvisited(KeyPtr),
|
||||
Visited { key: KeyPtr, node: Rc<Node> }, // TODO: this doesnt need to be an Rc, can just be a NonNull with manual memory management
|
||||
}
|
||||
|
||||
impl NodePtr {
|
||||
pub fn key_ptr(&self) -> &KeyPtr {
|
||||
match self {
|
||||
NodePtr::Unvisited(key) => key,
|
||||
NodePtr::Visited { key, node } => key,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn node(&self) -> Option<&Rc<Node>> {
|
||||
match self {
|
||||
NodePtr::Unvisited(_) => None,
|
||||
NodePtr::Visited { node, .. } => Some(&node),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn key(&self) -> &Key {
|
||||
&self.key_ptr().key
|
||||
}
|
||||
}
|
||||
|
||||
/// An internal node in a btrfs tree, containing `KeyPtr`s to other internal nodes or leaf nodes.
|
||||
#[derive(Derivative)]
|
||||
#[derivative(Debug)]
|
||||
pub struct BTreeInternalNode {
|
||||
pub header: Header,
|
||||
pub children: Vec<KeyPtr>,
|
||||
#[derivative(Debug = "ignore")]
|
||||
children: Vec<Cell<NodePtr>>,
|
||||
}
|
||||
|
||||
impl BTreeInternalNode {
|
||||
pub fn visit_child<R: super::Read>(
|
||||
&self,
|
||||
idx: usize,
|
||||
volume: &super::volume::Volume<R>,
|
||||
) -> Result<Rc<Node>> {
|
||||
match self.children.get(idx) {
|
||||
Some(child) => self.visit_child_inner(child, volume),
|
||||
None => Err(Error::OutOfBounds {
|
||||
range: 0..self.children.len(),
|
||||
index: idx,
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_child_inner<R: super::Read>(
|
||||
&self,
|
||||
child: &Cell<NodePtr>,
|
||||
volume: &super::volume::Volume<R>,
|
||||
) -> Result<Rc<Node>> {
|
||||
match unsafe { &*child.as_ptr() } {
|
||||
NodePtr::Unvisited(keyptr) => {
|
||||
let node = volume
|
||||
.read_keyptr(keyptr)
|
||||
.and_then(|bytes| Node::from_bytes(bytes))
|
||||
.map(|node| Rc::new(node))?;
|
||||
child.set(NodePtr::Visited {
|
||||
key: *keyptr,
|
||||
node: node.clone(),
|
||||
});
|
||||
Ok(node)
|
||||
}
|
||||
NodePtr::Visited { node, .. } => Ok(node.clone()),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn visit_children_keys(
|
||||
&self,
|
||||
) -> impl Iterator<Item = (usize, Key)> + DoubleEndedIterator + '_ {
|
||||
self.children
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(i, child)| (i, unsafe { *(&*child.as_ptr()).key() }))
|
||||
}
|
||||
|
||||
pub fn visit_children<'a, 'b, R: super::Read>(
|
||||
&'a self,
|
||||
volume: &'b super::volume::Volume<R>,
|
||||
) -> impl Iterator<Item = (usize, Result<Rc<Node>>)> + 'a
|
||||
where
|
||||
'b: 'a,
|
||||
{
|
||||
self.children
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(i, child)| (i, self.visit_child_inner(child, volume)))
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq for BTreeInternalNode {
|
||||
|
@ -42,7 +130,7 @@ impl PartialEq for BTreeLeafNode {
|
|||
impl Eq for BTreeLeafNode {}
|
||||
impl Eq for BTreeInternalNode {}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub enum BTreeNode {
|
||||
Internal(BTreeInternalNode),
|
||||
Leaf(BTreeLeafNode),
|
||||
|
@ -126,10 +214,9 @@ impl<R: super::Read> Tree<R> {
|
|||
}
|
||||
SearchResult::Edge(mut edge) => match &edge.node.inner {
|
||||
BTreeNode::Internal(internal) => {
|
||||
let child_ptr = internal.children.get(edge.idx as usize).expect("adsf");
|
||||
|
||||
let bytes = self.volume.read_keyptr(child_ptr)?;
|
||||
let child = Rc::new(Node::from_bytes(bytes)?);
|
||||
let child = internal
|
||||
.visit_child(edge.idx as usize, &self.volume)
|
||||
.expect("child");
|
||||
edge.parents.push((edge.node, edge.idx));
|
||||
node = NodeHandle {
|
||||
parents: edge.parents,
|
||||
|
@ -250,6 +337,7 @@ impl BTreeInternalNode {
|
|||
}
|
||||
})
|
||||
.take(header.nritems.get() as usize)
|
||||
.map(|ptr| Cell::new(NodePtr::Unvisited(ptr)))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
Ok(Self { header, children })
|
||||
|
@ -589,21 +677,18 @@ impl NodeHandle {
|
|||
pub fn find_key_rev<K: PartialEq<Key> + PartialOrd<Key>>(self, key: &K) -> SearchResult {
|
||||
match &self.node.inner {
|
||||
BTreeNode::Internal(node) => {
|
||||
for (i, child) in node.children.iter().enumerate().rev() {
|
||||
match key.partial_cmp(&child.key) {
|
||||
let idx = node
|
||||
.visit_children_keys()
|
||||
.rev()
|
||||
.find_map(|(i, child)| match key.partial_cmp(&child) {
|
||||
Some(core::cmp::Ordering::Greater)
|
||||
| Some(core::cmp::Ordering::Equal)
|
||||
| None => {
|
||||
return SearchResult::Edge(NodeHandle {
|
||||
idx: i as u32,
|
||||
..self
|
||||
});
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
| None => Some(i as u32),
|
||||
_ => None,
|
||||
})
|
||||
.unwrap_or(0);
|
||||
|
||||
SearchResult::Edge(NodeHandle { idx: 0, ..self })
|
||||
SearchResult::Edge(NodeHandle { idx, ..self })
|
||||
}
|
||||
BTreeNode::Leaf(node) => {
|
||||
for (i, child) in node.items.iter().enumerate().rev() {
|
||||
|
@ -624,28 +709,18 @@ impl NodeHandle {
|
|||
pub fn find_key<K: PartialEq<Key> + PartialOrd<Key>>(self, key: &K) -> SearchResult {
|
||||
match &self.node.inner {
|
||||
BTreeNode::Internal(node) => {
|
||||
for (i, child) in node.children.iter().enumerate() {
|
||||
match key.partial_cmp(&child.key) {
|
||||
let idx = node
|
||||
.visit_children_keys()
|
||||
.find_map(|(i, child)| match key.partial_cmp(&child) {
|
||||
Some(core::cmp::Ordering::Less) => {
|
||||
return SearchResult::Edge(Self {
|
||||
idx: if i == 0 { 0 } else { i as u32 - 1 },
|
||||
..self
|
||||
});
|
||||
Some(if i == 0 { 0 } else { i as u32 - 1 })
|
||||
}
|
||||
Some(core::cmp::Ordering::Equal) | None => {
|
||||
return SearchResult::Edge(NodeHandle {
|
||||
idx: i as u32,
|
||||
..self
|
||||
});
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
Some(core::cmp::Ordering::Equal) | None => Some(i as u32),
|
||||
_ => None,
|
||||
})
|
||||
.unwrap_or(node.children.len() as u32 - 1);
|
||||
|
||||
SearchResult::Edge(NodeHandle {
|
||||
idx: node.children.len() as u32 - 1,
|
||||
..self
|
||||
})
|
||||
SearchResult::Edge(NodeHandle { idx, ..self })
|
||||
}
|
||||
BTreeNode::Leaf(node) => {
|
||||
for (i, child) in node.items.iter().enumerate() {
|
||||
|
@ -694,15 +769,7 @@ impl NodeHandle {
|
|||
} 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))
|
||||
{
|
||||
let node = match internal.visit_child(idx as usize, volume) {
|
||||
Ok(child) => {
|
||||
parents.push((node, idx));
|
||||
Ok(Self {
|
||||
|
@ -757,15 +824,7 @@ impl NodeHandle {
|
|||
} 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))
|
||||
{
|
||||
let node = match internal.visit_child(idx as usize, volume) {
|
||||
Ok(child) => {
|
||||
parents.push((node, idx));
|
||||
Ok(Self {
|
||||
|
|
Loading…
Reference in a new issue