pub const ADAPTIVE_SAMPLE_INTERVAL: usize = 10;
pub const ADAPTIVE_MIN_BATCH: usize = 500;
pub fn next_adaptive_batch_size(current: usize, base: usize, under_pressure: bool) -> usize {
if under_pressure {
(current * 3 / 4).max(ADAPTIVE_MIN_BATCH)
} else {
(current * 5 / 4).min(base)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn adaptive_shrinks_by_25_percent_under_pressure() {
assert_eq!(next_adaptive_batch_size(10_000, 10_000, true), 7_500);
assert_eq!(next_adaptive_batch_size(8_000, 10_000, true), 6_000);
}
#[test]
fn adaptive_grows_by_25_percent_when_idle() {
assert_eq!(next_adaptive_batch_size(4_000, 10_000, false), 5_000);
}
#[test]
fn adaptive_recovery_caps_at_base_ceiling() {
assert_eq!(next_adaptive_batch_size(9_000, 10_000, false), 10_000);
assert_eq!(next_adaptive_batch_size(10_000, 10_000, false), 10_000);
}
#[test]
fn adaptive_shrink_respects_min_floor() {
assert_eq!(
next_adaptive_batch_size(600, 10_000, true),
ADAPTIVE_MIN_BATCH
);
assert_eq!(
next_adaptive_batch_size(ADAPTIVE_MIN_BATCH, 10_000, true),
ADAPTIVE_MIN_BATCH
);
}
#[test]
fn adaptive_pressure_path_ignores_base_uses_only_floor() {
assert_eq!(
next_adaptive_batch_size(ADAPTIVE_MIN_BATCH, 100, true),
ADAPTIVE_MIN_BATCH
);
}
#[test]
fn adaptive_steady_state_oscillation_stays_bounded() {
let base = 5_000;
let mut s = base;
for _ in 0..50 {
s = next_adaptive_batch_size(s, base, true);
}
assert_eq!(
s, ADAPTIVE_MIN_BATCH,
"sustained pressure must converge to floor"
);
for _ in 0..50 {
s = next_adaptive_batch_size(s, base, false);
}
assert_eq!(s, base, "sustained recovery must converge to base ceiling");
}
}