From 34f6b6fc62ac3bf2a260d923eeac83c9b83c4a7d Mon Sep 17 00:00:00 2001 From: Ming-Hung Tsai Date: Fri, 8 Oct 2021 22:02:57 +0800 Subject: [PATCH] [cache_metadata_size (rust)] First code drop --- src/bin/pdata_tools.rs | 2 + src/cache/metadata_size.rs | 19 +++++++ src/cache/mod.rs | 1 + src/commands/cache_metadata_size.rs | 88 +++++++++++++++++++++++++++++ src/commands/mod.rs | 1 + 5 files changed, 111 insertions(+) create mode 100644 src/cache/metadata_size.rs create mode 100644 src/commands/cache_metadata_size.rs diff --git a/src/bin/pdata_tools.rs b/src/bin/pdata_tools.rs index c2ababc..b3e0676 100644 --- a/src/bin/pdata_tools.rs +++ b/src/bin/pdata_tools.rs @@ -30,6 +30,8 @@ fn main_() -> Result<()> { cache_check::run(&new_args); } else if name_eq(name, "cache_dump") { cache_dump::run(&new_args); + } else if name_eq(name, "cache_metadata_size") { + cache_metadata_size::run(&new_args); } else if name_eq(name, "cache_repair") { cache_repair::run(&new_args); } else if name_eq(name, "cache_restore") { diff --git a/src/cache/metadata_size.rs b/src/cache/metadata_size.rs new file mode 100644 index 0000000..bedea4f --- /dev/null +++ b/src/cache/metadata_size.rs @@ -0,0 +1,19 @@ +use anyhow::Result; + +pub struct CacheMetadataSizeOptions { + pub nr_blocks: u64, + pub max_hint_width: u32, // bytes +} + +pub fn metadata_size(opts: &CacheMetadataSizeOptions) -> Result { + const SECTOR_SHIFT: u64 = 9; // 512 bytes per sector + const BYTES_PER_BLOCK_SHIFT: u64 = 4; // 16 bytes for key and value + const TRANSACTION_OVERHEAD: u64 = 8192; // in sectors; 4 MB + const HINT_OVERHEAD_PER_BLOCK: u64 = 8; // 8 bytes for the key + + let mapping_size = (opts.nr_blocks << BYTES_PER_BLOCK_SHIFT) >> SECTOR_SHIFT; + let hint_size = + (opts.nr_blocks * (opts.max_hint_width as u64 + HINT_OVERHEAD_PER_BLOCK)) >> SECTOR_SHIFT; + + Ok(TRANSACTION_OVERHEAD + mapping_size + hint_size) +} diff --git a/src/cache/mod.rs b/src/cache/mod.rs index 4a90694..7f9075e 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 metadata_size; pub mod repair; pub mod restore; pub mod superblock; diff --git a/src/commands/cache_metadata_size.rs b/src/commands/cache_metadata_size.rs new file mode 100644 index 0000000..047d08c --- /dev/null +++ b/src/commands/cache_metadata_size.rs @@ -0,0 +1,88 @@ +extern crate clap; + +use clap::{value_t_or_exit, App, Arg, ArgGroup}; +use std::ffi::OsString; +use std::process; + +use crate::cache::metadata_size::{metadata_size, CacheMetadataSizeOptions}; +use crate::math::div_up; + +//------------------------------------------ + +fn parse_args(args: I) -> CacheMetadataSizeOptions +where + I: IntoIterator, + T: Into + Clone, +{ + let parser = App::new("cache_metadata_size") + .version(crate::version::tools_version()) + .about("Estimate the size of the metadata device needed for a given configuration.") + .usage("cache_metadata_size [OPTIONS] <--device-size --block-size | --nr-blocks >") + // options + .arg( + Arg::with_name("BLOCK_SIZE") + .help("Specify the size of each cache block") + .long("block-size") + .requires("DEVICE_SIZE") + .value_name("SECTORS"), + ) + .arg( + Arg::with_name("DEVICE_SIZE") + .help("Specify total size of the fast device used in the cache") + .long("device-size") + .requires("BLOCK_SIZE") + .value_name("SECTORS"), + ) + .arg( + Arg::with_name("NR_BLOCKS") + .help("Specify the number of cache blocks") + .long("nr-blocks") + .value_name("NUM"), + ) + .arg( + Arg::with_name("MAX_HINT_WIDTH") + .help("Specity the per-block hint width") + .long("max-hint-width") + .value_name("BYTES") + .default_value("4"), + ) + .group( + ArgGroup::with_name("selection") + .args(&["DEVICE_SIZE", "NR_BLOCKS"]) + .required(true) + ); + + let matches = parser.get_matches_from(args); + + let nr_blocks = matches.value_of("NR_BLOCKS").map_or_else( + || { + let device_size = value_t_or_exit!(matches.value_of("DEVICE_SIZE"), u64); + let block_size = value_t_or_exit!(matches.value_of("BLOCK_SIZE"), u32); + div_up(device_size, block_size as u64) + }, + |_| value_t_or_exit!(matches.value_of("NR_BLOCKS"), u64), + ); + + let max_hint_width = value_t_or_exit!(matches.value_of("MAX_HINT_WIDTH"), u32); + + CacheMetadataSizeOptions { + nr_blocks, + max_hint_width, + } +} + +pub fn run(args: &[std::ffi::OsString]) { + let opts = parse_args(args); + + match metadata_size(&opts) { + Ok(size) => { + println!("{} sectors", size); + } + Err(reason) => { + eprintln!("{}", reason); + process::exit(1); + } + } +} + +//------------------------------------------ diff --git a/src/commands/mod.rs b/src/commands/mod.rs index 5dd1f19..34377a6 100644 --- a/src/commands/mod.rs +++ b/src/commands/mod.rs @@ -1,5 +1,6 @@ pub mod cache_check; pub mod cache_dump; +pub mod cache_metadata_size; pub mod cache_repair; pub mod cache_restore; pub mod era_check;