[thin_check (rust)] factor out btree_to_map() fn

This commit is contained in:
Joe Thornber
2020-08-10 14:45:35 +01:00
parent cbc9c2c72a
commit e28c602c3d
2 changed files with 60 additions and 80 deletions

View File

@@ -2,6 +2,7 @@ use anyhow::{anyhow, Result};
use fixedbitset::FixedBitSet; use fixedbitset::FixedBitSet;
use nom::{number::complete::*, IResult}; use nom::{number::complete::*, IResult};
use std::sync::{Arc, Mutex}; use std::sync::{Arc, Mutex};
use std::collections::BTreeMap;
use crate::checksum; use crate::checksum;
use crate::io_engine::*; use crate::io_engine::*;
@@ -307,3 +308,44 @@ impl BTreeWalker {
} }
//------------------------------------------ //------------------------------------------
struct ValueCollector<V> {
values: BTreeMap<u64, V>,
}
impl<V> ValueCollector<V> {
fn new() -> ValueCollector<V> {
ValueCollector { values: BTreeMap::new() }
}
}
impl<V: Unpack + Clone> NodeVisitor<V> for ValueCollector<V> {
fn visit(&mut self, _w: &BTreeWalker, _b: &Block, node: &Node<V>) -> Result<()> {
if let Node::Leaf {
header: _h,
keys,
values,
} = node
{
for n in 0..keys.len() {
let k = keys[n];
let v = values[n].clone();
self.values.insert(k, v);
}
}
Ok(())
}
}
pub fn btree_to_map<V: Unpack + Clone>(engine: Arc<dyn IoEngine + Send + Sync>,
ignore_non_fatal: bool,
root: u64) -> Result<BTreeMap<u64, V>> {
let mut walker = BTreeWalker::new(engine, ignore_non_fatal);
let mut visitor = ValueCollector::<V>::new();
walker.walk(&mut visitor, root)?;
Ok(visitor.values)
}
//------------------------------------------

View File

@@ -8,7 +8,7 @@ use threadpool::ThreadPool;
use crate::checksum; use crate::checksum;
use crate::io_engine::{AsyncIoEngine, Block, IoEngine, SyncIoEngine}; use crate::io_engine::{AsyncIoEngine, Block, IoEngine, SyncIoEngine};
use crate::pdata::btree::{unpack, BTreeWalker, Node, NodeVisitor, Unpack}; use crate::pdata::btree::{btree_to_map, unpack, BTreeWalker, Node, NodeVisitor, Unpack};
use crate::pdata::space_map::*; use crate::pdata::space_map::*;
use crate::thin::superblock::*; use crate::thin::superblock::*;
@@ -139,37 +139,6 @@ impl Unpack for DeviceDetail {
} }
} }
struct DeviceVisitor {
devs: BTreeMap<u32, DeviceDetail>,
}
impl DeviceVisitor {
pub fn new() -> DeviceVisitor {
DeviceVisitor {
devs: BTreeMap::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);
}
}
Ok(())
}
}
//------------------------------------------ //------------------------------------------
struct IndexVisitor { struct IndexVisitor {
@@ -197,38 +166,6 @@ impl NodeVisitor<IndexEntry> for IndexVisitor {
//------------------------------------------ //------------------------------------------
// FIXME: move to btree
struct ValueCollector<V> {
values: Vec<(u64, V)>,
}
impl<V> ValueCollector<V> {
fn new() -> ValueCollector<V> {
ValueCollector { values: Vec::new() }
}
}
impl<V: Unpack + Clone> NodeVisitor<V> for ValueCollector<V> {
fn visit(&mut self, _w: &BTreeWalker, _b: &Block, node: &Node<V>) -> Result<()> {
if let Node::Leaf {
header: _h,
keys,
values,
} = node
{
for n in 0..keys.len() {
let k = keys[n];
let v = values[n].clone();
self.values.push((k, v));
}
}
Ok(())
}
}
//------------------------------------------
struct OverflowChecker<'a> { struct OverflowChecker<'a> {
data_sm: &'a dyn SpaceMap, data_sm: &'a dyn SpaceMap,
} }
@@ -288,22 +225,12 @@ pub fn check(opts: &ThinCheckOptions) -> Result<()> {
let sb = read_superblock(engine.as_ref(), SUPERBLOCK_LOCATION)?; let sb = read_superblock(engine.as_ref(), SUPERBLOCK_LOCATION)?;
// device details // device details
let nr_devs; let devs = btree_to_map::<DeviceDetail>(engine.clone(), false, sb.details_root)?;
{ let nr_devs = devs.len();
let mut visitor = DeviceVisitor::new(); println!("found {} devices", nr_devs);
let mut w = BTreeWalker::new(engine.clone(), false);
w.walk(&mut visitor, sb.details_root)?;
nr_devs = visitor.devs.len();
println!("found {} devices", visitor.devs.len());
}
// mapping top level // mapping top level
let mut roots = BTreeMap::new(); let roots = btree_to_map::<u64>(engine.clone(), false, sb.mapping_root)?;
{
let mut visitor = TopLevelVisitor { roots: &mut roots };
let mut w = BTreeWalker::new(engine.clone(), false);
let _result = w.walk(&mut visitor, sb.mapping_root)?;
}
// mapping bottom level // mapping bottom level
let data_sm; let data_sm;
@@ -342,7 +269,7 @@ pub fn check(opts: &ThinCheckOptions) -> Result<()> {
// data space map // data space map
{ {
let mut data_sm = data_sm.lock().unwrap(); let data_sm = data_sm.lock().unwrap();
let root = unpack::<SMRoot>(&sb.data_sm_root[0..])?; let root = unpack::<SMRoot>(&sb.data_sm_root[0..])?;
let nr_data_blocks = root.nr_blocks; let nr_data_blocks = root.nr_blocks;
eprintln!("data root: {:?}", root); eprintln!("data root: {:?}", root);
@@ -369,6 +296,7 @@ pub fn check(opts: &ThinCheckOptions) -> Result<()> {
engine.read_many(&mut blocks)?; engine.read_many(&mut blocks)?;
let mut leaks = 0;
let mut fail = false; let mut fail = false;
let mut blocknr = 0; let mut blocknr = 0;
for (n, _i) in v.entries.iter().enumerate() { for (n, _i) in v.entries.iter().enumerate() {
@@ -389,7 +317,10 @@ pub fn check(opts: &ThinCheckOptions) -> Result<()> {
match e { match e {
BitmapEntry::Small(actual) => { BitmapEntry::Small(actual) => {
let expected = data_sm.get(blocknr)?; let expected = data_sm.get(blocknr)?;
if actual != expected as u8 { if actual == 1 && expected == 0 {
eprintln!("Data block {} leaked.", blocknr);
leaks += 1;
} else if actual != expected as u8 {
eprintln!("Bad reference count for data block {}. Expected {}, but space map contains {}.", eprintln!("Bad reference count for data block {}. Expected {}, but space map contains {}.",
blocknr, expected, actual); blocknr, expected, actual);
fail = true; fail = true;
@@ -408,6 +339,13 @@ pub fn check(opts: &ThinCheckOptions) -> Result<()> {
} }
} }
if leaks > 0 {
eprintln!(
"{} data blocks have leaked. Use --auto-repair to fix.",
leaks
);
}
if fail { if fail {
return Err(anyhow!("Inconsistent data space map")); return Err(anyhow!("Inconsistent data space map"));
} }