[thin_metadata_size (rust)] First code drop
This commit is contained in:
@ -48,6 +48,8 @@ fn main_() -> Result<()> {
|
|||||||
thin_dump::run(&new_args);
|
thin_dump::run(&new_args);
|
||||||
} else if name_eq(name, "thin_metadata_pack") {
|
} else if name_eq(name, "thin_metadata_pack") {
|
||||||
thin_metadata_pack::run(&new_args);
|
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") {
|
} else if name_eq(name, "thin_metadata_unpack") {
|
||||||
thin_metadata_unpack::run(&new_args);
|
thin_metadata_unpack::run(&new_args);
|
||||||
} else if name_eq(name, "thin_repair") {
|
} else if name_eq(name, "thin_repair") {
|
||||||
|
@ -11,6 +11,7 @@ pub mod era_restore;
|
|||||||
pub mod thin_check;
|
pub mod thin_check;
|
||||||
pub mod thin_dump;
|
pub mod thin_dump;
|
||||||
pub mod thin_metadata_pack;
|
pub mod thin_metadata_pack;
|
||||||
|
pub mod thin_metadata_size;
|
||||||
pub mod thin_metadata_unpack;
|
pub mod thin_metadata_unpack;
|
||||||
pub mod thin_repair;
|
pub mod thin_repair;
|
||||||
pub mod thin_restore;
|
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 report;
|
||||||
pub mod shrink;
|
pub mod shrink;
|
||||||
pub mod thin;
|
pub mod thin;
|
||||||
|
pub mod units;
|
||||||
pub mod version;
|
pub mod version;
|
||||||
pub mod write_batcher;
|
pub mod write_batcher;
|
||||||
pub mod xml;
|
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 ir;
|
||||||
pub mod metadata;
|
pub mod metadata;
|
||||||
pub mod metadata_repair;
|
pub mod metadata_repair;
|
||||||
|
pub mod metadata_size;
|
||||||
pub mod repair;
|
pub mod repair;
|
||||||
pub mod restore;
|
pub mod restore;
|
||||||
pub mod runs;
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------
|
Reference in New Issue
Block a user