[thin_check (rust)] walk devices tree.

This commit is contained in:
Joe Thornber 2020-08-03 16:22:08 +01:00
parent 1368227a71
commit f56ea2d031
3 changed files with 105 additions and 41 deletions

View File

@ -9,10 +9,11 @@ use crate::checksum;
//------------------------------------------
pub trait ValueType {
type Value;
// The size of the value when on disk.
fn disk_size() -> u32;
fn unpack(data: &[u8]) -> IResult<&[u8], Self::Value>;
fn unpack(data: &[u8]) -> IResult<&[u8], Self>
where
Self: std::marker::Sized;
}
const NODE_HEADER_SIZE: usize = 32;
@ -59,7 +60,7 @@ pub enum Node<V: ValueType> {
Leaf {
header: NodeHeader,
keys: Vec<u64>,
values: Vec<V::Value>,
values: Vec<V>,
},
}
@ -85,8 +86,7 @@ pub fn unpack_node<V: ValueType>(
let (i, header) = to_any(unpack_node_header(data))?;
// FIXME: lift checks to own fn
if header.value_size != V::disk_size() {
if header.is_leaf && header.value_size != V::disk_size() {
return node_err(format!(
"value_size mismatch: expected {}, was {}",
V::disk_size(),
@ -94,7 +94,7 @@ pub fn unpack_node<V: ValueType>(
));
}
let elt_size = V::disk_size() + 8;
let elt_size = header.value_size + 8;
if elt_size as usize * header.max_entries as usize + NODE_HEADER_SIZE > BLOCK_SIZE {
return node_err(format!("max_entries is too large ({})", header.max_entries));
}
@ -152,11 +152,7 @@ pub fn unpack_node<V: ValueType>(
//------------------------------------------
pub struct ValueU64;
impl ValueType for ValueU64 {
type Value = u64;
impl ValueType for u64 {
fn disk_size() -> u32 {
8
}
@ -180,10 +176,10 @@ pub struct BTreeWalker {
}
impl BTreeWalker {
pub fn new(engine: AsyncIoEngine, ignore_non_fatal: bool) -> BTreeWalker {
pub fn new(engine: Arc<AsyncIoEngine>, ignore_non_fatal: bool) -> BTreeWalker {
let nr_blocks = engine.get_nr_blocks() as usize;
let r: BTreeWalker = BTreeWalker {
engine: Arc::new(engine),
engine: engine,
seen: Arc::new(Mutex::new(FixedBitSet::with_capacity(nr_blocks))),
ignore_non_fatal,
};
@ -242,16 +238,22 @@ impl BTreeWalker {
Ok(())
}
pub fn walk<NV, V>(
&mut self,
visitor: &mut NV,
root: &Block,
) -> Result<()>
pub fn walk_b<NV, V>(&mut self, visitor: &mut NV, root: &Block) -> Result<()>
where
NV: NodeVisitor<V>,
V: ValueType,
{
self.walk_node(visitor, &root, true)
self.walk_node(visitor, &root, true)
}
pub fn walk<NV, V>(&mut self, visitor: &mut NV, root: u64) -> Result<()>
where
NV: NodeVisitor<V>,
V: ValueType,
{
let mut root = Block::new(root);
self.engine.read(&mut root)?;
self.walk_node(visitor, &root, true)
}
}

View File

@ -1,12 +1,13 @@
use anyhow::{anyhow, Result};
use nom::{number::complete::*, IResult};
use std::collections::HashMap;
use std::path::Path;
use std::sync::{Arc, Mutex};
use std::time::Instant;
use threadpool::ThreadPool;
use crate::block_manager::{AsyncIoEngine, Block, IoEngine};
use crate::pdata::btree::{BTreeWalker, Node, NodeVisitor, ValueType, ValueU64};
use crate::pdata::btree::{BTreeWalker, Node, NodeVisitor, ValueType};
use crate::thin::superblock::*;
//------------------------------------------
@ -17,11 +18,7 @@ struct BlockTime {
time: u32,
}
struct ValueBlockTime;
impl ValueType for ValueBlockTime {
type Value = BlockTime;
impl ValueType for BlockTime {
fn disk_size() -> u32 {
8
}
@ -43,8 +40,8 @@ impl ValueType for ValueBlockTime {
struct TopLevelVisitor {}
impl NodeVisitor<ValueU64> for TopLevelVisitor {
fn visit(&mut self, w: &BTreeWalker, _b: &Block, node: &Node<ValueU64>) -> Result<()> {
impl NodeVisitor<u64> for TopLevelVisitor {
fn visit(&mut self, w: &BTreeWalker, _b: &Block, node: &Node<u64>) -> Result<()> {
if let Node::Leaf {
header: _h,
keys,
@ -77,7 +74,7 @@ impl NodeVisitor<ValueU64> for TopLevelVisitor {
let mut w = w.clone();
pool.execute(move || {
let mut v = BottomLevelVisitor {};
let result = w.walk(&mut v, &b).expect("walk failed"); // FIXME: return error
let result = w.walk_b(&mut v, &b).expect("walk failed"); // FIXME: return error
eprintln!("checked thin_dev {} -> {:?}", thin_id, result);
});
}
@ -91,8 +88,67 @@ impl NodeVisitor<ValueU64> for TopLevelVisitor {
struct BottomLevelVisitor {}
impl NodeVisitor<ValueBlockTime> for BottomLevelVisitor {
fn visit(&mut self, _w: &BTreeWalker, _b: &Block, _node: &Node<ValueBlockTime>) -> Result<()> {
impl NodeVisitor<BlockTime> for BottomLevelVisitor {
fn visit(&mut self, _w: &BTreeWalker, _b: &Block, _node: &Node<BlockTime>) -> Result<()> {
Ok(())
}
}
//------------------------------------------
#[derive(Clone)]
struct DeviceDetail {
mapped_blocks: u64,
transaction_id: u64,
creation_time: u32,
snapshotted_time: u32,
}
impl ValueType for DeviceDetail {
fn disk_size() -> u32 {
24
}
fn unpack(i: &[u8]) -> IResult<&[u8], DeviceDetail> {
let (i, mapped_blocks) = le_u64(i)?;
let (i, transaction_id) = le_u64(i)?;
let (i, creation_time) = le_u32(i)?;
let (i, snapshotted_time) = le_u32(i)?;
Ok((
i,
DeviceDetail {
mapped_blocks,
transaction_id,
creation_time,
snapshotted_time,
},
))
}
}
struct DeviceVisitor {
devs: HashMap<u32, DeviceDetail>,
}
impl DeviceVisitor {
pub fn new() -> DeviceVisitor {
DeviceVisitor {
devs: HashMap::new(),
}
}
}
impl NodeVisitor<DeviceDetail> for DeviceVisitor {
fn visit(&mut self, _w: &BTreeWalker, _b: &Block, node: &Node<DeviceDetail>) -> Result<()> {
if let Node::Leaf {header: _h, keys, values} = node {
for n in 0..keys.len() {
let k = keys[n] as u32;
let v = values[n].clone();
self.devs.insert(k, v.clone());
}
}
Ok(())
}
}
@ -101,19 +157,25 @@ impl NodeVisitor<ValueBlockTime> for BottomLevelVisitor {
pub fn check(dev: &Path) -> Result<()> {
//let mut engine = SyncIoEngine::new(dev)?;
let mut engine = AsyncIoEngine::new(dev, 256)?;
let mut engine = Arc::new(AsyncIoEngine::new(dev, 256)?);
let now = Instant::now();
let sb = read_superblock(&mut engine, SUPERBLOCK_LOCATION)?;
let sb = read_superblock(engine.as_ref(), SUPERBLOCK_LOCATION)?;
eprintln!("{:?}", sb);
let mut root = Block::new(sb.mapping_root);
engine.read(&mut root)?;
let mut visitor = TopLevelVisitor {};
let mut w = BTreeWalker::new(engine, false);
let _result = w.walk(&mut visitor, &root)?;
println!("read mapping tree in {} ms", now.elapsed().as_millis());
{
let mut visitor = DeviceVisitor::new();
let mut w = BTreeWalker::new(engine.clone(), false);
w.walk(&mut visitor, sb.details_root)?;
println!("found {} devices", visitor.devs.len());
}
{
let mut visitor = TopLevelVisitor {};
let mut w = BTreeWalker::new(engine.clone(), false);
let _result = w.walk(&mut visitor, sb.mapping_root)?;
println!("read mapping tree in {} ms", now.elapsed().as_millis());
}
Ok(())
}

View File

@ -85,7 +85,7 @@ fn unpack(data: &[u8]) -> IResult<&[u8], Superblock> {
))
}
pub fn read_superblock<E: IoEngine>(engine: &mut E, loc: u64) -> Result<Superblock> {
pub fn read_superblock<E: IoEngine>(engine: &E, loc: u64) -> Result<Superblock> {
let mut b = Block::new(loc);
engine.read(&mut b)?;