use std::sync::atomic::{AtomicBool, Ordering};
use super::{LoadShedPolicy, PressureSnapshot, RequestClass, ShedDecision, ShedReason};
#[derive(Debug, Clone, Copy)]
pub struct Params {
pub egress_budget_bps: u64,
pub max_serves_high: u32,
pub max_serves_low: u32,
pub per_client_cap: u32,
}
#[derive(Debug)]
pub struct ResourcePressure {
params: Params,
pressured: AtomicBool,
}
impl ResourcePressure {
#[must_use]
pub const fn new(params: Params) -> Self {
Self {
params,
pressured: AtomicBool::new(false),
}
}
fn update_pressure(&self, streams_in_flight: u32) -> bool {
if streams_in_flight >= self.params.max_serves_high {
self.pressured.store(true, Ordering::Relaxed);
} else if streams_in_flight <= self.params.max_serves_low {
self.pressured.store(false, Ordering::Relaxed);
}
self.pressured.load(Ordering::Relaxed)
}
}
impl LoadShedPolicy for ResourcePressure {
fn decide(&self, class: RequestClass, snap: &PressureSnapshot) -> ShedDecision {
let pressured = self.update_pressure(snap.streams_in_flight);
if pressured
&& self.params.per_client_cap > 0
&& snap.client_streams_in_flight >= self.params.per_client_cap
{
return ShedDecision::Shed(ShedReason::ClientAtCapacity);
}
if self.params.egress_budget_bps > 0 && snap.egress_bps >= self.params.egress_budget_bps {
return ShedDecision::Shed(ShedReason::EgressSaturated);
}
if pressured && class == RequestClass::CacheMiss {
return ShedDecision::Shed(ShedReason::NodeAtCapacity);
}
ShedDecision::Admit
}
fn pressure_active(&self) -> bool {
self.pressured.load(Ordering::Relaxed)
}
}
#[cfg(test)]
mod tests;