[thin_metadata_size (rust)] First code drop
This commit is contained in:
parent
9ea75ba113
commit
e5f0acd288
@ -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") {
|
||||
|
@ -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;
|
||||
|
100
src/commands/thin_metadata_size.rs
Normal file
100
src/commands/thin_metadata_size.rs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------
|
@ -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
21
src/thin/metadata_size.rs
Normal 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)
|
||||
}
|
@ -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
104
src/units.rs
Normal 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
|
||||
}
|
||||
|
||||
//------------------------------------------
|
Loading…
Reference in New Issue
Block a user