Skip to main content

Governor

Struct Governor 

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

Both gates, and the occupancy they meter.

Implementations§

Source§

impl Governor

Source

pub fn new(band: LimitBand, budget: u64) -> Governor

A governor over band with budget bytes of memory to give out.

Source

pub fn codel(&self) -> &Codel

The delay controller.

Source

pub fn memory(&self) -> &MemoryLedger

The memory ledger.

Source

pub fn limit(&self) -> usize

The governed limit right now.

Source

pub fn occupied(&self) -> usize

Operations in flight right now.

Source

pub fn occupied_in(&self, lane: Lane) -> usize

Operations in flight in one lane.

Source

pub fn lane_ceiling(&self, lane: Lane, limit: usize) -> usize

How many slots lane may hold right now: the governed limit, less the part of every other lane’s floor that somebody is actually waiting for.

§A floor that reserves an idle lane’s slots is the old bug again

The per-principal cap used to bind unconditionally, and measured on the 32-core desktop that meant 32 served and 32 refused against 224 idle slots (crate::admission). A lane floor that reserved an eighth of the box for ls-remote whether or not any ls-remote existed would be the same mistake with a different noun: it would refuse a push the box could serve, to keep a slot warm for a request nobody had made.

So the floor is claimed on demand, and demand is now observable: since 2026-08-30 an operation over the limit parks (crate::Admission::admit_within) instead of being refused, so the number of parked operations per lane is a live, exact count of who is asking. A lane with nobody waiting reserves nothing; the instant one ls-remote parks, one slot of the cheap floor is held back and the next release goes to it rather than to the push storm that would otherwise take every slot for as long as it lasted.

min(floor, waiting) is what makes it a floor and not a queue: a lane can never reserve more than Lane::floor however many of its operations are waiting, so cheap cannot starve write either.

Source

pub fn waiting_in(&self, lane: Lane) -> usize

Operations of lane parked waiting for a slot right now.

Source

pub fn entered_wait(&self, lane: Lane)

Say that one operation of lane has started waiting.

Paired with Governor::left_wait by crate::Admission::admit_within, which is the only caller and which pairs them on every path including cancellation.

Source

pub fn left_wait(&self, lane: Lane)

Say that one operation of lane has stopped waiting.

Source

pub fn shed_counts(&self) -> (u64, u64, u64)

Refusals by gate: (concurrency, lane, memory).

Source

pub fn overdrawn(&self) -> u64

How many transfers have charged the ledger past its budget while running (Growth::Overdrawn).

Source

pub fn try_claim(&self, class: OpClass) -> Result<Claim, Shed>

The admission decision. Time first, then the lane, then space, then take all three.

Nothing is allocated on any refusal path, and nothing the operation needs is allocated on the success path either: a Claim is three Copy words. That is the point of the gate — the refusal has to arrive before the cost, or it is only a slower way of paying it.

Source

pub fn claim_for(&self, class: OpClass, count: bool) -> Result<Claim, Shed>

Governor::try_claim or Governor::attempt, chosen by the caller.

Source

pub fn claim_reserving( &self, class: OpClass, reserve: usize, count: bool, ) -> Result<Claim, Shed>

Governor::claim_for against a limit reserve slots lower than the governed one, so that this claim can never take one of the last reserve slots.

§Why the reserve is enforced here and not by the caller

A caller can read Governor::occupied, compare it to a threshold and only then ask for a claim — and that is a race, for exactly the reason written over the compare-and-swap below: N racing admissions all read the same occupancy and all decide they fit. Measured, on a four-slot gate with two hundred anonymous readers: strangers holding transient claims while they made that decision filled the server-wide gate, and a keyed caller arriving into that window was refused by gate 1 with AtCapacity — the reserve that existed to protect it having never been consulted. A limit that is checked outside the atomic that enforces it is not a limit.

So the reserve rides in the same fetch_update. N racing strangers can then no more collectively exceed limit - reserve than they can exceed limit, and a refused one never holds a slot at all — which matters twice, because the refusal path of a flood is the path an attacker is trying to make expensive.

§Why this moves no shed counter

The three Governor::shed_counts counters count this governor’s own gates — the limit it controls, the lane floors it computes, the ledger it keeps. The reserve is none of those: it is a number the caller handed in, for a policy the caller owns, and the caller counts it (AdmissionStats::refused_keyed_reserve). Counting it here as a concurrency shed would tell an operator the CoDel limit was full when it was nowhere near, and counting it here under a fourth name would give the same event two owners.

Source

pub fn attempt(&self, class: OpClass) -> Result<Claim, Shed>

Governor::try_claim without moving the shed counters.

The retry inside crate::Admission::admit_within asks this door many times for one operation. Counting every ask would make shed_concurrency a count of polls rather than of refusals — the counter would read 21 where one client was refused once, which is worse than no counter. So the wait loop attempts without counting and counts once, at the end, when the refusal is final.

Source

pub fn charge(&self, held_after: u64, extra: u64) -> Growth

Charge a running transfer for what has actually crossed the wire.

Called by crate::AdmissionGuard::reserve_more and by nothing else, so the guard stays the single owner of “what this operation holds” and the release cannot drift. See Growth for why it cannot refuse and WIRE_MEMORY_NUMERATOR for what fraction of the wire is charged.

Source

pub fn release(&self, claim: &Claim, grown: u64)

Give a claim’s slot and reservation back. Called from exactly one place: AdmissionGuard’s Drop, which passes what it grew the reservation to on top of Claim::bytes.

Source

pub fn record_sojourn(&self, class: OpClass, sojourn: Duration)

File one admission wait against its class’s window.

This is the controller’s input, and the change of input is the point: see LimitBand::for_budget for what it used to be (the runtime’s spawn-to-run gap) and why a controller that cannot move its own input runs to its floor. A wait of zero — the ordinary case on an unloaded server — is a sample too, and it is the one that grows the limit back.

Trait Implementations§

Source§

impl Debug for Governor

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> Allocation for T
where T: RefUnwindSafe + Send + Sync,

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<'a, T, E> AsTaggedExplicit<'a, E> for T
where T: 'a,

Source§

fn explicit(self, class: Class, tag: u32) -> TaggedParser<'a, Explicit, Self, E>

Source§

impl<'a, T, E> AsTaggedImplicit<'a, E> for T
where T: 'a,

Source§

fn implicit( self, class: Class, constructed: bool, tag: u32, ) -> TaggedParser<'a, Implicit, Self, E>

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<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

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

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

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> Read<Exclusive, BecauseExclusive> for T
where T: ?Sized,

Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
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.
Source§

impl<T> WithSubscriber for T

Source§

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
Source§

fn with_current_subscriber(self) -> WithDispatch<Self> ⓘ

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