use crate::{
clock::Clock,
event,
stream::{application::Builder as StreamBuilder, environment::Environment, server::stats},
sync::mpmc as channel,
};
use core::time::Duration;
use s2n_quic_core::time::Clock as _;
#[derive(Clone, Debug)]
pub struct Pruner {
pub sojourn_multiplier: u32,
pub min_threshold: Duration,
pub max_threshold: Duration,
pub min_sleep_time: Duration,
pub max_sleep_time: Duration,
}
impl Default for Pruner {
fn default() -> Self {
Self {
sojourn_multiplier: 3,
min_threshold: Duration::from_millis(100),
max_threshold: Duration::from_secs(5),
min_sleep_time: Duration::from_millis(100),
max_sleep_time: Duration::from_secs(1),
}
}
}
impl Pruner {
pub async fn run<Env>(
self,
env: Env,
channel: channel::WeakReceiver<StreamBuilder<Env::Subscriber>>,
stats: stats::Stats,
) where
Env: Environment,
{
let Self {
sojourn_multiplier,
min_threshold,
max_threshold,
min_sleep_time,
max_sleep_time,
} = self;
let clock = env.clock().clone();
let mut timer = clock.timer();
timer.sleep(clock.get_time() + min_sleep_time).await;
loop {
let now = clock.get_time();
let smoothed_sojourn_time = stats.smoothed_sojourn_time();
let Some(queue_time_threshold) = now.checked_sub(
(smoothed_sojourn_time * sojourn_multiplier).clamp(min_threshold, max_threshold),
) else {
timer.sleep(now + min_sleep_time).await;
continue;
};
let priority = channel::Priority::Optional;
loop {
let res = channel.pop_back_if(priority, |stream| {
stream.queue_time.has_elapsed(queue_time_threshold)
});
match res {
Ok(Some(stream)) => {
stream.prune(
event::builder::AcceptorStreamPruneReason::MaxSojournTimeExceeded,
);
continue;
}
Ok(None) => break,
Err(_) => return,
}
}
let target = smoothed_sojourn_time.clamp(min_sleep_time, max_sleep_time);
let target = clock.get_time() + target;
timer.sleep(target).await;
}
}
}