Skip to main content

EgressGauge

Struct EgressGauge 

Source
pub(crate) struct EgressGauge {
    queued: AtomicUsize,
    idle: Notify,
    discarding: AtomicBool,
}
Expand description

How many bytes one session’s egress queues are holding, right now.

One gauge per session, shared by every PendingQueue the session builds. It exists for a single caller — a requested close, which has to know when there is nothing left to flush so it can stop waiting early — and it answers that question in the one unit that is worth waiting on.

§Why a byte gauge rather than a stream count

A session’s live streams are already enumerated by StreamRegistry, and waiting for that to empty was the obvious alternative. It is the wrong signal twice over: a stream with an empty queue keeps its registration until its source FINs, so the wait would run to the deadline on a session that had nothing to flush at all; and a stream that ends while its queue is full drops its registration with the bytes still unwritten, so the wait would finish claiming a drain that lost data.

§Two-valued, and the second value is the whole bound

Self::wait_idle is the wait. Self::begin_discarding is what happens when the wait runs out: it puts every queue in the session into a mode where PendingQueue::drain_ignoring_release_times writes nothing at all.

That looks backwards next to the rest of this module, whose teardown rule is delivered late beats lost silently. The difference is that an ordinary teardown is not a deadline anybody set — the flush is the best remaining chance those bytes have. A close that has already been given its drain window and spent it is a deadline somebody set, and flushing past it makes the outcome unreportable: a write_all into quinn returns Ok as soon as the bytes are buffered and Connection::close discards that buffer, so the bytes are neither confirmably delivered nor confirmably lost, and no count of them adds up. Declining to write keeps the arithmetic exact — what the peer received plus what ImpairmentKind::QueuedBytesAtTeardown names equals what was queued when the close was requested — which is the property a gate can actually be written against.

Fields§

§queued: AtomicUsize

Bytes queued across every live PendingQueue of this session.

§idle: Notify

Pulsed whenever queued reaches zero.

§discarding: AtomicBool

Whether teardown flushes are declined — see the type’s own doc.

Implementations§

Source§

impl EgressGauge

Source

pub(crate) fn new() -> Arc<Self>

A gauge reading zero, flushing normally.

Source

pub(crate) fn queued(&self) -> usize

Bytes queued across the session at this instant.

Source

pub(crate) fn is_discarding(&self) -> bool

Whether teardown flushes are being declined.

Source

pub(crate) fn begin_discarding(&self)

Decline every later teardown flush on this session.

One-way: nothing turns it off again, because the only caller is a close whose drain window has expired and a session in that state is on its way down.

Source

fn add(&self, bytes: usize)

Charge bytes to the session total.

Source

fn sub(&self, bytes: usize)

Credit bytes back, waking a waiter when the session reaches zero.

Source

pub(crate) async fn wait_idle(&self, timeout: Duration) -> usize

Wait for the session’s queues to empty, for at most timeout.

Answers the bytes still queued when it returns: 0 when everything drained, and the residue when the deadline won. That residue is the figure a caller acts on — it is what will be abandoned — and it is deliberately a byte count and not “did it time out”, because the two differ: a queue that empties on the last poll before the deadline drained, and one that reports zero after the deadline drained too.

The registration is armed before the count is re-read, so a queue that empties between the two is not a lost wakeup that costs the caller its whole timeout.

Trait Implementations§

Source§

impl Debug for EgressGauge

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

§

impl<T> Instrument for T

§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided [Span], returning an Instrumented wrapper. Read more
§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, !>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
§

impl<T> WithSubscriber for T

§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a [WithDispatch] wrapper. Read more
§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a [WithDispatch] wrapper. Read more