pub struct ConnectionLimiter { /* private fields */ }Expand description
Shared rate limiter used by all deCDN-authored ProtocolHandler implementations.
reload(&self, &ResolvedSecurity) applies a new resolved-security
snapshot in place. The per-source governor limiter is rebuilt
from the new quota and swapped in wholesale through an internal
ArcSwap. The
global semaphore is replaced wholesale: a fresh Arc<Semaphore> of
the new capacity is built and atomically swapped into the
ArcSwapOption cell, so the next acquire hits the new semaphore.
Already-acquired OwnedSemaphorePermits hold a clone of the old
Arc<Semaphore> and continue to drain into it on Drop — they’re
dropped harmlessly once the last permit goes away.
semaphore = None encodes “global cap disabled”
(max_concurrent_handlers == 0) and the acquire path skips the
semaphore entirely.
Implementations§
Source§impl ConnectionLimiter
impl ConnectionLimiter
Sourcepub fn new(cfg: &ResolvedSecurity, metrics: Arc<Metrics>) -> Self
pub fn new(cfg: &ResolvedSecurity, metrics: Arc<Metrics>) -> Self
Construct a limiter from the resolved security configuration.
Sourcepub fn reload(&self, cfg: &ResolvedSecurity)
pub fn reload(&self, cfg: &ResolvedSecurity)
Apply a new ResolvedSecurity to the live limiter.
- Per-source: rebuild the keyed
governorlimiter from the new quota and atomically swap the wholePerSourceinto theArcSwapcell. Token-bucket state is not preserved across the swap. - Global semaphore: build a fresh
Arc<Semaphore>(orNonewhenmax_concurrent_handlers == 0) and atomically swap it into theArcSwapOptioncell. Already-acquired permits hold a clone of the previousArc<Semaphore>and drop it harmlessly on permit release; new acquires hit the new cell.
Infallible. Caller (RuntimeReloadState::reload) has already
validated the values via resolve_security.
Sourcepub fn acquire(&self, conn: &Connection) -> Result<Permit, RejectReason>
pub fn acquire(&self, conn: &Connection) -> Result<Permit, RejectReason>
Try to acquire a permit for conn.
On success returns a Permit that holds the semaphore slot and
updates the in-flight gauge. On failure returns the RejectReason,
records the appropriate metric counter, and emits a tracing::debug!
breadcrumb with reason/ip so operators investigating a counter
spike have something to grep for.
Cross-layer charge invariant: layers are checked in order global → per-source. The first layer to reject short-circuits; later layers never see the connection, so no token is wasted on a connection we already decided to drop.
This method is synchronous and completes in microseconds — it never awaits I/O.
Sourcepub fn gc_per_source(&self) -> Option<(usize, usize)>
pub fn gc_per_source(&self) -> Option<(usize, usize)>
Drop per-source buckets whose state has refilled to the fresh
baseline (#440). The acquire path dispatches an opportunistic
background sweep when the keyspace exceeds cap + cap/10, but a node
whose connection rate falls below the over-cap threshold can carry
millions of stale buckets indefinitely. The runtime spawns a
periodic task that calls this method to bound steady-state
memory regardless of acquire-driven activity.
Returns Some((before, after)) keyspace counts when a prune
actually ran, or None when the per-source layer is disabled or
the call lost the single-flight CAS to a concurrent prune. The
runtime’s periodic task uses this to emit a debug breadcrumb
only on real sweeps — silence is meaningful.
Single-flight with the acquire-path prune via the same
pruning_in_progress flag, with PruneGuard ensuring the flag
is released even if retain_recent panics — concurrent
observers (the periodic task and a flood-driven acquire)
coexist without spawning duplicate O(n) walks.
Sourcepub fn per_source_tracked(&self) -> usize
pub fn per_source_tracked(&self) -> usize
Number of per-source buckets currently tracked. Returns 0 when
the layer is disabled. Used by the periodic GC task in tests and
by the runtime’s debug-log breadcrumb so operators can correlate
keyspace size with the bookkeeping cap.
Auto Trait Implementations§
impl !Freeze for ConnectionLimiter
impl !RefUnwindSafe for ConnectionLimiter
impl !UnwindSafe for ConnectionLimiter
impl Send for ConnectionLimiter
impl Sync for ConnectionLimiter
impl Unpin for ConnectionLimiter
impl UnsafeUnpin for ConnectionLimiter
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> FutureExt for T
impl<T> FutureExt for T
Source§fn with_context(self, otel_cx: Context) -> WithContext<Self> ⓘ
fn with_context(self, otel_cx: Context) -> WithContext<Self> ⓘ
Source§fn with_current_context(self) -> WithContext<Self> ⓘ
fn with_current_context(self) -> WithContext<Self> ⓘ
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
Source§fn in_current_span(self) -> Instrumented<Self> ⓘ
fn in_current_span(self) -> Instrumented<Self> ⓘ
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§impl<T> IntoRequest<T> for T
impl<T> IntoRequest<T> for T
Source§fn into_request(self) -> Request<T>
fn into_request(self) -> Request<T>
T in a tonic::Request