[thin_check (rust)] Send all reporting through the Spinner.

This means the spinner doesn't overwrite messages.
This commit is contained in:
Joe Thornber 2020-08-12 09:35:21 +01:00
parent 3757e1d947
commit 544335ae4a

View File

@ -180,6 +180,7 @@ impl<'a> NodeVisitor<u32> for OverflowChecker<'a> {
//------------------------------------------ //------------------------------------------
enum SpinnerCmd { enum SpinnerCmd {
Log(String),
Complete, Complete,
Abort, Abort,
Title(String), Title(String),
@ -197,6 +198,11 @@ impl Spinner {
Ok(Spinner { tx, tid }) Ok(Spinner { tx, tid })
} }
fn log<I: Into<String>>(&mut self, txt: I) -> Result<()> {
self.tx.send(SpinnerCmd::Log(txt.into()))?;
Ok(())
}
fn complete(self) -> Result<()> { fn complete(self) -> Result<()> {
self.tx.send(SpinnerCmd::Complete)?; self.tx.send(SpinnerCmd::Complete)?;
self.tid.join(); self.tid.join();
@ -223,27 +229,34 @@ fn spinner_thread(
let interval = time::Duration::from_millis(250); let interval = time::Duration::from_millis(250);
let bar = ProgressBar::new(total_allocated); let bar = ProgressBar::new(total_allocated);
loop { loop {
match rx.try_recv() { loop {
Ok(SpinnerCmd::Complete) => { match rx.try_recv() {
bar.finish(); Ok(SpinnerCmd::Log(txt)) => {
return; bar.println(txt);
}
Ok(SpinnerCmd::Complete) => {
bar.finish();
return;
}
Ok(SpinnerCmd::Abort) => {
return;
}
Ok(SpinnerCmd::Title(txt)) => {
let mut fmt = "Checking thin metadata [{bar:40}] Remaining {eta}, ".to_string();
fmt.push_str(&txt);
bar.set_style(
ProgressStyle::default_bar()
.template(&fmt)
.progress_chars("=> "),
);
}
Err(TryRecvError::Disconnected) => {
return;
}
Err(TryRecvError::Empty) => {
break;
}
} }
Ok(SpinnerCmd::Abort) => {
return;
}
Ok(SpinnerCmd::Title(txt)) => {
let mut fmt = "Checking thin metadata [{bar:40}] Remaining {eta}, ".to_string();
fmt.push_str(&txt);
bar.set_style(
ProgressStyle::default_bar()
.template(&fmt)
.progress_chars("=> "),
);
}
Err(TryRecvError::Disconnected) => {
return;
}
Err(TryRecvError::Empty) => {}
} }
let sm = sm.lock().unwrap(); let sm = sm.lock().unwrap();
@ -260,8 +273,11 @@ fn spinner_thread(
//------------------------------------------ //------------------------------------------
fn check_space_map( fn check_space_map(
kind: &str,
engine: Arc<dyn IoEngine + Send + Sync>, engine: Arc<dyn IoEngine + Send + Sync>,
bar: &mut Spinner,
entries: Vec<IndexEntry>, entries: Vec<IndexEntry>,
metadata_sm: Option<Arc<Mutex<dyn SpaceMap + Send + Sync>>>,
sm: Arc<Mutex<dyn SpaceMap + Send + Sync>>, sm: Arc<Mutex<dyn SpaceMap + Send + Sync>>,
root: SMRoot, root: SMRoot,
) -> Result<()> { ) -> Result<()> {
@ -270,7 +286,12 @@ fn check_space_map(
// overflow btree // overflow btree
{ {
let mut v = OverflowChecker::new(&*sm); let mut v = OverflowChecker::new(&*sm);
let mut w = BTreeWalker::new(engine.clone(), false); let mut w;
if metadata_sm.is_none() {
w = BTreeWalker::new(engine.clone(), false);
} else {
w = BTreeWalker::new_with_sm(engine.clone(), metadata_sm.unwrap().clone(), false)?;
}
w.walk(&mut v, root.ref_count_root)?; w.walk(&mut v, root.ref_count_root)?;
} }
@ -304,19 +325,18 @@ fn check_space_map(
BitmapEntry::Small(actual) => { BitmapEntry::Small(actual) => {
let expected = sm.get(blocknr)?; let expected = sm.get(blocknr)?;
if actual == 1 && expected == 0 { if actual == 1 && expected == 0 {
// eprintln!("Data block {} leaked.", blocknr);
leaks += 1; leaks += 1;
} else if actual != expected as u8 { } else if actual != expected as u8 {
eprintln!("Bad reference count for data block {}. Expected {}, but space map contains {}.", bar.log(format!("Bad reference count for {} block {}. Expected {}, but space map contains {}.",
blocknr, expected, actual); kind, blocknr, expected, actual))?;
fail = true; fail = true;
} }
} }
BitmapEntry::Overflow => { BitmapEntry::Overflow => {
let expected = sm.get(blocknr)?; let expected = sm.get(blocknr)?;
if expected < 3 { if expected < 3 {
eprintln!("Bad reference count for data block {}. Expected {}, but space map says it's >= 3.", bar.log(format!("Bad reference count for {} block {}. Expected {}, but space map says it's >= 3.",
blocknr, expected); kind, blocknr, expected))?;
fail = true; fail = true;
} }
} }
@ -326,10 +346,10 @@ fn check_space_map(
} }
if leaks > 0 { if leaks > 0 {
eprintln!( bar.log(format!(
"{} data blocks have leaked. Use --auto-repair to fix.", "{} {} blocks have leaked. Use --auto-repair to fix.",
leaks leaks, kind
); ))?;
} }
if fail { if fail {
@ -340,6 +360,16 @@ fn check_space_map(
//------------------------------------------ //------------------------------------------
fn inc_entries(sm: &Arc<Mutex<dyn SpaceMap + Sync + Send>>, entries: &[IndexEntry]) -> Result<()> {
let mut sm = sm.lock().unwrap();
for ie in entries {
sm.inc(ie.blocknr, 1)?;
}
Ok(())
}
//------------------------------------------
const MAX_CONCURRENT_IO: u32 = 1024; const MAX_CONCURRENT_IO: u32 = 1024;
pub struct ThinCheckOptions<'a> { pub struct ThinCheckOptions<'a> {
@ -355,7 +385,6 @@ pub fn check(opts: &ThinCheckOptions) -> Result<()> {
nr_threads = std::cmp::min(4, num_cpus::get()); nr_threads = std::cmp::min(4, num_cpus::get());
engine = Arc::new(AsyncIoEngine::new(opts.dev, MAX_CONCURRENT_IO)?); engine = Arc::new(AsyncIoEngine::new(opts.dev, MAX_CONCURRENT_IO)?);
} else { } else {
eprintln!("Using synchronous io");
nr_threads = num_cpus::get() * 2; nr_threads = num_cpus::get() * 2;
engine = Arc::new(SyncIoEngine::new(opts.dev, nr_threads)?); engine = Arc::new(SyncIoEngine::new(opts.dev, nr_threads)?);
} }
@ -429,9 +458,25 @@ pub fn check(opts: &ThinCheckOptions) -> Result<()> {
spinner.set_title("data space map")?; spinner.set_title("data space map")?;
let root = unpack::<SMRoot>(&sb.data_sm_root[0..])?; let root = unpack::<SMRoot>(&sb.data_sm_root[0..])?;
let entries = btree_to_map::<IndexEntry>(engine.clone(), false, root.bitmap_root)?;
let entries = btree_to_map_with_sm::<IndexEntry>(
engine.clone(),
metadata_sm.clone(),
false,
root.bitmap_root,
)?;
let entries: Vec<IndexEntry> = entries.values().cloned().collect(); let entries: Vec<IndexEntry> = entries.values().cloned().collect();
check_space_map(engine.clone(), entries, data_sm.clone(), root)?; inc_entries(&metadata_sm, &entries[0..])?;
check_space_map(
"data",
engine.clone(),
&mut spinner,
entries,
Some(metadata_sm.clone()),
data_sm.clone(),
root,
)?;
spinner.set_title("metadata space map")?; spinner.set_title("metadata space map")?;
let root = unpack::<SMRoot>(&sb.metadata_sm_root[0..])?; let root = unpack::<SMRoot>(&sb.metadata_sm_root[0..])?;
@ -445,22 +490,25 @@ pub fn check(opts: &ThinCheckOptions) -> Result<()> {
.take_while(|e| e.blocknr != 0) .take_while(|e| e.blocknr != 0)
.cloned() .cloned()
.collect(); .collect();
inc_entries(&metadata_sm, &entries[0..])?;
// We need to increment the ref counts for all the bitmaps, then walk the overflow
// tree to inc the ref counts for those.
{
let mut sm = metadata_sm.lock().unwrap();
for ie in &entries {
sm.inc(ie.blocknr, 1)?;
}
}
let _counts = btree_to_map_with_sm::<u32>( let _counts = btree_to_map_with_sm::<u32>(
engine.clone(), engine.clone(),
metadata_sm.clone(), metadata_sm.clone(),
false, false,
root.ref_count_root, root.ref_count_root,
)?; )?;
check_space_map(engine.clone(), entries, metadata_sm.clone(), root)?;
// Now the counts should be correct and we can check it.
check_space_map(
"metadata",
engine.clone(),
&mut spinner,
entries,
None,
metadata_sm.clone(),
root,
)?;
spinner.complete()?; spinner.complete()?;
Ok(()) Ok(())