[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 { pub trait ValueType {
type Value;
// The size of the value when on disk. // The size of the value when on disk.
fn disk_size() -> u32; 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; const NODE_HEADER_SIZE: usize = 32;
@ -59,7 +60,7 @@ pub enum Node<V: ValueType> {
Leaf { Leaf {
header: NodeHeader, header: NodeHeader,
keys: Vec<u64>, 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))?; let (i, header) = to_any(unpack_node_header(data))?;
// FIXME: lift checks to own fn if header.is_leaf && header.value_size != V::disk_size() {
if header.value_size != V::disk_size() {
return node_err(format!( return node_err(format!(
"value_size mismatch: expected {}, was {}", "value_size mismatch: expected {}, was {}",
V::disk_size(), 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 { 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)); 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 u64 {
impl ValueType for ValueU64 {
type Value = u64;
fn disk_size() -> u32 { fn disk_size() -> u32 {
8 8
} }
@ -180,10 +176,10 @@ pub struct BTreeWalker {
} }
impl 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 nr_blocks = engine.get_nr_blocks() as usize;
let r: BTreeWalker = BTreeWalker { let r: BTreeWalker = BTreeWalker {
engine: Arc::new(engine), engine: engine,
seen: Arc::new(Mutex::new(FixedBitSet::with_capacity(nr_blocks))), seen: Arc::new(Mutex::new(FixedBitSet::with_capacity(nr_blocks))),
ignore_non_fatal, ignore_non_fatal,
}; };
@ -242,16 +238,22 @@ impl BTreeWalker {
Ok(()) Ok(())
} }
pub fn walk<NV, V>( pub fn walk_b<NV, V>(&mut self, visitor: &mut NV, root: &Block) -> Result<()>
&mut self,
visitor: &mut NV,
root: &Block,
) -> Result<()>
where where
NV: NodeVisitor<V>, NV: NodeVisitor<V>,
V: ValueType, 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 anyhow::{anyhow, Result};
use nom::{number::complete::*, IResult}; use nom::{number::complete::*, IResult};
use std::collections::HashMap;
use std::path::Path; use std::path::Path;
use std::sync::{Arc, Mutex}; use std::sync::{Arc, Mutex};
use std::time::Instant; use std::time::Instant;
use threadpool::ThreadPool; use threadpool::ThreadPool;
use crate::block_manager::{AsyncIoEngine, Block, IoEngine}; 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::*; use crate::thin::superblock::*;
//------------------------------------------ //------------------------------------------
@ -17,11 +18,7 @@ struct BlockTime {
time: u32, time: u32,
} }
struct ValueBlockTime; impl ValueType for BlockTime {
impl ValueType for ValueBlockTime {
type Value = BlockTime;
fn disk_size() -> u32 { fn disk_size() -> u32 {
8 8
} }
@ -43,8 +40,8 @@ impl ValueType for ValueBlockTime {
struct TopLevelVisitor {} struct TopLevelVisitor {}
impl NodeVisitor<ValueU64> for TopLevelVisitor { impl NodeVisitor<u64> for TopLevelVisitor {
fn visit(&mut self, w: &BTreeWalker, _b: &Block, node: &Node<ValueU64>) -> Result<()> { fn visit(&mut self, w: &BTreeWalker, _b: &Block, node: &Node<u64>) -> Result<()> {
if let Node::Leaf { if let Node::Leaf {
header: _h, header: _h,
keys, keys,
@ -77,7 +74,7 @@ impl NodeVisitor<ValueU64> for TopLevelVisitor {
let mut w = w.clone(); let mut w = w.clone();
pool.execute(move || { pool.execute(move || {
let mut v = BottomLevelVisitor {}; 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); eprintln!("checked thin_dev {} -> {:?}", thin_id, result);
}); });
} }
@ -91,8 +88,67 @@ impl NodeVisitor<ValueU64> for TopLevelVisitor {
struct BottomLevelVisitor {} struct BottomLevelVisitor {}
impl NodeVisitor<ValueBlockTime> for BottomLevelVisitor { impl NodeVisitor<BlockTime> for BottomLevelVisitor {
fn visit(&mut self, _w: &BTreeWalker, _b: &Block, _node: &Node<ValueBlockTime>) -> Result<()> { 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(()) Ok(())
} }
} }
@ -101,19 +157,25 @@ impl NodeVisitor<ValueBlockTime> for BottomLevelVisitor {
pub fn check(dev: &Path) -> Result<()> { pub fn check(dev: &Path) -> Result<()> {
//let mut engine = SyncIoEngine::new(dev)?; //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 now = Instant::now();
let sb = read_superblock(&mut engine, SUPERBLOCK_LOCATION)?; let sb = read_superblock(engine.as_ref(), SUPERBLOCK_LOCATION)?;
eprintln!("{:?}", sb); eprintln!("{:?}", sb);
let mut root = Block::new(sb.mapping_root); {
engine.read(&mut root)?; let mut visitor = DeviceVisitor::new();
let mut w = BTreeWalker::new(engine.clone(), false);
let mut visitor = TopLevelVisitor {}; w.walk(&mut visitor, sb.details_root)?;
let mut w = BTreeWalker::new(engine, false); println!("found {} devices", visitor.devs.len());
let _result = w.walk(&mut visitor, &root)?; }
println!("read mapping tree in {} ms", now.elapsed().as_millis());
{
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(()) 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); let mut b = Block::new(loc);
engine.read(&mut b)?; engine.read(&mut b)?;