use super::CompressionError;
use crate::atp::manifest::{CompressionAlgorithm, CompressionPolicy, ObjectKind};
pub struct CompressionPolicyEngine;
impl CompressionPolicyEngine {
pub fn default_policy() -> CompressionPolicy {
CompressionPolicy {
algorithm: CompressionAlgorithm::Lz4,
level: 1,
min_size_threshold: 1024, apply_to_kinds: vec![ObjectKind::FileObject, ObjectKind::ContentAddressedBlob],
}
}
pub fn disabled_policy() -> CompressionPolicy {
CompressionPolicy {
algorithm: CompressionAlgorithm::None,
level: 0,
min_size_threshold: u64::MAX,
apply_to_kinds: vec![],
}
}
pub fn bulk_transfer_policy() -> CompressionPolicy {
CompressionPolicy {
algorithm: CompressionAlgorithm::Gzip,
level: 6,
min_size_threshold: 4096, apply_to_kinds: vec![
ObjectKind::FileObject,
ObjectKind::ContentAddressedBlob,
ObjectKind::StreamObject,
],
}
}
pub fn validate_policy(policy: &CompressionPolicy) -> Result<(), CompressionError> {
match policy.algorithm {
CompressionAlgorithm::None => {
if policy.level != 0 {
return Err(CompressionError::PolicyViolation(
"none algorithm must have level 0".to_string(),
));
}
}
CompressionAlgorithm::Lz4 => {
}
CompressionAlgorithm::Gzip => {
if policy.level > 9 {
return Err(CompressionError::PolicyViolation(
"gzip level must be 0-9".to_string(),
));
}
}
CompressionAlgorithm::Brotli => {
if policy.level > 11 {
return Err(CompressionError::PolicyViolation(
"brotli level must be 0-11".to_string(),
));
}
}
}
if policy.min_size_threshold > 1_000_000 {
return Err(CompressionError::PolicyViolation(
"min_size_threshold too large (>1MB)".to_string(),
));
}
if matches!(policy.algorithm, CompressionAlgorithm::None)
&& !policy.apply_to_kinds.is_empty()
{
return Err(CompressionError::PolicyViolation(
"none algorithm should have empty apply_to_kinds".to_string(),
));
}
Ok(())
}
pub fn should_compress(
policy: &CompressionPolicy,
object_kind: ObjectKind,
object_size: u64,
) -> bool {
if matches!(policy.algorithm, CompressionAlgorithm::None) {
return false;
}
if !policy.apply_to_kinds.contains(&object_kind) {
return false;
}
object_size >= policy.min_size_threshold
}
pub fn estimate_compression_ratio(algorithm: CompressionAlgorithm, level: u8) -> f32 {
match algorithm {
CompressionAlgorithm::None => 1.0,
CompressionAlgorithm::Lz4 => 0.6, CompressionAlgorithm::Gzip => match level {
0..=2 => 0.7, 3..=6 => 0.5, 7..=9 => 0.4, _ => 0.5,
},
CompressionAlgorithm::Brotli => match level {
0..=3 => 0.6, 4..=7 => 0.4, 8..=11 => 0.3, _ => 0.4,
},
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_default_policy_validation() {
let policy = CompressionPolicyEngine::default_policy();
assert!(CompressionPolicyEngine::validate_policy(&policy).is_ok());
}
#[test]
fn test_disabled_policy() {
let policy = CompressionPolicyEngine::disabled_policy();
assert!(CompressionPolicyEngine::validate_policy(&policy).is_ok());
assert!(!CompressionPolicyEngine::should_compress(
&policy,
ObjectKind::FileObject,
1_000_000,
));
}
#[test]
fn test_bulk_transfer_policy() {
let policy = CompressionPolicyEngine::bulk_transfer_policy();
assert!(CompressionPolicyEngine::validate_policy(&policy).is_ok());
assert!(CompressionPolicyEngine::should_compress(
&policy,
ObjectKind::FileObject,
10_000,
));
assert!(!CompressionPolicyEngine::should_compress(
&policy,
ObjectKind::FileObject,
1000,
));
}
#[test]
fn test_policy_validation_errors() {
let bad_policy = CompressionPolicy {
algorithm: CompressionAlgorithm::Gzip,
level: 15, min_size_threshold: 1024,
apply_to_kinds: vec![ObjectKind::FileObject],
};
assert!(matches!(
CompressionPolicyEngine::validate_policy(&bad_policy),
Err(CompressionError::PolicyViolation(_))
));
let inconsistent_policy = CompressionPolicy {
algorithm: CompressionAlgorithm::None,
level: 0,
min_size_threshold: 1024,
apply_to_kinds: vec![ObjectKind::FileObject], };
assert!(matches!(
CompressionPolicyEngine::validate_policy(&inconsistent_policy),
Err(CompressionError::PolicyViolation(_))
));
}
#[test]
fn test_compression_ratio_estimates() {
assert_eq!(
CompressionPolicyEngine::estimate_compression_ratio(CompressionAlgorithm::None, 0),
1.0
);
assert_eq!(
CompressionPolicyEngine::estimate_compression_ratio(CompressionAlgorithm::Lz4, 1),
0.6
);
assert!(
CompressionPolicyEngine::estimate_compression_ratio(CompressionAlgorithm::Gzip, 9)
< 0.5
);
assert!(
CompressionPolicyEngine::estimate_compression_ratio(CompressionAlgorithm::Brotli, 11)
< 0.4
);
}
}