use std::mem::size_of;
use crate::core::CONTINUOUS_SEQUENCE_LIMIT;
use crate::ipdv::IpdvSample;
use crate::normalization::ReplySample;
use crate::rolling::RollingEvent;
use crate::{SampleMode, StatsConfig};
const GROWTH_FACTOR: u64 = 2;
const HASH_ENTRY_OVERHEAD: u64 = 1;
pub(crate) const EXACT_SAMPLES_PER_PROBE: u64 = 11;
const ROLLING_EVENTS_PER_PROBE: u64 = 2;
pub(crate) fn estimated_retained_bytes(config: &StatsConfig, probe_count: u64) -> u64 {
let cumulative = match config.samples {
SampleMode::Exact => exact_bytes(probe_count),
SampleMode::RunningOnly => running_only_bytes(probe_count),
};
cumulative
.saturating_add(rolling_count_bytes(config, probe_count))
.saturating_mul(GROWTH_FACTOR)
}
fn exact_bytes(probe_count: u64) -> u64 {
let per_probe = EXACT_SAMPLES_PER_PROBE
.saturating_mul(size_of::<i128>() as u64)
.saturating_add(ipdv_tracker_bytes_per_sample());
probe_count.saturating_mul(per_probe)
}
fn running_only_bytes(probe_count: u64) -> u64 {
probe_count
.min(CONTINUOUS_SEQUENCE_LIMIT as u64)
.saturating_mul(ipdv_tracker_bytes_per_sample())
}
fn ipdv_tracker_bytes_per_sample() -> u64 {
let sample_entry = (size_of::<u32>() + size_of::<IpdvSample>()) as u64 + HASH_ENTRY_OVERHEAD;
let order_entry = size_of::<u32>() as u64;
let completed_entry = size_of::<u32>() as u64 + HASH_ENTRY_OVERHEAD;
sample_entry
.saturating_add(order_entry)
.saturating_add(completed_entry)
}
fn rolling_count_bytes(config: &StatsConfig, probe_count: u64) -> u64 {
let Some(limit) = config.rolling_count else {
return 0;
};
let retained = probe_count
.saturating_mul(ROLLING_EVENTS_PER_PROBE)
.min(limit as u64);
retained.saturating_mul(rolling_bytes_per_event())
}
fn rolling_bytes_per_event() -> u64 {
(size_of::<RollingEvent>() + size_of::<ReplySample>()) as u64
}