use crate::hostinfo;
use once_cell::sync::Lazy;
use std::cmp::min;
#[derive(Debug, Clone)] pub struct StrategicConfig {
pub max_core_allowed: usize,
pub max_core_in_flight: usize,
pub max_core_in_compress: usize,
pub max_mem_allowed: u64,
pub min_free_memory_ratio: f32,
pub file_split_block_size: u64,
pub max_chunks: u32,
pub compression_level: i32,
pub zstd_output_buffer_size: usize,
}
pub static CONFIG: Lazy<StrategicConfig> = Lazy::new(strategic_confi_large);
const SLOT_POOL_MEM_FRACTION: f64 = 0.5;
pub fn slot_pool_budget_bytes() -> u64 {
if let Some(explicit) = std::env::var("ZNIPPY_SLOT_POOL_BYTES")
.ok()
.and_then(|raw| parse_byte_size(&raw))
{
log::info!("[slot_pool] budget {explicit} bytes (ZNIPPY_SLOT_POOL_BYTES)");
return explicit;
}
let host_available = hostinfo::mem_available_bytes().unwrap_or(0);
let headroom = match hostinfo::cgroup_memory() {
Some(cg) => cg.total_memory.saturating_sub(cg.rss).min(host_available.max(1)),
None => host_available,
};
let budget = (headroom as f64 * SLOT_POOL_MEM_FRACTION) as u64;
log::info!(
"[slot_pool] budget {} bytes ({:.0}% of {} bytes headroom)",
budget,
SLOT_POOL_MEM_FRACTION * 100.0,
headroom
);
budget
}
pub fn parse_byte_size(raw: &str) -> Option<u64> {
let s = raw.trim();
let (digits, unit) = s.split_at(s.find(|c: char| !c.is_ascii_digit()).unwrap_or(s.len()));
let n: u64 = digits.parse().ok()?;
let mult = match unit.trim().to_ascii_lowercase().as_str() {
"" | "b" => 1u64,
"k" | "kb" | "kib" => 1024,
"m" | "mb" | "mib" => 1024 * 1024,
"g" | "gb" | "gib" => 1024 * 1024 * 1024,
_ => return None,
};
n.checked_mul(mult)
}
pub fn strategic_config(resource: f32) -> StrategicConfig {
let total_memory = hostinfo::mem_total_bytes().unwrap_or(0);
let max_core_allowed =
hostinfo::physical_core_count().unwrap_or_else(hostinfo::logical_cpu_count);
let max_core_in_flight = ((max_core_allowed as f32) * 0.90).ceil() as usize;
let max_core_in_compress = max_core_allowed.saturating_sub(max_core_in_flight);
let min_free_memory_ratio = 1.0 - resource;
let compression_level = 19;
let max_mem_allowed = ((total_memory as f32) * (1.0 - min_free_memory_ratio)) as u64;
let file_split_block_size = 10 * 1024 * 1024;
let zstd_output_buffer_size = 1 * 1024 * 1024;
let max_chunks: u32 = (max_mem_allowed / file_split_block_size) as u32;
log::info!(
"[strategic_config] Detekterade {} kärnor och {} MiB minne",
max_core_allowed,
total_memory / (1024 * 1024)
);
let sc = StrategicConfig {
max_core_allowed,
max_core_in_flight,
max_core_in_compress,
max_mem_allowed,
min_free_memory_ratio,
file_split_block_size,
compression_level,
max_chunks,
zstd_output_buffer_size,
};
log_strategic_conf(&sc);
sc
}
fn strategic_confi_large() -> StrategicConfig {
let mut sc = strategic_config(1.0);
sc.max_chunks = min(sc.max_chunks as u64, 128) as u32;
log::info!(
"[strategic_config large] max_core_in_flight={} max_core_in_compress for zstd {} max_chunks {} ",
sc.max_core_in_flight,
sc.max_core_in_compress,
sc.max_chunks
);
log_strategic_conf(&sc);
sc
}
fn log_strategic_conf(sc: &StrategicConfig) {
log::info!(
"[strategic_config] max_core_in_flight: {} (10%)",
sc.max_core_in_flight
);
log::info!(
"[strategic_config] max_core_in_compress: {} (90%)",
sc.max_core_in_compress
);
log::info!(
"[strategic_config] min_free_memory_ratio: {:.0}%",
sc.min_free_memory_ratio * 100.0
);
log::info!(
"[strategic_config] compression_level: {}",
sc.compression_level
);
log::info!("[strategic_config] max_chunks: {}", sc.max_chunks);
log::info!(
"[strategic_config] zstd_output_buffer_size: {}",
sc.zstd_output_buffer_size
);
}