[thin_check (rust)] change BTreeWalker to use a space map rather than seen bitset
This commit is contained in:
parent
50bde693a1
commit
34425521e2
@ -1,11 +1,11 @@
|
|||||||
use anyhow::{anyhow, Result};
|
use anyhow::{anyhow, Result};
|
||||||
use fixedbitset::FixedBitSet;
|
|
||||||
use nom::{number::complete::*, IResult};
|
use nom::{number::complete::*, IResult};
|
||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
|
|
||||||
use crate::checksum;
|
use crate::checksum;
|
||||||
use crate::io_engine::*;
|
use crate::io_engine::*;
|
||||||
|
use crate::pdata::space_map::*;
|
||||||
use crate::pdata::unpack::*;
|
use crate::pdata::unpack::*;
|
||||||
|
|
||||||
// FIXME: check that keys are in ascending order between nodes.
|
// FIXME: check that keys are in ascending order between nodes.
|
||||||
@ -153,7 +153,7 @@ pub trait NodeVisitor<V: Unpack> {
|
|||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct BTreeWalker {
|
pub struct BTreeWalker {
|
||||||
pub engine: Arc<dyn IoEngine + Send + Sync>,
|
pub engine: Arc<dyn IoEngine + Send + Sync>,
|
||||||
pub seen: Arc<Mutex<FixedBitSet>>,
|
pub sm: Arc<Mutex<dyn SpaceMap + Send + Sync>>,
|
||||||
ignore_non_fatal: bool,
|
ignore_non_fatal: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -162,37 +162,35 @@ impl 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,
|
engine,
|
||||||
seen: Arc::new(Mutex::new(FixedBitSet::with_capacity(nr_blocks))),
|
sm: Arc::new(Mutex::new(RestrictedSpaceMap::new(nr_blocks as u64))),
|
||||||
ignore_non_fatal,
|
ignore_non_fatal,
|
||||||
};
|
};
|
||||||
r
|
r
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_with_seen(
|
pub fn new_with_sm(
|
||||||
engine: Arc<dyn IoEngine + Send + Sync>,
|
engine: Arc<dyn IoEngine + Send + Sync>,
|
||||||
seen: Arc<Mutex<FixedBitSet>>,
|
sm: Arc<Mutex<dyn SpaceMap + Send + Sync>>,
|
||||||
ignore_non_fatal: bool,
|
ignore_non_fatal: bool,
|
||||||
) -> BTreeWalker {
|
) -> Result<BTreeWalker> {
|
||||||
{
|
{
|
||||||
let seen = seen.lock().unwrap();
|
let sm = sm.lock().unwrap();
|
||||||
assert_eq!(seen.len(), engine.get_nr_blocks() as usize);
|
assert_eq!(sm.get_nr_blocks()?, engine.get_nr_blocks());
|
||||||
}
|
}
|
||||||
|
|
||||||
BTreeWalker {
|
Ok(BTreeWalker {
|
||||||
engine,
|
engine,
|
||||||
seen,
|
sm,
|
||||||
ignore_non_fatal,
|
ignore_non_fatal,
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_seen(&self, b: u64) -> bool {
|
// Atomically increments the ref count, and returns the _old_ count.
|
||||||
let mut seen = self.seen.lock().unwrap();
|
fn sm_inc(&self, b: u64) -> Result<u32> {
|
||||||
if !seen[b as usize] {
|
let mut sm = self.sm.lock().unwrap();
|
||||||
seen.insert(b as usize);
|
let count = sm.get(b)?;
|
||||||
return false;
|
sm.inc(b, 1)?;
|
||||||
}
|
Ok(count)
|
||||||
|
|
||||||
true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn walk_nodes<NV, V>(&mut self, visitor: &mut NV, bs: &[u64]) -> Result<()>
|
fn walk_nodes<NV, V>(&mut self, visitor: &mut NV, bs: &[u64]) -> Result<()>
|
||||||
@ -201,14 +199,11 @@ impl BTreeWalker {
|
|||||||
V: Unpack,
|
V: Unpack,
|
||||||
{
|
{
|
||||||
let mut blocks = Vec::new();
|
let mut blocks = Vec::new();
|
||||||
let mut seen = self.seen.lock().unwrap();
|
|
||||||
for b in bs {
|
for b in bs {
|
||||||
if !seen[*b as usize] {
|
if self.sm_inc(*b)? == 0 {
|
||||||
blocks.push(Block::new(*b));
|
blocks.push(Block::new(*b));
|
||||||
seen.insert(*b as usize);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
drop(seen);
|
|
||||||
|
|
||||||
self.engine.read_many(&mut blocks)?;
|
self.engine.read_many(&mut blocks)?;
|
||||||
|
|
||||||
@ -249,7 +244,7 @@ impl BTreeWalker {
|
|||||||
NV: NodeVisitor<V>,
|
NV: NodeVisitor<V>,
|
||||||
V: Unpack,
|
V: Unpack,
|
||||||
{
|
{
|
||||||
if self.is_seen(root.loc) {
|
if self.sm_inc(root.loc)? > 0 {
|
||||||
Ok(())
|
Ok(())
|
||||||
} else {
|
} else {
|
||||||
self.walk_node(visitor, &root, true)
|
self.walk_node(visitor, &root, true)
|
||||||
@ -261,7 +256,7 @@ impl BTreeWalker {
|
|||||||
NV: NodeVisitor<V>,
|
NV: NodeVisitor<V>,
|
||||||
V: Unpack,
|
V: Unpack,
|
||||||
{
|
{
|
||||||
if self.is_seen(root) {
|
if self.sm_inc(root)? > 0 {
|
||||||
Ok(())
|
Ok(())
|
||||||
} else {
|
} else {
|
||||||
let mut root = Block::new(root);
|
let mut root = Block::new(root);
|
||||||
@ -316,4 +311,17 @@ pub fn btree_to_map<V: Unpack + Clone>(
|
|||||||
Ok(visitor.values)
|
Ok(visitor.values)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn btree_to_map_with_sm<V: Unpack + Clone>(
|
||||||
|
engine: Arc<dyn IoEngine + Send + Sync>,
|
||||||
|
sm: Arc<Mutex<dyn SpaceMap + Send + Sync>>,
|
||||||
|
ignore_non_fatal: bool,
|
||||||
|
root: u64,
|
||||||
|
) -> Result<BTreeMap<u64, V>> {
|
||||||
|
let mut walker = BTreeWalker::new_with_sm(engine, sm, ignore_non_fatal)?;
|
||||||
|
let mut visitor = ValueCollector::<V>::new();
|
||||||
|
|
||||||
|
walker.walk(&mut visitor, root)?;
|
||||||
|
Ok(visitor.values)
|
||||||
|
}
|
||||||
|
|
||||||
//------------------------------------------
|
//------------------------------------------
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
use anyhow::{anyhow, Result};
|
use anyhow::{anyhow, Result};
|
||||||
|
use fixedbitset::FixedBitSet;
|
||||||
use nom::{number::complete::*, IResult};
|
use nom::{number::complete::*, IResult};
|
||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
|
|
||||||
@ -154,10 +155,13 @@ impl Unpack for Bitmap {
|
|||||||
//------------------------------------------
|
//------------------------------------------
|
||||||
|
|
||||||
pub trait SpaceMap {
|
pub trait SpaceMap {
|
||||||
|
fn get_nr_blocks(&self) -> Result<u64>;
|
||||||
fn get(&self, b: u64) -> Result<u32>;
|
fn get(&self, b: u64) -> Result<u32>;
|
||||||
fn inc(&mut self, begin: u64, len: u64) -> Result<()>;
|
fn inc(&mut self, begin: u64, len: u64) -> Result<()>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//------------------------------------------
|
||||||
|
|
||||||
pub struct CoreSpaceMap<T> {
|
pub struct CoreSpaceMap<T> {
|
||||||
counts: Vec<T>,
|
counts: Vec<T>,
|
||||||
}
|
}
|
||||||
@ -177,6 +181,10 @@ impl<V> SpaceMap for CoreSpaceMap<V>
|
|||||||
where
|
where
|
||||||
V: Copy + Default + std::ops::AddAssign + From<u8> + Into<u32>,
|
V: Copy + Default + std::ops::AddAssign + From<u8> + Into<u32>,
|
||||||
{
|
{
|
||||||
|
fn get_nr_blocks(&self) -> Result<u64> {
|
||||||
|
Ok(self.counts.len() as u64)
|
||||||
|
}
|
||||||
|
|
||||||
fn get(&self, b: u64) -> Result<u32> {
|
fn get(&self, b: u64) -> Result<u32> {
|
||||||
Ok(self.counts[b as usize].into())
|
Ok(self.counts[b as usize].into())
|
||||||
}
|
}
|
||||||
@ -189,7 +197,7 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn core_sm(nr_entries: u64, max_count: u32) -> Arc<Mutex<dyn SpaceMap + Send>> {
|
pub fn core_sm(nr_entries: u64, max_count: u32) -> Arc<Mutex<dyn SpaceMap + Send + Sync>> {
|
||||||
if max_count <= u8::MAX as u32 {
|
if max_count <= u8::MAX as u32 {
|
||||||
Arc::new(Mutex::new(CoreSpaceMap::<u8>::new(nr_entries)))
|
Arc::new(Mutex::new(CoreSpaceMap::<u8>::new(nr_entries)))
|
||||||
} else if max_count <= u16::MAX as u32 {
|
} else if max_count <= u16::MAX as u32 {
|
||||||
@ -200,3 +208,41 @@ pub fn core_sm(nr_entries: u64, max_count: u32) -> Arc<Mutex<dyn SpaceMap + Send
|
|||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------------------
|
//------------------------------------------
|
||||||
|
|
||||||
|
// This in core space map can only count to one, useful when walking
|
||||||
|
// btrees when we want to avoid visiting a node more than once, but
|
||||||
|
// aren't interested in counting how many times we've visited.
|
||||||
|
pub struct RestrictedSpaceMap {
|
||||||
|
counts: FixedBitSet,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RestrictedSpaceMap {
|
||||||
|
pub fn new(nr_entries: u64) -> RestrictedSpaceMap {
|
||||||
|
RestrictedSpaceMap {
|
||||||
|
counts: FixedBitSet::with_capacity(nr_entries as usize),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SpaceMap for RestrictedSpaceMap {
|
||||||
|
fn get_nr_blocks(&self) -> Result<u64> {
|
||||||
|
Ok(self.counts.len() as u64)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get(&self, b: u64) -> Result<u32> {
|
||||||
|
if self.counts.contains(b as usize) {
|
||||||
|
Ok(1)
|
||||||
|
} else {
|
||||||
|
Ok(0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn inc(&mut self, begin: u64, len: u64) -> Result<()> {
|
||||||
|
for b in begin..(begin + len) {
|
||||||
|
self.counts.insert(b as usize);
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
use anyhow::{anyhow, Result};
|
use anyhow::{anyhow, Result};
|
||||||
use fixedbitset::FixedBitSet;
|
|
||||||
use nom::{number::complete::*, IResult};
|
use nom::{number::complete::*, IResult};
|
||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
@ -8,9 +7,9 @@ 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::unpack::*;
|
use crate::pdata::btree::{btree_to_map, btree_to_map_with_sm, BTreeWalker, Node, NodeVisitor};
|
||||||
use crate::pdata::btree::{btree_to_map, BTreeWalker, Node, NodeVisitor};
|
|
||||||
use crate::pdata::space_map::*;
|
use crate::pdata::space_map::*;
|
||||||
|
use crate::pdata::unpack::*;
|
||||||
use crate::thin::superblock::*;
|
use crate::thin::superblock::*;
|
||||||
|
|
||||||
//------------------------------------------
|
//------------------------------------------
|
||||||
@ -200,11 +199,26 @@ pub fn check(opts: &ThinCheckOptions) -> Result<()> {
|
|||||||
// superblock
|
// superblock
|
||||||
let sb = read_superblock(engine.as_ref(), SUPERBLOCK_LOCATION)?;
|
let sb = read_superblock(engine.as_ref(), SUPERBLOCK_LOCATION)?;
|
||||||
|
|
||||||
// device details
|
// Device details. We read this once to get the number of thin devices, and hence the
|
||||||
|
// maximum metadata ref count. Then create metadata space map, and reread to increment
|
||||||
|
// the ref counts for that metadata.
|
||||||
let devs = btree_to_map::<DeviceDetail>(engine.clone(), false, sb.details_root)?;
|
let devs = btree_to_map::<DeviceDetail>(engine.clone(), false, sb.details_root)?;
|
||||||
let nr_devs = devs.len();
|
let nr_devs = devs.len();
|
||||||
|
let metadata_sm = core_sm(engine.get_nr_blocks(), nr_devs as u32);
|
||||||
|
let _devs = btree_to_map_with_sm::<DeviceDetail>(
|
||||||
|
engine.clone(),
|
||||||
|
metadata_sm.clone(),
|
||||||
|
false,
|
||||||
|
sb.details_root,
|
||||||
|
)?;
|
||||||
println!("found {} devices", nr_devs);
|
println!("found {} devices", nr_devs);
|
||||||
|
|
||||||
|
// increment superblock
|
||||||
|
{
|
||||||
|
let mut sm = metadata_sm.lock().unwrap();
|
||||||
|
sm.inc(SUPERBLOCK_LOCATION, 1)?;
|
||||||
|
}
|
||||||
|
|
||||||
// mapping top level
|
// mapping top level
|
||||||
let roots = btree_to_map::<u64>(engine.clone(), false, sb.mapping_root)?;
|
let roots = btree_to_map::<u64>(engine.clone(), false, sb.mapping_root)?;
|
||||||
|
|
||||||
@ -214,15 +228,12 @@ pub fn check(opts: &ThinCheckOptions) -> Result<()> {
|
|||||||
// FIXME: with a thread pool we need to return errors another way.
|
// FIXME: with a thread pool we need to return errors another way.
|
||||||
let nr_workers = nr_threads;
|
let nr_workers = nr_threads;
|
||||||
let pool = ThreadPool::new(nr_workers);
|
let pool = ThreadPool::new(nr_workers);
|
||||||
let seen = Arc::new(Mutex::new(FixedBitSet::with_capacity(
|
|
||||||
engine.get_nr_blocks() as usize,
|
|
||||||
)));
|
|
||||||
|
|
||||||
let root = unpack::<SMRoot>(&sb.data_sm_root[0..])?;
|
let root = unpack::<SMRoot>(&sb.data_sm_root[0..])?;
|
||||||
data_sm = core_sm(root.nr_blocks, nr_devs as u32);
|
data_sm = core_sm(root.nr_blocks, nr_devs as u32);
|
||||||
|
|
||||||
for (thin_id, root) in roots {
|
for (thin_id, root) in roots {
|
||||||
let mut w = BTreeWalker::new_with_seen(engine.clone(), seen.clone(), false);
|
let mut w = BTreeWalker::new_with_sm(engine.clone(), metadata_sm.clone(), false)?;
|
||||||
let data_sm = data_sm.clone();
|
let data_sm = data_sm.clone();
|
||||||
pool.execute(move || {
|
pool.execute(move || {
|
||||||
let mut v = BottomLevelVisitor { data_sm };
|
let mut v = BottomLevelVisitor { data_sm };
|
||||||
@ -325,7 +336,6 @@ pub fn check(opts: &ThinCheckOptions) -> Result<()> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Check the metadata space map.
|
// Check the metadata space map.
|
||||||
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user