2020-08-03 17:07:32 +05:30
|
|
|
use nom::{number::complete::*, IResult};
|
2020-08-10 19:15:35 +05:30
|
|
|
use std::collections::BTreeMap;
|
2020-09-16 19:40:01 +05:30
|
|
|
use std::fmt;
|
2020-08-10 20:12:10 +05:30
|
|
|
use std::sync::{Arc, Mutex};
|
2020-09-16 19:40:01 +05:30
|
|
|
use thiserror::Error;
|
2020-08-21 14:40:49 +05:30
|
|
|
use threadpool::ThreadPool;
|
2020-08-03 17:07:32 +05:30
|
|
|
|
|
|
|
use crate::checksum;
|
2020-08-10 17:00:12 +05:30
|
|
|
use crate::io_engine::*;
|
2020-08-11 15:20:43 +05:30
|
|
|
use crate::pdata::space_map::*;
|
2020-08-10 20:12:10 +05:30
|
|
|
use crate::pdata::unpack::*;
|
2020-08-03 17:07:32 +05:30
|
|
|
|
2020-08-04 16:41:36 +05:30
|
|
|
// FIXME: check that keys are in ascending order between nodes.
|
|
|
|
|
2020-08-03 17:07:32 +05:30
|
|
|
//------------------------------------------
|
|
|
|
|
2020-09-16 19:40:01 +05:30
|
|
|
#[derive(Clone, Debug, PartialEq)]
|
|
|
|
pub struct KeyRange {
|
|
|
|
start: Option<u64>,
|
|
|
|
end: Option<u64>, // This is the one-past-the-end value
|
|
|
|
}
|
|
|
|
|
|
|
|
impl fmt::Display for KeyRange {
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
|
|
match (self.start, self.end) {
|
|
|
|
(None, None) => write!(f, "[..]"),
|
|
|
|
(None, Some(e)) => write!(f, "[..{}]", e),
|
|
|
|
(Some(s), None) => write!(f, "[{}..]", s),
|
|
|
|
(Some(s), Some(e)) => write!(f, "[{}..{}]", s, e),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl KeyRange {
|
|
|
|
// None will be returned if either range would be zero length
|
|
|
|
fn split(&self, n: u64) -> Option<(KeyRange, KeyRange)> {
|
|
|
|
match (self.start, self.end) {
|
|
|
|
(None, None) => Some((
|
|
|
|
KeyRange {
|
|
|
|
start: None,
|
|
|
|
end: Some(n),
|
|
|
|
},
|
|
|
|
KeyRange {
|
|
|
|
start: Some(n),
|
|
|
|
end: None,
|
|
|
|
},
|
|
|
|
)),
|
|
|
|
(None, Some(e)) => {
|
|
|
|
if n < e {
|
|
|
|
Some((
|
|
|
|
KeyRange {
|
|
|
|
start: None,
|
|
|
|
end: Some(n),
|
|
|
|
},
|
|
|
|
KeyRange {
|
|
|
|
start: Some(n),
|
|
|
|
end: Some(e),
|
|
|
|
},
|
|
|
|
))
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
}
|
|
|
|
}
|
|
|
|
(Some(s), None) => {
|
|
|
|
if s < n {
|
|
|
|
Some((
|
|
|
|
KeyRange {
|
|
|
|
start: Some(s),
|
|
|
|
end: Some(n),
|
|
|
|
},
|
|
|
|
KeyRange {
|
|
|
|
start: Some(n),
|
|
|
|
end: None,
|
|
|
|
},
|
|
|
|
))
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
}
|
|
|
|
}
|
|
|
|
(Some(s), Some(e)) => {
|
|
|
|
if s < n && n < e {
|
|
|
|
Some((
|
|
|
|
KeyRange {
|
|
|
|
start: Some(s),
|
|
|
|
end: Some(n),
|
|
|
|
},
|
|
|
|
KeyRange {
|
|
|
|
start: Some(n),
|
|
|
|
end: Some(e),
|
|
|
|
},
|
|
|
|
))
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_split_range() {
|
|
|
|
struct Test(Option<u64>, Option<u64>, u64, Option<(KeyRange, KeyRange)>);
|
|
|
|
|
|
|
|
let tests = vec![
|
|
|
|
Test(
|
|
|
|
None,
|
|
|
|
None,
|
|
|
|
100,
|
|
|
|
Some((
|
|
|
|
KeyRange {
|
|
|
|
start: None,
|
|
|
|
end: Some(100),
|
|
|
|
},
|
|
|
|
KeyRange {
|
|
|
|
start: Some(100),
|
|
|
|
end: None,
|
|
|
|
},
|
|
|
|
)),
|
|
|
|
),
|
|
|
|
Test(None, Some(100), 1000, None),
|
|
|
|
Test(
|
|
|
|
None,
|
|
|
|
Some(100),
|
|
|
|
50,
|
|
|
|
Some((
|
|
|
|
KeyRange {
|
|
|
|
start: None,
|
|
|
|
end: Some(50),
|
|
|
|
},
|
|
|
|
KeyRange {
|
|
|
|
start: Some(50),
|
|
|
|
end: Some(100),
|
|
|
|
},
|
|
|
|
)),
|
|
|
|
),
|
|
|
|
Test(None, Some(100), 100, None),
|
|
|
|
Test(Some(100), None, 50, None),
|
|
|
|
Test(
|
|
|
|
Some(100),
|
|
|
|
None,
|
|
|
|
150,
|
|
|
|
Some((
|
|
|
|
KeyRange {
|
|
|
|
start: Some(100),
|
|
|
|
end: Some(150),
|
|
|
|
},
|
|
|
|
KeyRange {
|
|
|
|
start: Some(150),
|
|
|
|
end: None,
|
|
|
|
},
|
|
|
|
)),
|
|
|
|
),
|
|
|
|
Test(Some(100), Some(200), 50, None),
|
|
|
|
Test(Some(100), Some(200), 250, None),
|
|
|
|
Test(
|
|
|
|
Some(100),
|
|
|
|
Some(200),
|
|
|
|
150,
|
|
|
|
Some((
|
|
|
|
KeyRange {
|
|
|
|
start: Some(100),
|
|
|
|
end: Some(150),
|
|
|
|
},
|
|
|
|
KeyRange {
|
|
|
|
start: Some(150),
|
|
|
|
end: Some(200),
|
|
|
|
},
|
|
|
|
)),
|
|
|
|
),
|
|
|
|
];
|
|
|
|
|
|
|
|
for Test(start, end, n, expected) in tests {
|
|
|
|
let kr = KeyRange { start, end };
|
|
|
|
let actual = kr.split(n);
|
|
|
|
assert_eq!(actual, expected);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-09-18 15:46:09 +05:30
|
|
|
fn split_one(path: &Vec<u64>, kr: &KeyRange, k: u64) -> Result<(KeyRange, KeyRange)> {
|
2020-09-16 19:40:01 +05:30
|
|
|
match kr.split(k) {
|
|
|
|
None => {
|
2020-09-18 15:46:09 +05:30
|
|
|
return Err(node_err(path, &format!(
|
2020-09-16 19:40:01 +05:30
|
|
|
"couldn't split key range {} at {}",
|
|
|
|
kr, k
|
|
|
|
)));
|
|
|
|
}
|
|
|
|
Some(pair) => Ok(pair),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-09-18 15:46:09 +05:30
|
|
|
fn split_key_ranges_(path: &Vec<u64>, kr: &KeyRange, keys: &[u64]) -> Result<Vec<KeyRange>> {
|
2020-09-16 19:40:01 +05:30
|
|
|
let mut krs = Vec::with_capacity(keys.len());
|
|
|
|
|
|
|
|
if keys.len() == 0 {
|
2020-09-18 15:46:09 +05:30
|
|
|
return Err(node_err(path, "split_key_ranges: no keys present"));
|
2020-09-16 19:40:01 +05:30
|
|
|
}
|
|
|
|
|
|
|
|
// The first key gives the lower bound
|
|
|
|
let mut kr = KeyRange {
|
|
|
|
start: Some(keys[0]),
|
|
|
|
end: kr.end,
|
|
|
|
};
|
|
|
|
|
|
|
|
for i in 1..keys.len() {
|
2020-09-18 15:46:09 +05:30
|
|
|
let (first, rest) = split_one(path, &kr, keys[i])?;
|
2020-09-16 19:40:01 +05:30
|
|
|
krs.push(first);
|
|
|
|
kr = rest;
|
|
|
|
}
|
|
|
|
|
|
|
|
krs.push(kr);
|
|
|
|
|
|
|
|
Ok(krs)
|
|
|
|
}
|
|
|
|
|
2020-09-18 15:46:09 +05:30
|
|
|
fn split_key_ranges(path: &Vec<u64>, kr: &KeyRange, keys: &[u64]) -> Result<Vec<KeyRange>> {
|
2020-09-16 19:40:01 +05:30
|
|
|
let msg = format!("split: {:?} at {:?}", &kr, &keys);
|
2020-09-18 15:46:09 +05:30
|
|
|
let r = split_key_ranges_(path, kr, keys);
|
2020-09-16 19:40:01 +05:30
|
|
|
if r.is_err() {
|
|
|
|
eprintln!("{} -> {:?}", msg, &r);
|
|
|
|
}
|
|
|
|
|
|
|
|
r
|
|
|
|
}
|
|
|
|
|
|
|
|
//------------------------------------------
|
|
|
|
|
2020-08-03 19:34:59 +05:30
|
|
|
const NODE_HEADER_SIZE: usize = 32;
|
|
|
|
|
2020-09-16 19:40:01 +05:30
|
|
|
#[derive(Error, Clone, Debug)]
|
|
|
|
pub enum BTreeError {
|
|
|
|
// #[error("io error")]
|
|
|
|
IoError, // (std::io::Error), // FIXME: we can't clone an io_error
|
|
|
|
|
|
|
|
// #[error("node error: {0}")]
|
|
|
|
NodeError(String),
|
|
|
|
|
|
|
|
// #[error("value error: {0}")]
|
|
|
|
ValueError(String),
|
|
|
|
|
|
|
|
// #[error("keys: {0:?}")]
|
|
|
|
KeyContext(KeyRange, Box<BTreeError>),
|
|
|
|
|
|
|
|
// #[error("aggregate: {0:?}")]
|
|
|
|
Aggregate(Vec<BTreeError>),
|
|
|
|
|
|
|
|
// #[error("{0:?}, {1}")]
|
2020-09-18 15:46:09 +05:30
|
|
|
Path(Vec<u64>, Box<BTreeError>),
|
2020-09-16 19:40:01 +05:30
|
|
|
}
|
|
|
|
|
|
|
|
impl fmt::Display for BTreeError {
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
2020-09-18 15:46:09 +05:30
|
|
|
match self {
|
|
|
|
BTreeError::IoError => write!(f, "io error"),
|
|
|
|
BTreeError::NodeError(msg) => write!(f, "node error: {}", msg),
|
|
|
|
BTreeError::ValueError(msg) => write!(f, "value error: {}", msg),
|
|
|
|
BTreeError::KeyContext(kr, be) => write!(f, "{}, effecting keys {}", be, kr),
|
2020-09-16 19:40:01 +05:30
|
|
|
BTreeError::Aggregate(errs) => {
|
|
|
|
for e in errs {
|
|
|
|
write!(f, "{}", e)?
|
|
|
|
}
|
|
|
|
Ok(())
|
|
|
|
}
|
2020-09-18 15:46:09 +05:30
|
|
|
BTreeError::Path(path, e) => write!(f, "{} @{:?}", e, path),
|
2020-09-16 19:40:01 +05:30
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-09-18 15:46:09 +05:30
|
|
|
pub fn node_err(path: &Vec<u64>, msg: &str) -> BTreeError {
|
|
|
|
BTreeError::Path(path.clone(), Box::new(BTreeError::NodeError(msg.to_string())))
|
2020-09-16 19:40:01 +05:30
|
|
|
}
|
|
|
|
|
2020-09-18 15:46:09 +05:30
|
|
|
fn node_err_s(path: &Vec<u64>, msg: String) -> BTreeError {
|
|
|
|
BTreeError::Path(path.clone(), Box::new(BTreeError::NodeError(msg)))
|
2020-09-16 19:40:01 +05:30
|
|
|
}
|
|
|
|
|
2020-09-18 15:46:09 +05:30
|
|
|
pub fn io_err(path: &Vec<u64>) -> BTreeError {
|
|
|
|
BTreeError::Path(path.clone(), Box::new(BTreeError::IoError))
|
2020-09-16 19:40:01 +05:30
|
|
|
}
|
|
|
|
|
|
|
|
pub fn value_err(msg: String) -> BTreeError {
|
|
|
|
BTreeError::ValueError(msg)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn aggregate_error(rs: Vec<BTreeError>) -> BTreeError {
|
|
|
|
BTreeError::Aggregate(rs)
|
|
|
|
}
|
|
|
|
|
|
|
|
impl BTreeError {
|
|
|
|
pub fn keys_context(self, keys: &KeyRange) -> BTreeError {
|
|
|
|
BTreeError::KeyContext(keys.clone(), Box::new(self))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub type Result<T> = std::result::Result<T, BTreeError>;
|
|
|
|
|
|
|
|
//------------------------------------------
|
|
|
|
|
2020-09-18 14:36:33 +05:30
|
|
|
#[derive(Debug, Clone, Copy)]
|
2020-08-03 17:07:32 +05:30
|
|
|
pub struct NodeHeader {
|
2020-09-16 19:40:01 +05:30
|
|
|
pub block: u64,
|
|
|
|
pub is_leaf: bool,
|
|
|
|
pub nr_entries: u32,
|
|
|
|
pub max_entries: u32,
|
|
|
|
pub value_size: u32,
|
2020-08-03 17:07:32 +05:30
|
|
|
}
|
|
|
|
|
|
|
|
#[allow(dead_code)]
|
|
|
|
const INTERNAL_NODE: u32 = 1;
|
|
|
|
const LEAF_NODE: u32 = 2;
|
|
|
|
|
2020-09-16 19:40:01 +05:30
|
|
|
impl Unpack for NodeHeader {
|
|
|
|
fn disk_size() -> u32 {
|
|
|
|
32
|
|
|
|
}
|
|
|
|
|
|
|
|
fn unpack(data: &[u8]) -> IResult<&[u8], NodeHeader> {
|
|
|
|
let (i, _csum) = le_u32(data)?;
|
|
|
|
let (i, flags) = le_u32(i)?;
|
|
|
|
let (i, block) = le_u64(i)?;
|
|
|
|
let (i, nr_entries) = le_u32(i)?;
|
|
|
|
let (i, max_entries) = le_u32(i)?;
|
|
|
|
let (i, value_size) = le_u32(i)?;
|
|
|
|
let (i, _padding) = le_u32(i)?;
|
|
|
|
|
|
|
|
Ok((
|
|
|
|
i,
|
|
|
|
NodeHeader {
|
|
|
|
block,
|
|
|
|
is_leaf: flags == LEAF_NODE,
|
|
|
|
nr_entries,
|
|
|
|
max_entries,
|
|
|
|
value_size,
|
|
|
|
},
|
|
|
|
))
|
|
|
|
}
|
2020-08-03 17:07:32 +05:30
|
|
|
}
|
|
|
|
|
2020-09-16 19:40:01 +05:30
|
|
|
#[derive(Clone)]
|
2020-08-05 12:31:02 +05:30
|
|
|
pub enum Node<V: Unpack> {
|
2020-08-03 17:07:32 +05:30
|
|
|
Internal {
|
|
|
|
header: NodeHeader,
|
|
|
|
keys: Vec<u64>,
|
|
|
|
values: Vec<u64>,
|
|
|
|
},
|
|
|
|
Leaf {
|
|
|
|
header: NodeHeader,
|
|
|
|
keys: Vec<u64>,
|
2020-08-03 20:52:08 +05:30
|
|
|
values: Vec<V>,
|
2020-08-03 17:07:32 +05:30
|
|
|
},
|
|
|
|
}
|
|
|
|
|
2020-09-16 19:40:01 +05:30
|
|
|
impl<V: Unpack> Node<V> {
|
|
|
|
pub fn get_header(&self) -> &NodeHeader {
|
|
|
|
use Node::*;
|
|
|
|
match self {
|
|
|
|
Internal { header, .. } => header,
|
|
|
|
Leaf { header, .. } => header,
|
|
|
|
}
|
|
|
|
}
|
2020-08-03 19:34:59 +05:30
|
|
|
}
|
|
|
|
|
2020-09-18 15:46:09 +05:30
|
|
|
pub fn convert_result<'a, V>(path: &Vec<u64>, r: IResult<&'a [u8], V>) -> Result<(&'a [u8], V)> {
|
|
|
|
r.map_err(|_e| node_err(path, "parse error"))
|
2020-09-16 19:40:01 +05:30
|
|
|
}
|
|
|
|
|
2020-09-18 15:46:09 +05:30
|
|
|
pub fn convert_io_err<V>(path: &Vec<u64>, r: std::io::Result<V>) -> Result<V> {
|
|
|
|
r.map_err(|_| io_err(path))
|
2020-08-03 19:34:59 +05:30
|
|
|
}
|
|
|
|
|
2020-08-05 12:31:02 +05:30
|
|
|
pub fn unpack_node<V: Unpack>(
|
2020-09-18 15:46:09 +05:30
|
|
|
path: &Vec<u64>,
|
2020-08-03 19:34:59 +05:30
|
|
|
data: &[u8],
|
|
|
|
ignore_non_fatal: bool,
|
|
|
|
is_root: bool,
|
|
|
|
) -> Result<Node<V>> {
|
2020-08-03 17:07:32 +05:30
|
|
|
use nom::multi::count;
|
|
|
|
|
2020-09-16 19:40:01 +05:30
|
|
|
let (i, header) =
|
2020-09-18 15:46:09 +05:30
|
|
|
NodeHeader::unpack(data).map_err(|_e| node_err(path, "couldn't parse node header"))?;
|
2020-08-03 19:34:59 +05:30
|
|
|
|
2020-08-03 20:52:08 +05:30
|
|
|
if header.is_leaf && header.value_size != V::disk_size() {
|
2020-09-18 15:46:09 +05:30
|
|
|
return Err(node_err_s(path, format!(
|
2020-08-03 19:34:59 +05:30
|
|
|
"value_size mismatch: expected {}, was {}",
|
|
|
|
V::disk_size(),
|
|
|
|
header.value_size
|
2020-09-16 19:40:01 +05:30
|
|
|
)));
|
2020-08-03 19:34:59 +05:30
|
|
|
}
|
|
|
|
|
2020-08-03 20:52:08 +05:30
|
|
|
let elt_size = header.value_size + 8;
|
2020-08-03 19:34:59 +05:30
|
|
|
if elt_size as usize * header.max_entries as usize + NODE_HEADER_SIZE > BLOCK_SIZE {
|
2020-09-18 15:46:09 +05:30
|
|
|
return Err(node_err_s(path, format!(
|
2020-09-16 19:40:01 +05:30
|
|
|
"max_entries is too large ({})",
|
|
|
|
header.max_entries
|
|
|
|
)));
|
2020-08-03 19:34:59 +05:30
|
|
|
}
|
|
|
|
|
|
|
|
if header.nr_entries > header.max_entries {
|
2020-09-18 15:46:09 +05:30
|
|
|
return Err(node_err(path, "nr_entries > max_entries"));
|
2020-08-03 19:34:59 +05:30
|
|
|
}
|
|
|
|
|
|
|
|
if !ignore_non_fatal {
|
|
|
|
if header.max_entries % 3 != 0 {
|
2020-09-18 15:46:09 +05:30
|
|
|
return Err(node_err(path, "max_entries is not divisible by 3"));
|
2020-08-03 19:34:59 +05:30
|
|
|
}
|
|
|
|
|
|
|
|
if !is_root {
|
|
|
|
let min = header.max_entries / 3;
|
|
|
|
if header.nr_entries < min {
|
2020-09-18 15:46:09 +05:30
|
|
|
return Err(node_err_s(path, format!(
|
2020-09-16 19:40:01 +05:30
|
|
|
"too few entries {}, expected at least {}",
|
|
|
|
header.nr_entries, min
|
|
|
|
)));
|
2020-08-03 19:34:59 +05:30
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-09-18 15:46:09 +05:30
|
|
|
let (i, keys) = convert_result(path, count(le_u64, header.nr_entries as usize)(i))?;
|
2020-08-03 19:34:59 +05:30
|
|
|
|
|
|
|
let mut last = None;
|
|
|
|
for k in &keys {
|
|
|
|
if let Some(l) = last {
|
|
|
|
if k <= l {
|
2020-09-18 15:46:09 +05:30
|
|
|
return Err(node_err(path, "keys out of order"));
|
2020-08-03 19:34:59 +05:30
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
last = Some(k);
|
|
|
|
}
|
|
|
|
|
2020-08-03 17:07:32 +05:30
|
|
|
let nr_free = header.max_entries - header.nr_entries;
|
2020-09-18 15:46:09 +05:30
|
|
|
let (i, _padding) = convert_result(path, count(le_u64, nr_free as usize)(i))?;
|
2020-08-03 17:07:32 +05:30
|
|
|
|
|
|
|
if header.is_leaf {
|
2020-09-18 15:46:09 +05:30
|
|
|
let (_i, values) = convert_result(path, count(V::unpack, header.nr_entries as usize)(i))?;
|
2020-08-03 17:07:32 +05:30
|
|
|
|
2020-08-03 19:34:59 +05:30
|
|
|
Ok(Node::Leaf {
|
|
|
|
header,
|
|
|
|
keys,
|
|
|
|
values,
|
|
|
|
})
|
2020-08-03 17:07:32 +05:30
|
|
|
} else {
|
2020-09-18 15:46:09 +05:30
|
|
|
let (_i, values) = convert_result(path, count(le_u64, header.nr_entries as usize)(i))?;
|
2020-08-03 19:34:59 +05:30
|
|
|
Ok(Node::Internal {
|
|
|
|
header,
|
|
|
|
keys,
|
|
|
|
values,
|
|
|
|
})
|
2020-08-03 17:07:32 +05:30
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//------------------------------------------
|
|
|
|
|
2020-08-05 12:31:02 +05:30
|
|
|
pub trait NodeVisitor<V: Unpack> {
|
2020-08-20 15:35:14 +05:30
|
|
|
// &self is deliberately non mut to allow the walker to use multiple threads.
|
2020-09-18 15:46:09 +05:30
|
|
|
fn visit(&self, path: &Vec<u64>, keys: &KeyRange, header: &NodeHeader, keys: &[u64], values: &[V])
|
2020-09-16 19:40:01 +05:30
|
|
|
-> Result<()>;
|
2020-08-03 17:07:32 +05:30
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Clone)]
|
|
|
|
pub struct BTreeWalker {
|
2020-08-21 14:40:49 +05:30
|
|
|
engine: Arc<dyn IoEngine + Send + Sync>,
|
|
|
|
sm: Arc<Mutex<dyn SpaceMap + Send + Sync>>,
|
2020-09-16 19:40:01 +05:30
|
|
|
fails: Arc<Mutex<BTreeMap<u64, BTreeError>>>,
|
2020-08-03 19:34:59 +05:30
|
|
|
ignore_non_fatal: bool,
|
2020-08-03 17:07:32 +05:30
|
|
|
}
|
|
|
|
|
|
|
|
impl BTreeWalker {
|
2020-08-10 13:29:02 +05:30
|
|
|
pub fn new(engine: Arc<dyn IoEngine + Send + Sync>, ignore_non_fatal: bool) -> BTreeWalker {
|
2020-08-03 17:07:32 +05:30
|
|
|
let nr_blocks = engine.get_nr_blocks() as usize;
|
|
|
|
let r: BTreeWalker = BTreeWalker {
|
2020-08-07 20:11:21 +05:30
|
|
|
engine,
|
2020-08-11 15:20:43 +05:30
|
|
|
sm: Arc::new(Mutex::new(RestrictedSpaceMap::new(nr_blocks as u64))),
|
2020-09-16 19:40:01 +05:30
|
|
|
fails: Arc::new(Mutex::new(BTreeMap::new())),
|
2020-08-03 19:34:59 +05:30
|
|
|
ignore_non_fatal,
|
2020-08-03 17:07:32 +05:30
|
|
|
};
|
|
|
|
r
|
|
|
|
}
|
|
|
|
|
2020-08-11 15:20:43 +05:30
|
|
|
pub fn new_with_sm(
|
2020-08-10 13:29:02 +05:30
|
|
|
engine: Arc<dyn IoEngine + Send + Sync>,
|
2020-08-11 15:20:43 +05:30
|
|
|
sm: Arc<Mutex<dyn SpaceMap + Send + Sync>>,
|
2020-08-04 16:41:36 +05:30
|
|
|
ignore_non_fatal: bool,
|
2020-08-11 15:20:43 +05:30
|
|
|
) -> Result<BTreeWalker> {
|
2020-08-04 16:41:36 +05:30
|
|
|
{
|
2020-08-11 15:20:43 +05:30
|
|
|
let sm = sm.lock().unwrap();
|
2020-09-16 19:40:01 +05:30
|
|
|
assert_eq!(sm.get_nr_blocks().unwrap(), engine.get_nr_blocks());
|
2020-08-04 16:41:36 +05:30
|
|
|
}
|
|
|
|
|
2020-08-11 15:20:43 +05:30
|
|
|
Ok(BTreeWalker {
|
2020-08-04 16:41:36 +05:30
|
|
|
engine,
|
2020-08-11 15:20:43 +05:30
|
|
|
sm,
|
2020-09-16 19:40:01 +05:30
|
|
|
fails: Arc::new(Mutex::new(BTreeMap::new())),
|
2020-08-04 16:41:36 +05:30
|
|
|
ignore_non_fatal,
|
2020-08-11 15:20:43 +05:30
|
|
|
})
|
2020-08-04 16:41:36 +05:30
|
|
|
}
|
|
|
|
|
2020-09-16 19:40:01 +05:30
|
|
|
fn failed(&self, b: u64) -> Option<BTreeError> {
|
|
|
|
let fails = self.fails.lock().unwrap();
|
|
|
|
match fails.get(&b) {
|
|
|
|
None => None,
|
|
|
|
Some(e) => Some(e.clone()),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn set_fail(&self, b: u64, err: BTreeError) {
|
|
|
|
// FIXME: should we monitor the size of fails, and abort if too many errors?
|
|
|
|
let mut fails = self.fails.lock().unwrap();
|
|
|
|
fails.insert(b, err);
|
|
|
|
}
|
|
|
|
|
2020-08-11 15:20:43 +05:30
|
|
|
// Atomically increments the ref count, and returns the _old_ count.
|
2020-09-16 19:40:01 +05:30
|
|
|
fn sm_inc(&self, b: u64) -> u32 {
|
2020-08-11 15:20:43 +05:30
|
|
|
let mut sm = self.sm.lock().unwrap();
|
2020-09-16 19:40:01 +05:30
|
|
|
let count = sm.get(b).unwrap();
|
|
|
|
sm.inc(b, 1).unwrap();
|
|
|
|
count
|
2020-08-10 17:00:12 +05:30
|
|
|
}
|
|
|
|
|
2020-09-16 19:40:01 +05:30
|
|
|
fn build_aggregate(&self, b: u64, errs: Vec<BTreeError>) -> Result<()> {
|
|
|
|
match errs.len() {
|
|
|
|
0 => Ok(()),
|
|
|
|
1 => {
|
|
|
|
let e = errs[0].clone();
|
|
|
|
self.set_fail(b, e.clone());
|
|
|
|
Err(e)
|
|
|
|
}
|
|
|
|
_ => {
|
|
|
|
let e = aggregate_error(errs);
|
|
|
|
self.set_fail(b, e.clone());
|
|
|
|
Err(e)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-09-18 15:46:09 +05:30
|
|
|
fn walk_nodes<NV, V>(
|
|
|
|
&self,
|
|
|
|
path: &mut Vec<u64>,
|
|
|
|
visitor: &NV,
|
|
|
|
kr: &[KeyRange],
|
|
|
|
bs: &[u64],
|
|
|
|
) -> Vec<BTreeError>
|
2020-08-03 17:07:32 +05:30
|
|
|
where
|
|
|
|
NV: NodeVisitor<V>,
|
2020-08-05 12:31:02 +05:30
|
|
|
V: Unpack,
|
2020-08-03 17:07:32 +05:30
|
|
|
{
|
2020-09-16 19:40:01 +05:30
|
|
|
let mut errs: Vec<BTreeError> = Vec::new();
|
|
|
|
|
2020-08-21 13:30:21 +05:30
|
|
|
let mut blocks = Vec::with_capacity(bs.len());
|
2020-08-03 17:07:32 +05:30
|
|
|
for b in bs {
|
2020-09-16 19:40:01 +05:30
|
|
|
if self.sm_inc(*b) == 0 {
|
|
|
|
// Node not yet seen
|
2020-09-02 17:27:47 +05:30
|
|
|
blocks.push(*b);
|
2020-09-16 19:40:01 +05:30
|
|
|
} else {
|
|
|
|
// This node has already been checked ...
|
|
|
|
match self.failed(*b) {
|
|
|
|
None => {
|
|
|
|
// ... it was clean so we can ignore.
|
|
|
|
}
|
|
|
|
Some(e) => {
|
|
|
|
// ... there was an error
|
|
|
|
errs.push(e.clone());
|
|
|
|
}
|
|
|
|
}
|
2020-08-03 17:07:32 +05:30
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-09-16 19:40:01 +05:30
|
|
|
match self.engine.read_many(&blocks[0..]) {
|
|
|
|
Err(_) => {
|
|
|
|
// IO completely failed, error every block
|
|
|
|
for (i, b) in blocks.iter().enumerate() {
|
2020-09-18 15:46:09 +05:30
|
|
|
let e = io_err(path).keys_context(&kr[i]);
|
2020-09-16 19:40:01 +05:30
|
|
|
errs.push(e.clone());
|
|
|
|
self.set_fail(*b, e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Ok(rblocks) => {
|
|
|
|
let mut i = 0;
|
|
|
|
for rb in rblocks {
|
|
|
|
match rb {
|
|
|
|
Err(_) => {
|
2020-09-18 15:46:09 +05:30
|
|
|
let e = io_err(path).keys_context(&kr[i]);
|
2020-09-16 19:40:01 +05:30
|
|
|
errs.push(e.clone());
|
|
|
|
self.set_fail(blocks[i], e);
|
|
|
|
}
|
2020-09-18 15:46:09 +05:30
|
|
|
Ok(b) => match self.walk_node(path, visitor, &kr[i], &b, false) {
|
2020-09-16 19:40:01 +05:30
|
|
|
Err(e) => {
|
|
|
|
errs.push(e);
|
|
|
|
}
|
|
|
|
Ok(()) => {}
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
i += 1;
|
|
|
|
}
|
2020-09-02 17:27:47 +05:30
|
|
|
}
|
2020-08-03 17:07:32 +05:30
|
|
|
}
|
|
|
|
|
2020-09-16 19:40:01 +05:30
|
|
|
errs
|
2020-08-03 17:07:32 +05:30
|
|
|
}
|
|
|
|
|
2020-09-18 15:46:09 +05:30
|
|
|
fn walk_node_<NV, V>(
|
|
|
|
&self,
|
|
|
|
path: &mut Vec<u64>,
|
|
|
|
visitor: &NV,
|
|
|
|
kr: &KeyRange,
|
|
|
|
b: &Block,
|
|
|
|
is_root: bool,
|
|
|
|
) -> Result<()>
|
2020-08-03 17:07:32 +05:30
|
|
|
where
|
|
|
|
NV: NodeVisitor<V>,
|
2020-08-05 12:31:02 +05:30
|
|
|
V: Unpack,
|
2020-08-03 17:07:32 +05:30
|
|
|
{
|
2020-08-20 15:25:38 +05:30
|
|
|
use Node::*;
|
|
|
|
|
2020-08-03 17:07:32 +05:30
|
|
|
let bt = checksum::metadata_block_type(b.get_data());
|
|
|
|
if bt != checksum::BT::NODE {
|
2020-09-16 19:40:01 +05:30
|
|
|
return Err(
|
2020-09-18 15:46:09 +05:30
|
|
|
node_err_s(path, format!("checksum failed for node {}, {:?}", b.loc, bt))
|
2020-09-16 19:40:01 +05:30
|
|
|
.keys_context(kr),
|
|
|
|
);
|
2020-08-03 17:07:32 +05:30
|
|
|
}
|
|
|
|
|
2020-09-18 15:46:09 +05:30
|
|
|
let node = unpack_node::<V>(path, &b.get_data(), self.ignore_non_fatal, is_root)?;
|
2020-08-03 17:07:32 +05:30
|
|
|
|
2020-08-20 15:25:38 +05:30
|
|
|
match node {
|
2020-09-16 19:40:01 +05:30
|
|
|
Internal { keys, values, .. } => {
|
2020-09-18 15:46:09 +05:30
|
|
|
let krs = split_key_ranges(path, &kr, &keys)?;
|
|
|
|
let errs = self.walk_nodes(path, visitor, &krs, &values);
|
2020-09-16 19:40:01 +05:30
|
|
|
return self.build_aggregate(b.loc, errs);
|
2020-08-20 15:25:38 +05:30
|
|
|
}
|
2020-08-21 14:40:49 +05:30
|
|
|
Leaf {
|
|
|
|
header,
|
|
|
|
keys,
|
|
|
|
values,
|
|
|
|
} => {
|
2020-09-18 15:46:09 +05:30
|
|
|
if let Err(e) = visitor.visit(path, &kr, &header, &keys, &values) {
|
|
|
|
let e = BTreeError::Path(path.clone(), Box::new(e.clone()));
|
2020-09-16 19:40:01 +05:30
|
|
|
self.set_fail(b.loc, e.clone());
|
|
|
|
return Err(e);
|
|
|
|
}
|
2020-08-20 15:25:38 +05:30
|
|
|
}
|
2020-08-03 17:07:32 +05:30
|
|
|
}
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
2020-08-03 19:34:59 +05:30
|
|
|
|
2020-09-18 15:46:09 +05:30
|
|
|
fn walk_node<NV, V>(
|
|
|
|
&self,
|
|
|
|
path: &mut Vec<u64>,
|
|
|
|
visitor: &NV,
|
|
|
|
kr: &KeyRange,
|
|
|
|
b: &Block,
|
|
|
|
is_root: bool,
|
|
|
|
) -> Result<()>
|
2020-09-16 19:40:01 +05:30
|
|
|
where
|
|
|
|
NV: NodeVisitor<V>,
|
|
|
|
V: Unpack,
|
|
|
|
{
|
2020-09-18 15:46:09 +05:30
|
|
|
path.push(b.loc);
|
|
|
|
let r = self.walk_node_(path, visitor, kr, b, is_root);
|
|
|
|
path.pop();
|
2020-09-16 19:40:01 +05:30
|
|
|
r
|
|
|
|
}
|
|
|
|
|
2020-09-18 15:46:09 +05:30
|
|
|
pub fn walk<NV, V>(&self, path: &mut Vec<u64>, visitor: &NV, root: u64) -> Result<()>
|
2020-08-03 19:34:59 +05:30
|
|
|
where
|
|
|
|
NV: NodeVisitor<V>,
|
2020-08-05 12:31:02 +05:30
|
|
|
V: Unpack,
|
2020-08-03 19:34:59 +05:30
|
|
|
{
|
2020-09-16 19:40:01 +05:30
|
|
|
if self.sm_inc(root) > 0 {
|
|
|
|
if let Some(e) = self.failed(root) {
|
|
|
|
Err(e.clone())
|
|
|
|
} else {
|
|
|
|
Ok(())
|
|
|
|
}
|
2020-08-10 17:00:12 +05:30
|
|
|
} else {
|
2020-09-18 15:46:09 +05:30
|
|
|
let root = self.engine.read(root).map_err(|_| io_err(path))?;
|
2020-09-16 19:40:01 +05:30
|
|
|
let kr = KeyRange {
|
|
|
|
start: None,
|
|
|
|
end: None,
|
|
|
|
};
|
2020-09-18 15:46:09 +05:30
|
|
|
self.walk_node(path, visitor, &kr, &root, true)
|
2020-08-10 17:00:12 +05:30
|
|
|
}
|
2020-08-03 19:34:59 +05:30
|
|
|
}
|
2020-08-03 17:07:32 +05:30
|
|
|
}
|
|
|
|
|
2020-08-21 14:40:49 +05:30
|
|
|
//--------------------------------
|
|
|
|
|
2020-09-16 19:40:01 +05:30
|
|
|
/*
|
2020-08-21 14:40:49 +05:30
|
|
|
fn walk_node_threaded<NV, V>(
|
|
|
|
w: Arc<BTreeWalker>,
|
|
|
|
pool: &ThreadPool,
|
|
|
|
visitor: Arc<NV>,
|
2020-09-16 19:40:01 +05:30
|
|
|
kr: &KeyRange,
|
2020-08-21 14:40:49 +05:30
|
|
|
b: &Block,
|
|
|
|
is_root: bool,
|
|
|
|
) -> Result<()>
|
|
|
|
where
|
|
|
|
NV: NodeVisitor<V> + Send + Sync + 'static,
|
|
|
|
V: Unpack,
|
|
|
|
{
|
|
|
|
use Node::*;
|
|
|
|
|
|
|
|
let bt = checksum::metadata_block_type(b.get_data());
|
|
|
|
if bt != checksum::BT::NODE {
|
2020-09-16 19:40:01 +05:30
|
|
|
return Err(node_err_s(format!(
|
|
|
|
"checksum failed for node {}, {:?}",
|
|
|
|
b.loc, bt
|
|
|
|
)));
|
2020-08-21 14:40:49 +05:30
|
|
|
}
|
|
|
|
|
|
|
|
let node = unpack_node::<V>(&b.get_data(), w.ignore_non_fatal, is_root)?;
|
|
|
|
|
|
|
|
match node {
|
2020-09-16 19:40:01 +05:30
|
|
|
Internal { keys, values, .. } => {
|
|
|
|
let krs = BTreeWalker::split_key_ranges(&kr, &keys)?;
|
|
|
|
walk_nodes_threaded(w, pool, visitor, &krs, &values)?;
|
2020-08-21 14:40:49 +05:30
|
|
|
}
|
|
|
|
Leaf {
|
|
|
|
header,
|
|
|
|
keys,
|
|
|
|
values,
|
|
|
|
} => {
|
2020-09-16 19:40:01 +05:30
|
|
|
visitor.visit(kr, &header, &keys, &values)?;
|
2020-08-21 14:40:49 +05:30
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
fn walk_nodes_threaded<NV, V>(
|
|
|
|
w: Arc<BTreeWalker>,
|
|
|
|
pool: &ThreadPool,
|
|
|
|
visitor: Arc<NV>,
|
2020-09-16 19:40:01 +05:30
|
|
|
krs: &[KeyRange],
|
2020-08-21 14:40:49 +05:30
|
|
|
bs: &[u64],
|
|
|
|
) -> Result<()>
|
|
|
|
where
|
|
|
|
NV: NodeVisitor<V> + Send + Sync + 'static,
|
|
|
|
V: Unpack,
|
|
|
|
{
|
|
|
|
let mut blocks = Vec::new();
|
|
|
|
for b in bs {
|
|
|
|
if w.sm_inc(*b)? == 0 {
|
2020-09-02 17:27:47 +05:30
|
|
|
blocks.push(*b);
|
2020-08-21 14:40:49 +05:30
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-09-16 19:40:01 +05:30
|
|
|
let rblocks = convert_io_err(w.engine.read_many(&blocks[0..]))?;
|
2020-08-21 14:40:49 +05:30
|
|
|
|
2020-09-16 19:40:01 +05:30
|
|
|
let mut i = 0;
|
|
|
|
for b in rblocks {
|
2020-09-02 17:27:47 +05:30
|
|
|
match b {
|
2020-09-16 19:40:01 +05:30
|
|
|
Err(_) => {
|
|
|
|
// FIXME: aggregate these
|
|
|
|
return Err(io_err());
|
|
|
|
}
|
2020-09-02 17:27:47 +05:30
|
|
|
Ok(b) => {
|
|
|
|
let w = w.clone();
|
|
|
|
let visitor = visitor.clone();
|
2020-09-16 19:40:01 +05:30
|
|
|
let kr = krs[i].clone();
|
|
|
|
|
2020-09-02 17:27:47 +05:30
|
|
|
pool.execute(move || {
|
2020-09-16 19:40:01 +05:30
|
|
|
let result = w.walk_node(visitor.as_ref(), &kr, &b, false);
|
|
|
|
if result.is_err() {
|
|
|
|
todo!();
|
|
|
|
}
|
2020-09-02 17:27:47 +05:30
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
2020-09-16 19:40:01 +05:30
|
|
|
|
|
|
|
i += 1;
|
2020-08-21 14:40:49 +05:30
|
|
|
}
|
|
|
|
pool.join();
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn walk_threaded<NV, V>(
|
|
|
|
w: Arc<BTreeWalker>,
|
|
|
|
pool: &ThreadPool,
|
|
|
|
visitor: Arc<NV>,
|
|
|
|
root: u64,
|
|
|
|
) -> Result<()>
|
|
|
|
where
|
|
|
|
NV: NodeVisitor<V> + Send + Sync + 'static,
|
|
|
|
V: Unpack,
|
|
|
|
{
|
|
|
|
if w.sm_inc(root)? > 0 {
|
|
|
|
Ok(())
|
|
|
|
} else {
|
2020-09-16 19:40:01 +05:30
|
|
|
let root = convert_io_err(w.engine.read(root))?;
|
|
|
|
let kr = KeyRange {
|
|
|
|
start: None,
|
|
|
|
end: None,
|
|
|
|
};
|
|
|
|
walk_node_threaded(w, pool, visitor, &kr, &root, true)
|
2020-08-21 14:40:49 +05:30
|
|
|
}
|
|
|
|
}
|
2020-09-16 19:40:01 +05:30
|
|
|
*/
|
|
|
|
|
|
|
|
pub fn walk_threaded<NV, V>(
|
2020-09-18 15:46:09 +05:30
|
|
|
path: &mut Vec<u64>,
|
2020-09-16 19:40:01 +05:30
|
|
|
w: Arc<BTreeWalker>,
|
|
|
|
pool: &ThreadPool,
|
|
|
|
visitor: Arc<NV>,
|
|
|
|
root: u64,
|
|
|
|
) -> Result<()>
|
|
|
|
where
|
|
|
|
NV: NodeVisitor<V> + Send + Sync + 'static,
|
|
|
|
V: Unpack,
|
|
|
|
{
|
2020-09-18 15:46:09 +05:30
|
|
|
w.walk(path, visitor.as_ref(), root)
|
2020-09-16 19:40:01 +05:30
|
|
|
}
|
2020-08-21 14:40:49 +05:30
|
|
|
|
2020-08-03 17:07:32 +05:30
|
|
|
//------------------------------------------
|
2020-08-10 19:15:35 +05:30
|
|
|
|
|
|
|
struct ValueCollector<V> {
|
2020-08-20 15:35:14 +05:30
|
|
|
values: Mutex<BTreeMap<u64, V>>,
|
2020-08-10 19:15:35 +05:30
|
|
|
}
|
|
|
|
|
|
|
|
impl<V> ValueCollector<V> {
|
|
|
|
fn new() -> ValueCollector<V> {
|
2020-08-10 20:12:10 +05:30
|
|
|
ValueCollector {
|
2020-08-20 15:35:14 +05:30
|
|
|
values: Mutex::new(BTreeMap::new()),
|
2020-08-10 20:12:10 +05:30
|
|
|
}
|
2020-08-10 19:15:35 +05:30
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-09-18 14:36:33 +05:30
|
|
|
// FIXME: should we be using Copy rather than clone? (Yes)
|
|
|
|
impl<V: Unpack + Copy> NodeVisitor<V> for ValueCollector<V> {
|
2020-09-18 15:46:09 +05:30
|
|
|
fn visit(&self, _path: &Vec<u64>, _kr: &KeyRange, _h: &NodeHeader, keys: &[u64], values: &[V]) -> Result<()> {
|
2020-08-20 15:35:14 +05:30
|
|
|
let mut vals = self.values.lock().unwrap();
|
2020-08-20 15:25:38 +05:30
|
|
|
for n in 0..keys.len() {
|
2020-08-20 15:35:14 +05:30
|
|
|
vals.insert(keys[n], values[n].clone());
|
2020-08-10 19:15:35 +05:30
|
|
|
}
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-09-18 14:36:33 +05:30
|
|
|
pub fn btree_to_map<V: Unpack + Copy>(
|
2020-09-18 15:46:09 +05:30
|
|
|
path: &mut Vec<u64>,
|
2020-08-10 20:12:10 +05:30
|
|
|
engine: Arc<dyn IoEngine + Send + Sync>,
|
|
|
|
ignore_non_fatal: bool,
|
|
|
|
root: u64,
|
|
|
|
) -> Result<BTreeMap<u64, V>> {
|
2020-08-21 14:40:49 +05:30
|
|
|
let walker = BTreeWalker::new(engine, ignore_non_fatal);
|
|
|
|
let visitor = ValueCollector::<V>::new();
|
2020-09-18 15:46:09 +05:30
|
|
|
let mut path = Vec::new();
|
|
|
|
walker.walk(&mut path, &visitor, root)?;
|
2020-08-20 15:35:14 +05:30
|
|
|
Ok(visitor.values.into_inner().unwrap())
|
2020-08-10 19:15:35 +05:30
|
|
|
}
|
|
|
|
|
2020-09-18 14:36:33 +05:30
|
|
|
pub fn btree_to_map_with_sm<V: Unpack + Copy>(
|
2020-09-18 15:46:09 +05:30
|
|
|
path: &mut Vec<u64>,
|
2020-08-11 15:20:43 +05:30
|
|
|
engine: Arc<dyn IoEngine + Send + Sync>,
|
|
|
|
sm: Arc<Mutex<dyn SpaceMap + Send + Sync>>,
|
|
|
|
ignore_non_fatal: bool,
|
|
|
|
root: u64,
|
|
|
|
) -> Result<BTreeMap<u64, V>> {
|
2020-08-21 14:40:49 +05:30
|
|
|
let walker = BTreeWalker::new_with_sm(engine, sm, ignore_non_fatal)?;
|
|
|
|
let visitor = ValueCollector::<V>::new();
|
2020-08-11 15:20:43 +05:30
|
|
|
|
2020-09-18 15:46:09 +05:30
|
|
|
walker.walk(path, &visitor, root)?;
|
2020-08-20 15:35:14 +05:30
|
|
|
Ok(visitor.values.into_inner().unwrap())
|
2020-08-11 15:20:43 +05:30
|
|
|
}
|
|
|
|
|
2020-08-10 19:15:35 +05:30
|
|
|
//------------------------------------------
|
2020-09-18 14:36:33 +05:30
|
|
|
|
|
|
|
struct ValuePathCollector<V> {
|
|
|
|
values: Mutex<BTreeMap<u64, (Vec<u64>, V)>>
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<V> ValuePathCollector<V> {
|
|
|
|
fn new() -> ValuePathCollector<V> {
|
|
|
|
ValuePathCollector {
|
|
|
|
values: Mutex::new(BTreeMap::new()),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-09-18 15:46:09 +05:30
|
|
|
impl<V: Unpack + Clone> NodeVisitor<V> for ValuePathCollector<V> {
|
|
|
|
fn visit(&self, path: &Vec<u64>, _kr: &KeyRange, _h: &NodeHeader, keys: &[u64], values: &[V]) -> Result<()> {
|
|
|
|
let mut vals = self.values.lock().unwrap();
|
|
|
|
for n in 0..keys.len() {
|
|
|
|
vals.insert(keys[n], (path.clone(), values[n].clone()));
|
|
|
|
}
|
2020-09-18 14:36:33 +05:30
|
|
|
|
2020-09-18 15:46:09 +05:30
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn btree_to_map_with_path<V: Unpack + Copy>(
|
|
|
|
path: &mut Vec<u64>,
|
|
|
|
engine: Arc<dyn IoEngine + Send + Sync>,
|
|
|
|
sm: Arc<Mutex<dyn SpaceMap + Send + Sync>>,
|
|
|
|
ignore_non_fatal: bool,
|
|
|
|
root: u64,
|
|
|
|
) -> Result<BTreeMap<u64, (Vec<u64>, V)>> {
|
|
|
|
let walker = BTreeWalker::new_with_sm(engine, sm, ignore_non_fatal)?;
|
|
|
|
let visitor = ValuePathCollector::<V>::new();
|
|
|
|
|
|
|
|
walker.walk(path, &visitor, root)?;
|
|
|
|
Ok(visitor.values.into_inner().unwrap())
|
2020-09-18 14:36:33 +05:30
|
|
|
}
|
|
|
|
|
|
|
|
//------------------------------------------
|