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)]
|
#![allow(dead_code)]
|
||||||
#![feature(error_in_core)]
|
#![feature(error_in_core, cell_update)]
|
||||||
#![cfg_attr(not(any(feature = "std", test)), no_std)]
|
#![cfg_attr(not(any(feature = "std", test)), no_std)]
|
||||||
|
|
||||||
use core::{
|
use core::{
|
||||||
|
@ -22,7 +22,6 @@ use tree::Tree;
|
||||||
extern crate alloc;
|
extern crate alloc;
|
||||||
|
|
||||||
pub mod crc32c;
|
pub mod crc32c;
|
||||||
pub mod files;
|
|
||||||
pub mod path;
|
pub mod path;
|
||||||
pub mod structs;
|
pub mod structs;
|
||||||
pub mod tree;
|
pub mod tree;
|
||||||
|
@ -30,7 +29,7 @@ pub mod v2;
|
||||||
|
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
pub mod std_io {
|
pub mod std_io {
|
||||||
use std::io::{Cursor, Read, Seek};
|
use std::io::{Read, Seek};
|
||||||
|
|
||||||
use crate::{Error, VolumeIo};
|
use crate::{Error, VolumeIo};
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use alloc::{collections::VecDeque, vec::Vec};
|
use alloc::collections::VecDeque;
|
||||||
|
|
||||||
const SEPERATOR: u8 = b'/';
|
const SEPERATOR: u8 = b'/';
|
||||||
|
|
||||||
|
|
|
@ -23,6 +23,11 @@ pub mod error {
|
||||||
NoDefaultSubvolFsRoot,
|
NoDefaultSubvolFsRoot,
|
||||||
#[error("INode could not be found in FsTree")]
|
#[error("INode could not be found in FsTree")]
|
||||||
INodeNotFound,
|
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:#?}")]
|
#[error("Invalid checksum: expected {expected:#?} but got {actual:#?}")]
|
||||||
InvalidChecksum {
|
InvalidChecksum {
|
||||||
expected: [u8; 32],
|
expected: [u8; 32],
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
use core::cell::Cell;
|
||||||
use core::fmt::Display;
|
use core::fmt::Display;
|
||||||
use core::mem::size_of;
|
use core::mem::size_of;
|
||||||
use core::ops::Deref;
|
use core::ops::Deref;
|
||||||
|
@ -20,11 +21,98 @@ pub struct BTreeLeafNode {
|
||||||
pub items: Vec<Item>,
|
pub items: Vec<Item>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// An internal node in a btrfs tree, containing `KeyPtr`s to other internal nodes or leaf nodes.
|
|
||||||
#[derive(Debug, Clone)]
|
#[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 struct BTreeInternalNode {
|
||||||
pub header: Header,
|
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 {
|
impl PartialEq for BTreeInternalNode {
|
||||||
|
@ -42,7 +130,7 @@ impl PartialEq for BTreeLeafNode {
|
||||||
impl Eq for BTreeLeafNode {}
|
impl Eq for BTreeLeafNode {}
|
||||||
impl Eq for BTreeInternalNode {}
|
impl Eq for BTreeInternalNode {}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
#[derive(Debug, PartialEq, Eq)]
|
||||||
pub enum BTreeNode {
|
pub enum BTreeNode {
|
||||||
Internal(BTreeInternalNode),
|
Internal(BTreeInternalNode),
|
||||||
Leaf(BTreeLeafNode),
|
Leaf(BTreeLeafNode),
|
||||||
|
@ -126,10 +214,9 @@ impl<R: super::Read> Tree<R> {
|
||||||
}
|
}
|
||||||
SearchResult::Edge(mut edge) => match &edge.node.inner {
|
SearchResult::Edge(mut edge) => match &edge.node.inner {
|
||||||
BTreeNode::Internal(internal) => {
|
BTreeNode::Internal(internal) => {
|
||||||
let child_ptr = internal.children.get(edge.idx as usize).expect("adsf");
|
let child = internal
|
||||||
|
.visit_child(edge.idx as usize, &self.volume)
|
||||||
let bytes = self.volume.read_keyptr(child_ptr)?;
|
.expect("child");
|
||||||
let child = Rc::new(Node::from_bytes(bytes)?);
|
|
||||||
edge.parents.push((edge.node, edge.idx));
|
edge.parents.push((edge.node, edge.idx));
|
||||||
node = NodeHandle {
|
node = NodeHandle {
|
||||||
parents: edge.parents,
|
parents: edge.parents,
|
||||||
|
@ -250,6 +337,7 @@ impl BTreeInternalNode {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.take(header.nritems.get() as usize)
|
.take(header.nritems.get() as usize)
|
||||||
|
.map(|ptr| Cell::new(NodePtr::Unvisited(ptr)))
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
Ok(Self { header, children })
|
Ok(Self { header, children })
|
||||||
|
@ -589,21 +677,18 @@ impl NodeHandle {
|
||||||
pub fn find_key_rev<K: PartialEq<Key> + PartialOrd<Key>>(self, key: &K) -> SearchResult {
|
pub fn find_key_rev<K: PartialEq<Key> + PartialOrd<Key>>(self, key: &K) -> SearchResult {
|
||||||
match &self.node.inner {
|
match &self.node.inner {
|
||||||
BTreeNode::Internal(node) => {
|
BTreeNode::Internal(node) => {
|
||||||
for (i, child) in node.children.iter().enumerate().rev() {
|
let idx = node
|
||||||
match key.partial_cmp(&child.key) {
|
.visit_children_keys()
|
||||||
|
.rev()
|
||||||
|
.find_map(|(i, child)| match key.partial_cmp(&child) {
|
||||||
Some(core::cmp::Ordering::Greater)
|
Some(core::cmp::Ordering::Greater)
|
||||||
| Some(core::cmp::Ordering::Equal)
|
| Some(core::cmp::Ordering::Equal)
|
||||||
| None => {
|
| None => Some(i as u32),
|
||||||
return SearchResult::Edge(NodeHandle {
|
_ => None,
|
||||||
idx: i as u32,
|
})
|
||||||
..self
|
.unwrap_or(0);
|
||||||
});
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
SearchResult::Edge(NodeHandle { idx: 0, ..self })
|
SearchResult::Edge(NodeHandle { idx, ..self })
|
||||||
}
|
}
|
||||||
BTreeNode::Leaf(node) => {
|
BTreeNode::Leaf(node) => {
|
||||||
for (i, child) in node.items.iter().enumerate().rev() {
|
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 {
|
pub fn find_key<K: PartialEq<Key> + PartialOrd<Key>>(self, key: &K) -> SearchResult {
|
||||||
match &self.node.inner {
|
match &self.node.inner {
|
||||||
BTreeNode::Internal(node) => {
|
BTreeNode::Internal(node) => {
|
||||||
for (i, child) in node.children.iter().enumerate() {
|
let idx = node
|
||||||
match key.partial_cmp(&child.key) {
|
.visit_children_keys()
|
||||||
|
.find_map(|(i, child)| match key.partial_cmp(&child) {
|
||||||
Some(core::cmp::Ordering::Less) => {
|
Some(core::cmp::Ordering::Less) => {
|
||||||
return SearchResult::Edge(Self {
|
Some(if i == 0 { 0 } else { i as u32 - 1 })
|
||||||
idx: if i == 0 { 0 } else { i as u32 - 1 },
|
|
||||||
..self
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
Some(core::cmp::Ordering::Equal) | None => {
|
Some(core::cmp::Ordering::Equal) | None => Some(i as u32),
|
||||||
return SearchResult::Edge(NodeHandle {
|
_ => None,
|
||||||
idx: i as u32,
|
|
||||||
..self
|
|
||||||
});
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
SearchResult::Edge(NodeHandle {
|
|
||||||
idx: node.children.len() as u32 - 1,
|
|
||||||
..self
|
|
||||||
})
|
})
|
||||||
|
.unwrap_or(node.children.len() as u32 - 1);
|
||||||
|
|
||||||
|
SearchResult::Edge(NodeHandle { idx, ..self })
|
||||||
}
|
}
|
||||||
BTreeNode::Leaf(node) => {
|
BTreeNode::Leaf(node) => {
|
||||||
for (i, child) in node.items.iter().enumerate() {
|
for (i, child) in node.items.iter().enumerate() {
|
||||||
|
@ -694,15 +769,7 @@ impl NodeHandle {
|
||||||
} else {
|
} else {
|
||||||
match &node.inner {
|
match &node.inner {
|
||||||
BTreeNode::Internal(internal) => {
|
BTreeNode::Internal(internal) => {
|
||||||
let child_ptr = *internal
|
let node = match internal.visit_child(idx as usize, volume) {
|
||||||
.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) => {
|
Ok(child) => {
|
||||||
parents.push((node, idx));
|
parents.push((node, idx));
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
|
@ -757,15 +824,7 @@ impl NodeHandle {
|
||||||
} else {
|
} else {
|
||||||
match &node.inner {
|
match &node.inner {
|
||||||
BTreeNode::Internal(internal) => {
|
BTreeNode::Internal(internal) => {
|
||||||
let child_ptr = *internal
|
let node = match internal.visit_child(idx as usize, volume) {
|
||||||
.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) => {
|
Ok(child) => {
|
||||||
parents.push((node, idx));
|
parents.push((node, idx));
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
|
|
Loading…
Reference in a new issue