From 36767bcda6c59802e089d106a2cc17d941a95a3c Mon Sep 17 00:00:00 2001 From: Ming-Hung Tsai Date: Wed, 22 Sep 2021 16:58:04 +0800 Subject: [PATCH] [era_repair (rust)] First code drop --- src/commands/era_repair.rs | 73 ++++++++++++++++++++++++++++++++++++++ src/commands/mod.rs | 1 + src/era/mod.rs | 1 + src/era/repair.rs | 68 +++++++++++++++++++++++++++++++++++ 4 files changed, 143 insertions(+) create mode 100644 src/commands/era_repair.rs create mode 100644 src/era/repair.rs diff --git a/src/commands/era_repair.rs b/src/commands/era_repair.rs new file mode 100644 index 0000000..6f05764 --- /dev/null +++ b/src/commands/era_repair.rs @@ -0,0 +1,73 @@ +extern crate clap; + +use atty::Stream; +use clap::{App, Arg}; +use std::path::Path; +use std::process; +use std::sync::Arc; + +use crate::commands::utils::*; +use crate::era::repair::{repair, EraRepairOptions}; +use crate::report::*; + +pub fn run(args: &[std::ffi::OsString]) { + let parser = App::new("era_repair") + .version(crate::version::tools_version()) + .about("Repair binary era 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("FILE") + .required(true), + ) + .arg( + Arg::with_name("OUTPUT") + .help("Specify the output device") + .short("o") + .long("output") + .value_name("FILE") + .required(true), + ); + + let matches = parser.get_matches_from(args); + let input_file = Path::new(matches.value_of("INPUT").unwrap()); + let output_file = Path::new(matches.value_of("OUTPUT").unwrap()); + + let report = if matches.is_present("QUIET") { + std::sync::Arc::new(mk_quiet_report()) + } else if atty::is(Stream::Stdout) { + std::sync::Arc::new(mk_progress_bar_report()) + } else { + Arc::new(mk_simple_report()) + }; + + check_input_file(input_file, &report); + + let opts = EraRepairOptions { + input: input_file, + output: output_file, + async_io: matches.is_present("ASYNC_IO"), + report: report.clone(), + }; + + if let Err(reason) = repair(opts) { + report.fatal(&format!("{}", reason)); + process::exit(1); + } +} diff --git a/src/commands/mod.rs b/src/commands/mod.rs index 2abfeaa..c1d35e8 100644 --- a/src/commands/mod.rs +++ b/src/commands/mod.rs @@ -4,6 +4,7 @@ pub mod cache_repair; pub mod cache_restore; pub mod era_check; pub mod era_dump; +pub mod era_repair; pub mod era_restore; pub mod thin_check; pub mod thin_dump; diff --git a/src/era/mod.rs b/src/era/mod.rs index 9f6f3b4..da8383a 100644 --- a/src/era/mod.rs +++ b/src/era/mod.rs @@ -1,6 +1,7 @@ pub mod check; pub mod dump; pub mod ir; +pub mod repair; pub mod restore; pub mod superblock; pub mod writeset; diff --git a/src/era/repair.rs b/src/era/repair.rs new file mode 100644 index 0000000..2139a8e --- /dev/null +++ b/src/era/repair.rs @@ -0,0 +1,68 @@ +use anyhow::Result; +use std::path::Path; +use std::sync::Arc; + +use crate::era::dump::*; +use crate::era::restore::*; +use crate::era::superblock::*; +use crate::io_engine::*; +use crate::pdata::space_map_metadata::*; +use crate::report::*; +use crate::write_batcher::*; + +//------------------------------------------ + +pub struct EraRepairOptions<'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: &EraRepairOptions) -> Result { + let engine_in: Arc; + let engine_out: Arc; + + if opts.async_io { + engine_in = Arc::new(AsyncIoEngine::new(opts.input, MAX_CONCURRENT_IO, false)?); + 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, false)?); + 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: EraRepairOptions) -> Result<()> { + let ctx = new_context(&opts)?; + + let sb = read_superblock(ctx.engine_in.as_ref(), SUPERBLOCK_LOCATION)?; + + let sm = core_metadata_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) +} + +//------------------------------------------