[thin_check (rust)] walk devices tree.
This commit is contained in:
parent
1368227a71
commit
f56ea2d031
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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(())
|
||||||
}
|
}
|
||||||
|
@ -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)?;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user