From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from firstgate.proxmox.com (firstgate.proxmox.com [212.224.123.68]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits)) (No client certificate requested) by lists.proxmox.com (Postfix) with ESMTPS id BEFB68048A for ; Wed, 17 Nov 2021 14:37:55 +0100 (CET) Received: from firstgate.proxmox.com (localhost [127.0.0.1]) by firstgate.proxmox.com (Proxmox) with ESMTP id B56B7D5D5 for ; Wed, 17 Nov 2021 14:37:25 +0100 (CET) Received: from proxmox-new.maurer-it.com (proxmox-new.maurer-it.com [94.136.29.106]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits)) (No client certificate requested) by firstgate.proxmox.com (Proxmox) with ESMTPS id 1D317D5C5 for ; Wed, 17 Nov 2021 14:37:24 +0100 (CET) Received: from proxmox-new.maurer-it.com (localhost.localdomain [127.0.0.1]) by proxmox-new.maurer-it.com (Proxmox) with ESMTP id C003543DC1; Wed, 17 Nov 2021 14:37:23 +0100 (CET) From: Dietmar Maurer To: pbs-devel@lists.proxmox.com Date: Wed, 17 Nov 2021 14:37:20 +0100 Message-Id: <20211117133720.1799124-5-dietmar@proxmox.com> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20211117133720.1799124-1-dietmar@proxmox.com> References: <20211117133720.1799124-1-dietmar@proxmox.com> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-SPAM-LEVEL: Spam detection results: 0 AWL 0.491 Adjusted score from AWL reputation of From: address BAYES_00 -1.9 Bayes spam probability is 0 to 1% KAM_DMARC_STATUS 0.01 Test Rule for DKIM or SPF Failure with Strict Alignment SPF_HELO_NONE 0.001 SPF: HELO does not publish an SPF Record SPF_PASS -0.001 SPF: sender matches SPF record Subject: [pbs-devel] [RFC proxmox-backup v2 4/4] HumanByte: do not store unit (always compute canonical form) X-BeenThere: pbs-devel@lists.proxmox.com X-Mailman-Version: 2.1.29 Precedence: list List-Id: Proxmox Backup Server development discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 17 Nov 2021 13:37:55 -0000 --- pbs-api-types/src/human_byte.rs | 161 ++++++++++++++------------------ src/cached_traffic_control.rs | 16 ++-- 2 files changed, 80 insertions(+), 97 deletions(-) diff --git a/pbs-api-types/src/human_byte.rs b/pbs-api-types/src/human_byte.rs index 4d8c4f21..f233c9fb 100644 --- a/pbs-api-types/src/human_byte.rs +++ b/pbs-api-types/src/human_byte.rs @@ -8,15 +8,10 @@ use proxmox_schema::{ApiStringFormat, ApiType, StringSchema, Schema, UpdaterType pub enum SizeUnit { None, Byte, - Kilo, KByte, - Mega, MByte, - Giga, GByte, - Tera, TByte, - Peta, PByte, Kibi, Mebi, @@ -31,11 +26,11 @@ impl SizeUnit { SizeUnit::None => 1, SizeUnit::Byte => 1, - SizeUnit::Kilo | SizeUnit::KByte => 1_000, - SizeUnit::Mega | SizeUnit::MByte => 1_000_000, - SizeUnit::Giga | SizeUnit::GByte => 1_000_000_000, - SizeUnit::Tera | SizeUnit::TByte => 1_000_000_000_000, - SizeUnit::Peta | SizeUnit::PByte => 1_000_000_000_000_000, + SizeUnit::KByte => 1_000, + SizeUnit::MByte => 1_000_000, + SizeUnit::GByte => 1_000_000_000, + SizeUnit::TByte => 1_000_000_000_000, + SizeUnit::PByte => 1_000_000_000_000_000, SizeUnit::Kibi => 1024, SizeUnit::Mebi => 1024*1024, @@ -50,12 +45,6 @@ impl SizeUnit { SizeUnit::None => "", SizeUnit::Byte => "B", - SizeUnit::Kilo => "K", - SizeUnit::Mega => "M", - SizeUnit::Giga => "G", - SizeUnit::Tera => "T", - SizeUnit::Peta => "P", - SizeUnit::KByte => "KB", SizeUnit::MByte => "MB", SizeUnit::GByte => "GB", @@ -74,19 +63,19 @@ impl SizeUnit { fn strip_unit(v: &str) -> (&str, SizeUnit) { if let Some(v) = v.strip_suffix(&['k', 'K'][..]) { - return (v, SizeUnit::Kilo); + return (v, SizeUnit::KByte); } if let Some(v) = v.strip_suffix(&['m', 'M'][..]) { - return (v, SizeUnit::Mega); + return (v, SizeUnit::MByte); } if let Some(v) = v.strip_suffix(&['g', 'G'][..]) { - return (v, SizeUnit::Giga); + return (v, SizeUnit::GByte); } if let Some(v) = v.strip_suffix(&['t', 'T'][..]) { - return (v, SizeUnit::Tera); + return (v, SizeUnit::TByte); } if let Some(v) = v.strip_suffix(&['p', 'P'][..]) { - return (v, SizeUnit::Peta); + return (v, SizeUnit::PByte); } if let Some(mut v) = v.strip_suffix(&['b', 'B'][..]) { @@ -122,8 +111,8 @@ fn strip_unit(v: &str) -> (&str, SizeUnit) { #[derive(Debug, Copy, Clone, UpdaterType)] /// Byte size with unit pub struct HumanByte { - size: u64, - unit: SizeUnit, + pub size: u64, + binary: bool, } fn verify_human_byte(s: &str) -> Result<(), Error> { @@ -144,64 +133,54 @@ impl ApiType for HumanByte { impl HumanByte { pub fn new_decimal(size: u64) -> Self { - let this = HumanByte { size: size, unit: SizeUnit::None }; - this.auto_unit_decimal() + HumanByte { size: size, binary: false } } pub fn new_binary(size: u64) -> Self { - let this = HumanByte { size: size, unit: SizeUnit::None }; - this.auto_unit_binary() - } - - pub fn as_u64(&self) -> u64 { - self.size as u64 + HumanByte { size: size, binary: true } } - pub fn auto_unit_binary(mut self) -> Self { - let size = self.size as u64; - let zeroes = size.leading_zeros(); - let bits = 63 - zeroes; - self.unit = if bits >= 50 { - SizeUnit::Pebi - } else if bits >= 40 { - SizeUnit::Tebi - } else if bits >= 30 { - SizeUnit::Gibi - } else if bits >= 20 { - SizeUnit::Mebi - } else if bits >= 10 { - SizeUnit::Kibi - } else { - SizeUnit::None - }; - self - } - - pub fn auto_unit_decimal(mut self) -> Self { - self.unit = if self.size >= 1_000_000_000_000_000 { - SizeUnit::PByte - } else if self.size >= 1_000_000_000_000 { - SizeUnit::TByte - } else if self.size >= 1_000_000_000 { - SizeUnit::GByte - } else if self.size >= 1_000_000 { - SizeUnit::MByte - } else if self.size >= 1_000 { - SizeUnit::KByte + fn auto_unit(&self) -> SizeUnit { + if self.binary { + let zeroes = self.size.leading_zeros(); + let bits = 63 - zeroes; + if bits >= 50 { + SizeUnit::Pebi + } else if bits >= 40 { + SizeUnit::Tebi + } else if bits >= 30 { + SizeUnit::Gibi + } else if bits >= 20 { + SizeUnit::Mebi + } else if bits >= 10 { + SizeUnit::Kibi + } else { + SizeUnit::None + } } else { - SizeUnit::None - }; - self + if self.size >= 1_000_000_000_000_000 { + SizeUnit::PByte + } else if self.size >= 1_000_000_000_000 { + SizeUnit::TByte + } else if self.size >= 1_000_000_000 { + SizeUnit::GByte + } else if self.size >= 1_000_000 { + SizeUnit::MByte + } else if self.size >= 1_000 { + SizeUnit::KByte + } else { + SizeUnit::None + } + } } } impl std::fmt::Display for HumanByte { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - let size = self.size; - let unit = self.unit; + let unit = self.auto_unit(); - let size = (size as f64)/(unit.factor() as f64); + let size = (self.size as f64)/(unit.factor() as f64); let unit_str = unit.unit_str(); if unit == SizeUnit::Byte || unit == SizeUnit::None { @@ -239,9 +218,16 @@ impl FromStr for HumanByte { let size = (size*(unit.factor() as f64)) as u64; - Ok(Self { size, unit }) - } + let binary = match unit { + SizeUnit::Kibi | SizeUnit::Mebi | SizeUnit::Gibi | + SizeUnit::Tebi | SizeUnit::Pebi => true, + SizeUnit::None | SizeUnit::Byte | SizeUnit::KByte | + SizeUnit::MByte | SizeUnit::GByte | SizeUnit::TByte | + SizeUnit::PByte => false, + }; + Ok(Self { size, binary}) + } } proxmox::forward_deserialize_to_from_str!(HumanByte); @@ -252,15 +238,12 @@ fn test_human_byte_parser() -> Result<(), Error> { assert!("-10".parse::().is_err()); // negative size - fn test(v: &str, size: u64, unit: SizeUnit, as_str: &str) -> Result<(), Error> { + fn test(v: &str, size: u64, as_str: &str) -> Result<(), Error> { let h: HumanByte = v.parse()?; if h.size != size { bail!("got unexpected size for '{}' ({} != {})", v, h.size, size); } - if h.unit != unit { - bail!("got unexpected unit for '{}' ({:?} != {:?})", v, h.unit, unit); - } let new = h.to_string(); if &new != as_str { @@ -271,29 +254,29 @@ fn test_human_byte_parser() -> Result<(), Error> { Ok(()) } - test("14.4", 14, SizeUnit::None, "14")?; + test("14.4", 14, "14")?; - test("14", 14, SizeUnit::None, "14")?; - test("987654321", 987654321, SizeUnit::None, "987654321")?; + test("14", 14, "14")?; + test("987654321", 987654321, "987.654 MB")?; - test("1300b", 1300, SizeUnit::Byte, "1300 B")?; - test("1300B", 1300, SizeUnit::Byte, "1300 B")?; + test("1300b", 1300, "1.3 KB")?; + test("1300B", 1300, "1.3 KB")?; - test("1.5KB", 1500, SizeUnit::KByte, "1.5 KB")?; - test("1.5kb", 1500, SizeUnit::KByte, "1.5 KB")?; - test("1.654321MB", 1_654_321, SizeUnit::MByte, "1.654 MB")?; + test("1.5KB", 1500, "1.5 KB")?; + test("1.5kb", 1500, "1.5 KB")?; + test("1.654321MB", 1_654_321, "1.654 MB")?; - test("2.0GB", 2_000_000_000, SizeUnit::GByte, "2 GB")?; + test("2.0GB", 2_000_000_000, "2 GB")?; - test("1.4TB", 1_400_000_000_000, SizeUnit::TByte, "1.4 TB")?; - test("1.4tb", 1_400_000_000_000, SizeUnit::TByte, "1.4 TB")?; + test("1.4TB", 1_400_000_000_000, "1.4 TB")?; + test("1.4tb", 1_400_000_000_000, "1.4 TB")?; - test("2KiB", 2048, SizeUnit::Kibi, "2 KiB")?; - test("2kib", 2048, SizeUnit::Kibi, "2 KiB")?; + test("2KiB", 2048, "2 KiB")?; + test("2kib", 2048, "2 KiB")?; - test("2.3456MiB", (2.3456*1024.0*1024.0) as u64, SizeUnit::Mebi, "2.345 MiB")?; + test("2.3456MiB", (2.3456*1024.0*1024.0) as u64, "2.345 MiB")?; - test("4gib", (4.0*1024.0*1024.0*1024.0) as u64, SizeUnit::Gibi, "4 GiB")?; + test("4gib", (4.0*1024.0*1024.0*1024.0) as u64, "4 GiB")?; Ok(()) } diff --git a/src/cached_traffic_control.rs b/src/cached_traffic_control.rs index b45e564c..05bf8a60 100644 --- a/src/cached_traffic_control.rs +++ b/src/cached_traffic_control.rs @@ -225,8 +225,8 @@ impl TrafficControlCache { match rule.rate_in { Some(rate_in) => { read_limiter.update_rate( - rate_in.as_u64(), - rule.burst_in.unwrap_or(rate_in).as_u64(), + rate_in.size, + rule.burst_in.unwrap_or(rate_in).size, ); } None => entry.0 = None, @@ -238,8 +238,8 @@ impl TrafficControlCache { let limiter = create_limiter( self.use_shared_memory, &name, - rate_in.as_u64(), - rule.burst_in.unwrap_or(rate_in).as_u64(), + rate_in.size, + rule.burst_in.unwrap_or(rate_in).size, )?; entry.0 = Some(limiter); } @@ -251,8 +251,8 @@ impl TrafficControlCache { match rule.rate_out { Some(rate_out) => { write_limiter.update_rate( - rate_out.as_u64(), - rule.burst_out.unwrap_or(rate_out).as_u64(), + rate_out.size, + rule.burst_out.unwrap_or(rate_out).size, ); } None => entry.1 = None, @@ -264,8 +264,8 @@ impl TrafficControlCache { let limiter = create_limiter( self.use_shared_memory, &name, - rate_out.as_u64(), - rule.burst_out.unwrap_or(rate_out).as_u64(), + rate_out.size, + rule.burst_out.unwrap_or(rate_out).size, )?; entry.1 = Some(limiter); } -- 2.30.2