From 7239204b0149a2d3d0beedad4cf2f932d5d5ffb4 Mon Sep 17 00:00:00 2001 From: Ming-Hung Tsai Date: Mon, 19 Jul 2021 11:43:03 +0800 Subject: [PATCH] [cache_repair (rust)] First pass at cache_repair --- src/bin/cache_repair.rs | 79 +++++++++++++++++++++++++++++++++++++++++ src/cache/mod.rs | 1 + src/cache/repair.rs | 68 +++++++++++++++++++++++++++++++++++ 3 files changed, 148 insertions(+) create mode 100644 src/bin/cache_repair.rs create mode 100644 src/cache/repair.rs diff --git a/src/bin/cache_repair.rs b/src/bin/cache_repair.rs new file mode 100644 index 0000000..d964a0f --- /dev/null +++ b/src/bin/cache_repair.rs @@ -0,0 +1,79 @@ +extern crate clap; +extern crate thinp; + +use atty::Stream; +use clap::{App, Arg}; +use std::path::Path; +use std::process; +use std::process::exit; +use std::sync::Arc; +use thinp::cache::repair::{repair, CacheRepairOptions}; +use thinp::file_utils; +use thinp::report::*; + +fn main() { + let parser = App::new("cache_repair") + .version(thinp::version::tools_version()) + .about("Repair binary cache metadata, and write it to a different device or file") + // flags + .arg( + Arg::with_name("ASYNC_IO") + .help("Force use of io_uring for synchronous io") + .long("async-io") + .hidden(true), + ) + .arg( + Arg::with_name("QUIET") + .help("Suppress output messages, return only exit code.") + .short("q") + .long("quiet"), + ) + // options + .arg( + Arg::with_name("INPUT") + .help("Specify the input device") + .short("i") + .long("input") + .value_name("INPUT") + .required(true), + ) + .arg( + Arg::with_name("OUTPUT") + .help("Specify the output device") + .short("o") + .long("output") + .value_name("OUTPUT") + .required(true), + ); + + let matches = parser.get_matches(); + let input_file = Path::new(matches.value_of("INPUT").unwrap()); + let output_file = Path::new(matches.value_of("OUTPUT").unwrap()); + + if !file_utils::file_exists(input_file) { + eprintln!("Couldn't find input file '{:?}'.", &input_file); + exit(1); + } + + let report; + + if matches.is_present("QUIET") { + report = std::sync::Arc::new(mk_quiet_report()); + } else if atty::is(Stream::Stdout) { + report = std::sync::Arc::new(mk_progress_bar_report()); + } else { + report = Arc::new(mk_simple_report()); + } + + let opts = CacheRepairOptions { + input: &input_file, + output: &output_file, + async_io: matches.is_present("ASYNC_IO"), + report, + }; + + if let Err(reason) = repair(opts) { + eprintln!("{}", reason); + process::exit(1); + } +} diff --git a/src/cache/mod.rs b/src/cache/mod.rs index c01cc6c..4a90694 100644 --- a/src/cache/mod.rs +++ b/src/cache/mod.rs @@ -3,6 +3,7 @@ pub mod dump; pub mod hint; pub mod ir; pub mod mapping; +pub mod repair; pub mod restore; pub mod superblock; pub mod xml; diff --git a/src/cache/repair.rs b/src/cache/repair.rs new file mode 100644 index 0000000..dd88a26 --- /dev/null +++ b/src/cache/repair.rs @@ -0,0 +1,68 @@ +use anyhow::Result; +use std::path::Path; +use std::sync::Arc; + +use crate::cache::dump::*; +use crate::cache::restore::*; +use crate::cache::superblock::*; +use crate::io_engine::*; +use crate::pdata::space_map::*; +use crate::report::*; +use crate::write_batcher::*; + +//------------------------------------------ + +pub struct CacheRepairOptions<'a> { + pub input: &'a Path, + pub output: &'a Path, + pub async_io: bool, + pub report: Arc, +} + +struct Context { + _report: Arc, + engine_in: Arc, + engine_out: Arc, +} + +const MAX_CONCURRENT_IO: u32 = 1024; + +fn new_context(opts: &CacheRepairOptions) -> Result { + let engine_in: Arc; + let engine_out: Arc; + + if opts.async_io { + engine_in = Arc::new(AsyncIoEngine::new(opts.input, MAX_CONCURRENT_IO, true)?); + engine_out = Arc::new(AsyncIoEngine::new(opts.output, MAX_CONCURRENT_IO, true)?); + } else { + let nr_threads = std::cmp::max(8, num_cpus::get() * 2); + engine_in = Arc::new(SyncIoEngine::new(opts.input, nr_threads, true)?); + engine_out = Arc::new(SyncIoEngine::new(opts.output, nr_threads, true)?); + } + + Ok(Context { + _report: opts.report.clone(), + engine_in, + engine_out, + }) +} + +//------------------------------------------ + +pub fn repair(opts: CacheRepairOptions) -> Result<()> { + let ctx = new_context(&opts)?; + + let sb = read_superblock(ctx.engine_in.as_ref(), SUPERBLOCK_LOCATION)?; + + let sm = core_sm(ctx.engine_out.get_nr_blocks(), u32::MAX); + let mut w = WriteBatcher::new( + ctx.engine_out.clone(), + sm.clone(), + ctx.engine_out.get_batch_size(), + ); + let mut restorer = Restorer::new(&mut w); + + dump_metadata(ctx.engine_in, &mut restorer, &sb, true) +} + +//------------------------------------------