[thin_metadata_size (rust)] First code drop

This commit is contained in:
Ming-Hung Tsai 2021-10-14 22:14:33 +08:00
parent 9ea75ba113
commit e5f0acd288
7 changed files with 230 additions and 0 deletions

View File

@ -48,6 +48,8 @@ fn main_() -> Result<()> {
thin_dump::run(&new_args);
} else if name_eq(name, "thin_metadata_pack") {
thin_metadata_pack::run(&new_args);
} else if name_eq(name, "thin_metadata_size") {
thin_metadata_size::run(&new_args);
} else if name_eq(name, "thin_metadata_unpack") {
thin_metadata_unpack::run(&new_args);
} else if name_eq(name, "thin_repair") {

View File

@ -11,6 +11,7 @@ pub mod era_restore;
pub mod thin_check;
pub mod thin_dump;
pub mod thin_metadata_pack;
pub mod thin_metadata_size;
pub mod thin_metadata_unpack;
pub mod thin_repair;
pub mod thin_restore;

View File

@ -0,0 +1,100 @@
extern crate clap;
use clap::{value_t_or_exit, App, Arg};
use std::ffi::OsString;
use std::process;
use crate::thin::metadata_size::{metadata_size, ThinMetadataSizeOptions};
use crate::units::*;
//------------------------------------------
fn parse_args<I, T>(args: I) -> (ThinMetadataSizeOptions, Units, bool)
where
I: IntoIterator<Item = T>,
T: Into<OsString> + Clone,
{
let parser = App::new("thin_metadata_size")
.version(crate::version::tools_version())
.about("Estimate the size of the metadata device needed for a given configuration.")
// options
.arg(
Arg::with_name("BLOCK_SIZE")
.help("Specify the data block size")
.short("b")
.long("block-size")
.required(true)
.value_name("SECTORS"),
)
.arg(
Arg::with_name("POOL_SIZE")
.help("Specify the size of pool device")
.short("s")
.long("pool-size")
.required(true)
.value_name("SECTORS"),
)
.arg(
Arg::with_name("MAX_THINS")
.help("Maximum number of thin devices and snapshots")
.short("m")
.long("max-thins")
.required(true)
.value_name("NUM"),
)
.arg(
Arg::with_name("UNIT")
.help("Specify the output unit")
.short("u")
.long("unit")
.value_name("UNIT")
.default_value("sector"),
)
.arg(
Arg::with_name("NUMERIC_ONLY")
.help("Output numeric value only")
.short("n")
.long("numeric-only"),
);
let matches = parser.get_matches_from(args);
// TODO: handle unit suffix
let pool_size = value_t_or_exit!(matches.value_of("POOL_SIZE"), u64);
let block_size = value_t_or_exit!(matches.value_of("BLOCK_SIZE"), u32);
let max_thins = value_t_or_exit!(matches.value_of("MAX_THINS"), u64);
let unit = value_t_or_exit!(matches.value_of("UNIT"), Units);
let numeric_only = matches.is_present("NUMERIC_ONLY");
(
ThinMetadataSizeOptions {
nr_blocks: pool_size / block_size as u64,
max_thins,
},
unit,
numeric_only,
)
}
pub fn run(args: &[std::ffi::OsString]) {
let (opts, unit, numeric_only) = parse_args(args);
match metadata_size(&opts) {
Ok(size) => {
let size = to_units(size * 512, unit.clone());
if numeric_only {
println!("{}", size);
} else {
let mut name = unit.to_string();
name.push('s');
println!("{} {}", size, name);
}
}
Err(reason) => {
eprintln!("{}", reason);
process::exit(1);
}
}
}
//------------------------------------------

View File

@ -27,6 +27,7 @@ pub mod pdata;
pub mod report;
pub mod shrink;
pub mod thin;
pub mod units;
pub mod version;
pub mod write_batcher;
pub mod xml;

21
src/thin/metadata_size.rs Normal file
View File

@ -0,0 +1,21 @@
use anyhow::Result;
use crate::math::div_up;
pub struct ThinMetadataSizeOptions {
pub nr_blocks: u64,
pub max_thins: u64,
}
pub fn metadata_size(opts: &ThinMetadataSizeOptions) -> Result<u64> {
const ENTRIES_PER_NODE: u64 = 126; // assumed the mapping leaves are half populated
const BLOCK_SIZE: u64 = 8; // sectors
// size of all the leaf nodes for data mappings
let mapping_size = div_up(opts.nr_blocks, ENTRIES_PER_NODE) * BLOCK_SIZE;
// space required by root nodes
let roots_overhead = opts.max_thins * BLOCK_SIZE;
Ok(mapping_size + roots_overhead)
}

View File

@ -5,6 +5,7 @@ pub mod dump;
pub mod ir;
pub mod metadata;
pub mod metadata_repair;
pub mod metadata_size;
pub mod repair;
pub mod restore;
pub mod runs;

104
src/units.rs Normal file
View File

@ -0,0 +1,104 @@
use anyhow::anyhow;
use std::str::FromStr;
//------------------------------------------
#[derive(Clone)]
pub enum Units {
Byte,
Sector,
Kilobyte,
Megabyte,
Gigabyte,
Terabyte,
Petabyte,
Exabyte,
Kibibyte,
Mebibyte,
Gibibyte,
Tebibyte,
Pebibyte,
Exbibyte,
}
impl Units {
fn size_bytes(&self) -> u64 {
match self {
Units::Byte => 1,
Units::Sector => 512,
// base 2
Units::Kibibyte => 1024,
Units::Mebibyte => 1048576,
Units::Gibibyte => 1073741824,
Units::Tebibyte => 1099511627776,
Units::Pebibyte => 1125899906842624,
Units::Exbibyte => 1152921504606846976,
// base 10
Units::Kilobyte => 1000,
Units::Megabyte => 1000000,
Units::Gigabyte => 1000000000,
Units::Terabyte => 1000000000000,
Units::Petabyte => 1000000000000000,
Units::Exabyte => 1000000000000000000,
}
}
}
impl FromStr for Units {
type Err = anyhow::Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"byte" | "b" => Ok(Units::Byte),
"sector" | "s" => Ok(Units::Sector),
// base 2
"kibibyte" | "k" => Ok(Units::Kibibyte),
"mibibyte" | "m" => Ok(Units::Mebibyte),
"gibibyte" | "g" => Ok(Units::Gibibyte),
"tebibyte" | "t" => Ok(Units::Tebibyte),
"pebibyte" | "p" => Ok(Units::Pebibyte),
"exbibyte" | "e" => Ok(Units::Exbibyte),
// base 10
"kilobyte" | "K" => Ok(Units::Kilobyte),
"megabyte" | "M" => Ok(Units::Megabyte),
"gigabyte" | "G" => Ok(Units::Gigabyte),
"terabyte" | "T" => Ok(Units::Terabyte),
"petabyte" | "P" => Ok(Units::Petabyte),
"exabyte" | "E" => Ok(Units::Exabyte),
_ => Err(anyhow!("Invalid unit specifier")),
}
}
}
impl ToString for Units {
fn to_string(&self) -> String {
String::from(match self {
Units::Byte => "byte",
Units::Sector => "sector",
// base 2
Units::Kibibyte => "kibibyte",
Units::Mebibyte => "mibibyte",
Units::Gibibyte => "gibibyte",
Units::Tebibyte => "terabyte",
Units::Pebibyte => "pebibyte",
Units::Exbibyte => "exbibyte",
// base 10
Units::Kilobyte => "kilobyte",
Units::Megabyte => "megabyte",
Units::Gigabyte => "gigabyte",
Units::Terabyte => "terabyte",
Units::Petabyte => "petabyte",
Units::Exabyte => "exabyte",
})
}
}
pub fn to_bytes(size: u64, unit: Units) -> u64 {
size * unit.size_bytes()
}
pub fn to_units(bytes: u64, unit: Units) -> f64 {
bytes as f64 / unit.size_bytes() as f64
}
//------------------------------------------