Skip to main content

logicaffeine_data/
backpressure.rs

1//! `BoundedRing<T>` — a fixed-capacity queue that drops the OLDEST item on overflow.
2//!
3//! This is the backpressure primitive for the real-time relay's per-connection outbound queue.
4//! The relay hands each connection an UNBOUNDED channel today (`logicaffeine_system::relay`), so a
5//! single slow consumer under a fast producer grows without bound — a latent OOM. A live-media
6//! queue must instead be bounded, and when it fills it should shed the STALEST frames (a late video
7//! frame is worthless; FEC and the next keyframe cover the gap), never the freshest, and never
8//! stall the whole relay. Every shed frame is counted in [`BoundedRing::dropped`] — the exact
9//! signal the congestion controller (`adaptRate`) reads to back off. Bounded memory,
10//! freshest-data-wins, drop-aware: the correct real-time transport policy.
11
12use std::collections::VecDeque;
13
14/// A FIFO queue capped at `cap` items; a push into a full ring evicts the oldest.
15#[derive(Debug, Clone)]
16pub struct BoundedRing<T> {
17    buf: VecDeque<T>,
18    cap: usize,
19    dropped: u64,
20}
21
22impl<T> BoundedRing<T> {
23    /// A ring holding at most `cap` items. `cap` must be positive.
24    pub fn new(cap: usize) -> Self {
25        assert!(cap > 0, "a BoundedRing needs a positive capacity");
26        Self {
27            buf: VecDeque::with_capacity(cap),
28            cap,
29            dropped: 0,
30        }
31    }
32
33    /// Enqueue `item`. If the ring is already full, the OLDEST item is evicted first (and counted
34    /// in [`dropped`](Self::dropped)); the evicted item is returned so the caller can telemeter it.
35    pub fn push(&mut self, item: T) -> Option<T> {
36        let evicted = if self.buf.len() == self.cap {
37            self.dropped += 1;
38            self.buf.pop_front()
39        } else {
40            None
41        };
42        self.buf.push_back(item);
43        evicted
44    }
45
46    /// Dequeue the oldest surviving item (FIFO).
47    pub fn pop(&mut self) -> Option<T> {
48        self.buf.pop_front()
49    }
50
51    pub fn len(&self) -> usize {
52        self.buf.len()
53    }
54
55    pub fn is_empty(&self) -> bool {
56        self.buf.is_empty()
57    }
58
59    pub fn is_full(&self) -> bool {
60        self.buf.len() == self.cap
61    }
62
63    pub fn capacity(&self) -> usize {
64        self.cap
65    }
66
67    /// The number of items shed to overflow since construction — the drop telemetry the congestion
68    /// controller reads to lower the send rate.
69    pub fn dropped(&self) -> u64 {
70        self.dropped
71    }
72}
73
74#[cfg(test)]
75#[path = "../../logicaffeine_tests/unit/logicaffeine_data/backpressure/tests.rs"]
76mod tests;