const ENGAGE_PCT: u64 = 90;
const RELEASE_PCT: u64 = 80;
const EVICT_PCT: u64 = 95;
const EVICT_FACTOR_START: f64 = 0.75;
const EVICT_FACTOR_STEP: f64 = 0.85;
const EVICT_FACTOR_FLOOR: f64 = 0.50;
#[derive(Clone, Copy, PartialEq, Eq, Debug, Default)]
pub(crate) enum StreamPressureStage {
#[default]
None,
Gate,
Evict,
}
impl StreamPressureStage {
pub(crate) fn freezes_loads(self) -> bool {
matches!(self, Self::Gate)
}
}
pub(crate) struct PressureDecision {
pub(crate) stage: StreamPressureStage,
pub(crate) budget_factor: f64,
}
pub(crate) fn step_pressure(
rss: u64,
budget: u64,
rising: bool,
prev_stage: StreamPressureStage,
prev_factor: f64,
) -> PressureDecision {
let stage = next_stage(rss, budget, rising, prev_stage);
let budget_factor = match stage {
StreamPressureStage::Evict => {
if prev_stage == StreamPressureStage::Evict {
(prev_factor * EVICT_FACTOR_STEP).max(EVICT_FACTOR_FLOOR)
} else {
EVICT_FACTOR_START
}
}
StreamPressureStage::None | StreamPressureStage::Gate => 1.0,
};
PressureDecision {
stage,
budget_factor,
}
}
fn next_stage(
rss: u64,
budget: u64,
rising: bool,
prev: StreamPressureStage,
) -> StreamPressureStage {
use StreamPressureStage::*;
if budget == 0 {
return None;
}
let over = |pct: u64| rss.saturating_mul(100) > budget.saturating_mul(pct);
let under = |pct: u64| rss.saturating_mul(100) < budget.saturating_mul(pct);
match prev {
None => {
if over(EVICT_PCT) {
Evict
} else if over(ENGAGE_PCT) {
Gate
} else {
None
}
}
Gate => {
if under(RELEASE_PCT) {
None
} else if over(EVICT_PCT) || (over(ENGAGE_PCT) && rising) {
Evict
} else {
Gate
}
}
Evict => {
if under(RELEASE_PCT) {
None
} else {
Evict
}
}
}
}
pub(crate) fn scale_budget(baseline: u64, factor: f64) -> u64 {
if factor >= 1.0 {
baseline
} else {
(baseline as f64 * factor) as u64
}
}
#[cfg(test)]
mod tests {
use super::*;
const BUDGET: u64 = 1000;
fn step(rss: u64, rising: bool, prev: StreamPressureStage, factor: f64) -> PressureDecision {
step_pressure(rss, BUDGET, rising, prev, factor)
}
#[test]
fn holds_normal_below_engage() {
let d = step(500, true, StreamPressureStage::None, 1.0);
assert_eq!(d.stage, StreamPressureStage::None);
assert_eq!(d.budget_factor, 1.0);
}
#[test]
fn engages_gate_between_90_and_95() {
let d = step(920, false, StreamPressureStage::None, 1.0);
assert_eq!(d.stage, StreamPressureStage::Gate);
assert_eq!(d.budget_factor, 1.0);
}
#[test]
fn jumps_to_evict_above_95() {
let d = step(970, false, StreamPressureStage::None, 1.0);
assert_eq!(d.stage, StreamPressureStage::Evict);
assert_eq!(d.budget_factor, EVICT_FACTOR_START);
}
#[test]
fn latches_in_the_hysteresis_band() {
let engaged = step(850, false, StreamPressureStage::Gate, 1.0);
assert_eq!(engaged.stage, StreamPressureStage::Gate);
let released = step(850, true, StreamPressureStage::None, 1.0);
assert_eq!(released.stage, StreamPressureStage::None);
}
#[test]
fn releases_below_80() {
let from_gate = step(790, false, StreamPressureStage::Gate, 1.0);
assert_eq!(from_gate.stage, StreamPressureStage::None);
let from_evict = step(500, false, StreamPressureStage::Evict, EVICT_FACTOR_START);
assert_eq!(from_evict.stage, StreamPressureStage::None);
assert_eq!(from_evict.budget_factor, 1.0);
}
#[test]
fn gate_escalates_to_evict_when_rss_keeps_rising() {
let d = step(920, true, StreamPressureStage::Gate, 1.0);
assert_eq!(d.stage, StreamPressureStage::Evict);
assert_eq!(d.budget_factor, EVICT_FACTOR_START);
}
#[test]
fn gate_holds_when_not_rising_below_evict() {
let d = step(920, false, StreamPressureStage::Gate, 1.0);
assert_eq!(d.stage, StreamPressureStage::Gate);
}
#[test]
fn evict_holds_until_full_release() {
let d = step(920, false, StreamPressureStage::Evict, EVICT_FACTOR_START);
assert_eq!(d.stage, StreamPressureStage::Evict);
}
#[test]
fn evict_factor_tightens_across_sustained_samples_down_to_the_floor() {
let a = step(990, true, StreamPressureStage::Evict, EVICT_FACTOR_START);
assert_eq!(a.budget_factor, EVICT_FACTOR_START * EVICT_FACTOR_STEP);
let b = step(
990,
true,
StreamPressureStage::Evict,
EVICT_FACTOR_FLOOR + 0.01,
);
assert_eq!(b.budget_factor, EVICT_FACTOR_FLOOR);
}
#[test]
fn zero_budget_disables_the_valve() {
let d = step_pressure(
9_999,
0,
true,
StreamPressureStage::Evict,
EVICT_FACTOR_START,
);
assert_eq!(d.stage, StreamPressureStage::None);
assert_eq!(d.budget_factor, 1.0);
}
#[test]
fn only_stage_one_freezes_loads() {
assert!(!StreamPressureStage::None.freezes_loads());
assert!(StreamPressureStage::Gate.freezes_loads());
assert!(!StreamPressureStage::Evict.freezes_loads());
}
#[test]
fn scale_budget_restores_at_one_and_reduces_below() {
assert_eq!(scale_budget(1000, 1.0), 1000);
assert_eq!(scale_budget(1000, 1.5), 1000);
assert_eq!(scale_budget(1000, 0.75), 750);
assert_eq!(scale_budget(1000, 0.5), 500);
}
}