use crate::pressure::{ConsumerCapacity, PressureSignal};
use std::time::Duration;
pub const DEFAULT_MAX_IN_FLIGHT: usize = 128;
pub const DEFAULT_MAX_BUFFER_DEPTH: usize = 1_024;
#[must_use]
pub const fn default_capacity() -> ConsumerCapacity {
ConsumerCapacity {
max_in_flight: DEFAULT_MAX_IN_FLIGHT,
max_buffer_depth: DEFAULT_MAX_BUFFER_DEPTH,
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct ChannelPressureConfig {
pub defer_delay_base_ms: u64,
pub defer_delay_max_ms: u64,
pub durable_reject_watermark_percent: u8,
}
impl ChannelPressureConfig {
pub const DEFAULT: Self = Self {
defer_delay_base_ms: 25,
defer_delay_max_ms: 250,
durable_reject_watermark_percent: 100,
};
}
impl Default for ChannelPressureConfig {
fn default() -> Self {
Self::DEFAULT
}
}
const fn buffer_fill(signal: &PressureSignal) -> (u128, u128) {
match *signal {
PressureSignal::Accept { .. } => (0, 1),
PressureSignal::Defer {
current_buffer_depth,
max_buffer_depth,
..
} => {
if max_buffer_depth == 0 || current_buffer_depth >= max_buffer_depth {
(1, 1)
} else {
(current_buffer_depth as u128, max_buffer_depth as u128)
}
}
PressureSignal::Reject { .. } => (1, 1),
}
}
const fn fill_at_least(candidate: &PressureSignal, held: &PressureSignal) -> bool {
let (candidate_filled, candidate_bound) = buffer_fill(candidate);
let (held_filled, held_bound) = buffer_fill(held);
candidate_filled * held_bound >= held_filled * candidate_bound
}
#[must_use]
pub fn defer_delay(signal: &PressureSignal, config: ChannelPressureConfig) -> Option<Duration> {
if matches!(*signal, PressureSignal::Accept { .. }) {
return None;
}
let base = config.defer_delay_base_ms;
let ceiling = config.defer_delay_max_ms.max(base);
let span = ceiling.saturating_sub(base);
let (filled, bound) = buffer_fill(signal);
let scaled = u128::from(span) * filled / bound;
let added = u64::try_from(scaled).unwrap_or(span);
Some(Duration::from_millis(base.saturating_add(added)))
}
#[must_use]
pub const fn defer_after_append(signal: PressureSignal) -> PressureSignal {
match signal {
PressureSignal::Reject {
current_in_flight,
max_in_flight,
current_buffer_depth,
max_buffer_depth,
} => PressureSignal::defer(
current_in_flight,
max_in_flight,
current_buffer_depth,
max_buffer_depth,
),
other => other,
}
}
#[must_use]
pub const fn clamp_capacity_to_depth_cap(
declared: ConsumerCapacity,
depth_cap: usize,
) -> ConsumerCapacity {
let headroom = depth_cap.saturating_sub(declared.max_buffer_depth);
let max_in_flight = if declared.max_in_flight < headroom {
declared.max_in_flight
} else {
headroom
};
let max_in_flight = if max_in_flight == 0 { 1 } else { max_in_flight };
let remaining = depth_cap.saturating_sub(max_in_flight);
let max_buffer_depth = if declared.max_buffer_depth < remaining {
declared.max_buffer_depth
} else {
remaining
};
let max_buffer_depth = if max_buffer_depth == 0 {
1
} else {
max_buffer_depth
};
ConsumerCapacity {
max_in_flight,
max_buffer_depth,
}
}
#[must_use]
pub const fn watermark_reached(total_queued: usize, total_bound: usize, percent: u8) -> bool {
if total_bound == 0 {
return false;
}
let queued = (total_queued as u128) * 100;
let threshold = (total_bound as u128) * (percent as u128);
queued >= threshold
}
#[derive(Clone, Debug, Default)]
pub struct PressureAggregate {
matching: usize,
accepted: usize,
rejected: usize,
dropped: usize,
worst_accept: Option<PressureSignal>,
worst_pressured: Option<PressureSignal>,
}
impl PressureAggregate {
#[must_use]
pub const fn new() -> Self {
Self {
matching: 0,
accepted: 0,
rejected: 0,
dropped: 0,
worst_accept: None,
worst_pressured: None,
}
}
pub fn record(&mut self, signal: PressureSignal) {
self.matching += 1;
match signal {
PressureSignal::Accept {
current_in_flight, ..
} => {
self.accepted += 1;
let replace = self
.worst_accept
.as_ref()
.is_none_or(|held| accept_in_flight(held) <= current_in_flight);
if replace {
self.worst_accept = Some(signal);
}
}
PressureSignal::Defer { .. } | PressureSignal::Reject { .. } => {
if matches!(signal, PressureSignal::Reject { .. }) {
self.rejected += 1;
}
let replace = self
.worst_pressured
.as_ref()
.is_none_or(|held| fill_at_least(&signal, held));
if replace {
self.worst_pressured = Some(signal);
}
}
}
}
pub fn record_dropped(&mut self, signal: PressureSignal) {
self.dropped += 1;
self.record(signal);
}
#[must_use]
pub const fn matching(&self) -> usize {
self.matching
}
#[must_use]
pub const fn dropped(&self) -> usize {
self.dropped
}
#[must_use]
pub const fn every_match_dropped(&self) -> bool {
self.matching > 0 && self.dropped == self.matching
}
#[must_use]
pub fn resolve(&self) -> PressureSignal {
if self.matching == 0 {
return PressureSignal::accept(0, 0);
}
if self.rejected == self.matching {
return self
.worst_pressured
.unwrap_or_else(|| PressureSignal::accept(0, 0));
}
if self.accepted == self.matching {
return self
.worst_accept
.unwrap_or_else(|| PressureSignal::accept(0, 0));
}
self.worst_pressured
.map_or_else(|| PressureSignal::accept(0, 0), defer_after_append)
}
}
const fn accept_in_flight(signal: &PressureSignal) -> usize {
match *signal {
PressureSignal::Accept {
current_in_flight, ..
}
| PressureSignal::Defer {
current_in_flight, ..
}
| PressureSignal::Reject {
current_in_flight, ..
} => current_in_flight,
}
}
#[cfg(test)]
mod tests;