use std::collections::VecDeque;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ObjectClass {
CompilerArtifact,
DepInfo,
Source,
ToolchainBlob,
Unknown,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum CpuPressure {
Low,
Elevated,
Critical,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum VerificationBasis {
UncompressedLogical,
EncodedBytes,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct CompressionProfile {
pub name: &'static str,
pub level: i32,
pub verify: VerificationBasis,
}
pub const ZSTD_BALANCED: CompressionProfile = CompressionProfile {
name: "zstd-3",
level: 3,
verify: VerificationBasis::UncompressedLogical,
};
pub const ZSTD_FAST: CompressionProfile = CompressionProfile {
name: "zstd-1",
level: 1,
verify: VerificationBasis::UncompressedLogical,
};
pub const MIN_COMPRESS_BYTES: u64 = 4096;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum SkipReason {
Tiny,
AlreadyCompressed,
CpuPressure,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum CompressionDecision {
Skip(SkipReason),
Compress(CompressionProfile),
}
const MAGIC_PREFIXES: &[&[u8]] = &[
&[0x28, 0xB5, 0x2F, 0xFD], &[0x1F, 0x8B], &[0xFD, b'7', b'z', b'X', b'Z', 0x00], &[b'P', b'K', 0x03, 0x04], &[0x89, b'P', b'N', b'G'], &[0xFF, 0xD8, 0xFF], ];
#[must_use]
pub fn looks_precompressed(leading: &[u8]) -> bool {
MAGIC_PREFIXES
.iter()
.any(|magic| leading.len() >= magic.len() && &leading[..magic.len()] == *magic)
}
#[must_use]
pub fn decide(
class: ObjectClass,
logical_size: u64,
leading: &[u8],
pressure: CpuPressure,
) -> CompressionDecision {
if logical_size <= MIN_COMPRESS_BYTES {
return CompressionDecision::Skip(SkipReason::Tiny);
}
if looks_precompressed(leading) {
return CompressionDecision::Skip(SkipReason::AlreadyCompressed);
}
match pressure {
CpuPressure::Low => CompressionDecision::Compress(ZSTD_BALANCED),
CpuPressure::Elevated => CompressionDecision::Compress(ZSTD_FAST),
CpuPressure::Critical => match class {
ObjectClass::CompilerArtifact => CompressionDecision::Compress(ZSTD_FAST),
ObjectClass::DepInfo
| ObjectClass::Source
| ObjectClass::ToolchainBlob
| ObjectClass::Unknown => CompressionDecision::Skip(SkipReason::CpuPressure),
},
}
}
#[derive(Debug, Clone, Default, PartialEq, Eq)]
pub struct CompressionMetrics {
pub compressed_logical_bytes: u64,
pub compressed_encoded_bytes: u64,
pub compress_cpu_micros: u64,
pub skipped_tiny_bytes: u64,
pub skipped_precompressed_bytes: u64,
pub skipped_pressure_bytes: u64,
pub compressed_objects: u64,
pub skipped_objects: u64,
}
impl CompressionMetrics {
pub const fn record(
&mut self,
decision: CompressionDecision,
logical_bytes: u64,
encoded_bytes: u64,
cpu_micros: u64,
) {
match decision {
CompressionDecision::Compress(_) => {
self.compressed_objects += 1;
self.compressed_logical_bytes += logical_bytes;
self.compressed_encoded_bytes += encoded_bytes;
self.compress_cpu_micros += cpu_micros;
}
CompressionDecision::Skip(reason) => {
self.skipped_objects += 1;
match reason {
SkipReason::Tiny => self.skipped_tiny_bytes += logical_bytes,
SkipReason::AlreadyCompressed => {
self.skipped_precompressed_bytes += logical_bytes;
}
SkipReason::CpuPressure => self.skipped_pressure_bytes += logical_bytes,
}
}
}
}
#[must_use]
pub const fn emit(&self) -> CompressionReport {
let saved = self
.compressed_logical_bytes
.saturating_sub(self.compressed_encoded_bytes);
const GIB: u128 = 1024 * 1024 * 1024;
let cpu_micros_per_gib = if self.compressed_logical_bytes == 0 {
0
} else {
((self.compress_cpu_micros as u128 * GIB) / self.compressed_logical_bytes as u128)
as u64
};
let savings_permille = if self.compressed_logical_bytes == 0 {
0
} else {
((saved as u128 * 1000) / self.compressed_logical_bytes as u128) as u64
};
CompressionReport {
cpu_micros_per_gib,
transfer_bytes_saved: saved,
savings_permille,
skipped_bytes_total: self.skipped_tiny_bytes
+ self.skipped_precompressed_bytes
+ self.skipped_pressure_bytes,
compressed_objects: self.compressed_objects,
skipped_objects: self.skipped_objects,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct CompressionReport {
pub cpu_micros_per_gib: u64,
pub transfer_bytes_saved: u64,
pub savings_permille: u64,
pub skipped_bytes_total: u64,
pub compressed_objects: u64,
pub skipped_objects: u64,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct HotCache {
budget_bytes: u64,
used_bytes: u64,
entries: VecDeque<(String, u64)>,
pub hits: u64,
pub misses: u64,
}
impl HotCache {
#[must_use]
pub const fn new(budget_bytes: u64) -> Self {
Self {
budget_bytes,
used_bytes: 0,
entries: VecDeque::new(),
hits: 0,
misses: 0,
}
}
#[must_use]
pub const fn used_bytes(&self) -> u64 {
self.used_bytes
}
pub fn lookup(&mut self, key: &str) -> bool {
if let Some(index) = self.entries.iter().position(|(k, _)| k == key) {
let entry = self.entries.remove(index).expect("index valid");
self.entries.push_back(entry);
self.hits += 1;
true
} else {
self.misses += 1;
false
}
}
pub fn insert(&mut self, key: &str, size: u64) -> Vec<String> {
let mut evicted = Vec::new();
if size > self.budget_bytes {
return evicted;
}
if self.entries.iter().any(|(k, _)| k == key) {
return evicted;
}
while self.used_bytes + size > self.budget_bytes {
let (old_key, old_size) = self.entries.pop_front().expect("used > 0 implies entries");
self.used_bytes -= old_size;
evicted.push(old_key);
}
self.used_bytes += size;
self.entries.push_back((key.to_owned(), size));
evicted
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn h005_tiny_and_precompressed_objects_skip() {
for class in [
ObjectClass::CompilerArtifact,
ObjectClass::DepInfo,
ObjectClass::Unknown,
] {
assert_eq!(
decide(class, MIN_COMPRESS_BYTES, b"plain text", CpuPressure::Low),
CompressionDecision::Skip(SkipReason::Tiny)
);
}
let magics: [&[u8]; 6] = [
&[0x28, 0xB5, 0x2F, 0xFD, 0x00],
&[0x1F, 0x8B, 0x08],
&[0xFD, b'7', b'z', b'X', b'Z', 0x00, 0x00],
b"PK\x03\x04rest",
&[0x89, b'P', b'N', b'G', 0x0D],
&[0xFF, 0xD8, 0xFF, 0xE0],
];
for magic in magics {
assert_eq!(
decide(ObjectClass::ToolchainBlob, 1 << 20, magic, CpuPressure::Low),
CompressionDecision::Skip(SkipReason::AlreadyCompressed),
"magic {magic:02x?}"
);
}
assert_eq!(
decide(
ObjectClass::Source,
MIN_COMPRESS_BYTES + 1,
b"fn main() {}",
CpuPressure::Low
),
CompressionDecision::Compress(ZSTD_BALANCED)
);
}
#[test]
fn h005_pressure_degrades_level_before_decision() {
let big = 1 << 20;
assert_eq!(
decide(ObjectClass::DepInfo, big, b"text", CpuPressure::Low),
CompressionDecision::Compress(ZSTD_BALANCED)
);
assert_eq!(
decide(ObjectClass::DepInfo, big, b"text", CpuPressure::Elevated),
CompressionDecision::Compress(ZSTD_FAST)
);
assert_eq!(
decide(
ObjectClass::CompilerArtifact,
big,
b"elf",
CpuPressure::Critical
),
CompressionDecision::Compress(ZSTD_FAST)
);
for class in [
ObjectClass::DepInfo,
ObjectClass::Source,
ObjectClass::ToolchainBlob,
ObjectClass::Unknown,
] {
assert_eq!(
decide(class, big, b"text", CpuPressure::Critical),
CompressionDecision::Skip(SkipReason::CpuPressure)
);
}
}
#[test]
fn h005_zstd_profiles_verify_over_uncompressed_logical_bytes() {
for profile in [ZSTD_BALANCED, ZSTD_FAST] {
assert_eq!(profile.verify, VerificationBasis::UncompressedLogical);
}
assert_eq!(ZSTD_BALANCED.name, "zstd-3");
assert_eq!(ZSTD_FAST.name, "zstd-1");
assert_eq!(ZSTD_FAST.level, 1);
assert_eq!(ZSTD_BALANCED.level, 3);
}
#[test]
fn h005_metrics_emit_with_predeclared_denominator_and_countermetric() {
let mut metrics = CompressionMetrics::default();
const GIB: u64 = 1024 * 1024 * 1024;
metrics.record(
CompressionDecision::Compress(ZSTD_BALANCED),
2 * GIB,
GIB / 2,
3000,
);
metrics.record(CompressionDecision::Compress(ZSTD_FAST), GIB, GIB / 2, 1500);
metrics.record(CompressionDecision::Skip(SkipReason::Tiny), 1000, 1000, 0);
metrics.record(
CompressionDecision::Skip(SkipReason::AlreadyCompressed),
5 * GIB,
5 * GIB,
0,
);
let report = metrics.emit();
assert_eq!(report.cpu_micros_per_gib, 1500, "4500 micros / 3 GiB");
assert_eq!(report.transfer_bytes_saved, 2 * GIB);
assert_eq!(
report.savings_permille, 666,
"2/3 saved of COMPRESSED bytes"
);
assert_eq!(report.skipped_bytes_total, 5 * GIB + 1000);
assert_eq!(report.compressed_objects, 2);
assert_eq!(report.skipped_objects, 2);
let mut lazy = CompressionMetrics::default();
lazy.record(
CompressionDecision::Skip(SkipReason::CpuPressure),
10 * GIB,
10 * GIB,
0,
);
let lazy_report = lazy.emit();
assert_eq!(lazy_report.savings_permille, 0);
assert_eq!(lazy_report.cpu_micros_per_gib, 0);
assert_eq!(lazy_report.skipped_bytes_total, 10 * GIB);
}
#[test]
fn h005_hot_cache_is_bounded_lru_with_honest_hit_accounting() {
let mut cache = HotCache::new(100);
assert!(cache.insert("a", 40).is_empty());
assert!(cache.insert("b", 40).is_empty());
assert!(!cache.lookup("c"));
assert!(cache.lookup("a"), "a is resident");
assert_eq!((cache.hits, cache.misses), (1, 1));
let evicted = cache.insert("c", 40);
assert_eq!(evicted, vec!["b".to_owned()]);
assert!(cache.lookup("a"));
assert!(!cache.lookup("b"));
assert!(cache.lookup("c"));
assert_eq!(cache.used_bytes(), 80);
assert!(cache.insert("huge", 101).is_empty());
assert_eq!(cache.used_bytes(), 80);
assert!(cache.insert("a", 40).is_empty());
assert_eq!(cache.used_bytes(), 80);
}
}