Skip to main content

Quota

Struct Quota 

Source
pub struct Quota { /* private fields */ }
Expand description

One connection’s tunnel budget.

Every tunnel — TCP or UDP — costs a file descriptor on the target side, and a single client multiplexes as many as it likes onto one QUIC connection. This is the bound that keeps one client from exhausting the process fd limit, so both tunnel types draw on the same budget rather than one each.

A semaphore for the admission decision, plus a signal for the drain: the shutdown path needs to observe the count reaching zero without competing for it.

The two used to be one thing — wait_until_idle was acquire_many(limit), on the reading that taking every permit at once is the same as waiting for every tunnel to end. It is not. tokio’s semaphore is fair, so a waiter that cannot be satisfied yet takes the permits that are free and queues for the rest; while the drain waited, available_permits() was zero, so live() reported the full limit and acquire() refused every caller. The connection then answered 503 connection_limit_reached to requests below the GOAWAY identifier — ones the peer had been told “might have been processed”, RFC 9114 §5.2, and this server means to serve — with one tunnel open out of a hundred (adversarial pass 2026-08-29).

Implementations§

Source§

impl Quota

Source

pub fn new(limit: u32) -> Self

Creates a quota allowing limit concurrent tunnels.

Source

pub fn acquire(&self) -> Option<Slot>

Takes a slot, or None when the connection is at its limit.

Source

pub fn enter(&self) -> Pending

Records that a request has been accepted and is being served.

Held by the task from the moment the request stream is accepted until that task ends, which is the span Self::acquire cannot cover: a request only reaches the semaphore once its headers have arrived and its credentials have been checked, and the ones that never get that far – the 400s, the 407s – never reach it at all. Nothing is rationed here; the count exists so the drain can tell “no work left” from “no work that has a slot yet”.

Source

pub fn live(&self) -> u32

How many tunnels are open right now.

Source

pub fn is_busy(&self) -> bool

Whether anything on this connection is still being served.

Both halves count, and the second is the one a tunnel count alone misses: a request accepted before the GOAWAY whose headers are still arriving holds no slot, and closing the connection on it contradicts the “might have been processed” its GOAWAY identifier signalled (RFC 9114 §5.2) without the REQUEST_REJECTED that would let the client retry.

Source

pub async fn wait_until_idle(&self)

Resolves once every request on this connection has finished.

Used by the graceful shutdown path. The caller is responsible for bounding the wait — a tunnel that never ends would otherwise hold shutdown open forever.

Cancel-safe, which it has to be: crate::conn::handle polls this as one arm of a select! and drops it again on every pass. notify_one leaves a permit behind when nobody is waiting and hands an unclaimed notification on when a waiter is dropped, so neither a slot released between the check and the park nor a lost race can wedge the drain.

Auto Trait Implementations§

§

impl Freeze for Quota

§

impl RefUnwindSafe for Quota

§

impl Send for Quota

§

impl Sync for Quota

§

impl Unpin for Quota

§

impl UnsafeUnpin for Quota

§

impl UnwindSafe for Quota

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 = Infallible

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

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

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