Skip to main content

Refusal

Enum Refusal 

Source
pub enum Refusal {
    AtCapacity {
        limit: usize,
    },
    PrincipalAtCapacity {
        limit: usize,
        active_principals: usize,
    },
    LaneAtCapacity {
        lane: Lane,
        ceiling: usize,
        limit: usize,
    },
    AnonymousAtCapacity {
        limit: usize,
    },
    KeyedReserve {
        occupied: usize,
        limit: usize,
        reserve: usize,
    },
    MemoryBudget {
        class: OpClass,
        wanted: u64,
        reserved: u64,
        budget: u64,
    },
    Paused {
        pause: Pause,
    },
}
Expand description

Why a transfer was not admitted.

Every variant carries the number that was hit, because a refusal an operator cannot tie to a number is a mystery rather than a signal.

Variants§

§

AtCapacity

The server-wide concurrent-transfer limit is full.

Fields

§limit: usize

The server-wide limit in force at the moment of the refusal.

The governed limit, not the configured one: the configured number is the ceiling of LimitBand, and what actually refuses is wherever the CoDel controller has moved to inside it. Reported rather than assumed, for the same reason the per-principal share is: an operator who read one number out of a config file and a different one out of a log would conclude the gate was broken.

§

PrincipalAtCapacity

This principal already holds its share of the server-wide limit.

Fields

§limit: usize

The per-principal limit in force at the moment of the refusal.

Under SshConfig::per_principal_limit_is_hard that is the configured number. Otherwise it is the max-min share — max(configured, server_wide / active) — which is why it is reported rather than assumed: an operator who read the configured number out of a file and a different number out of a log would conclude the gate was broken.

§active_principals: usize

How many identities held a transfer when this one was refused.

1 means the refusal came from a hard configured cap: a share is never smaller than the whole server when there is only one claimant. Without this an operator cannot tell “you are being throttled because the box is shared” from “you are being throttled because somebody pinned a number”.

§

LaneAtCapacity

This operation’s lane is full while the rest of the server is held by the other lanes’ floors (gate 1b, Lane::floor).

Its own variant because the operator action is different: “the box is full” says raise the budget, and this one says a write storm is being held to five eighths of the box on purpose so that reads still land.

Fields

§lane: Lane

The lane that was full.

§ceiling: usize

What that lane may hold right now.

§limit: usize

The governed server-wide limit it is a share of.

§

AnonymousAtCapacity

The anonymous caller is already holding its whole ceiling.

Its own variant, and not Refusal::PrincipalAtCapacity with the anonymous id in it, because the operator action is different in kind. A per-principal refusal names a client that can be found, telephoned or given a bigger share; this one says strangers are at their cap, which is either normal (a popular public repository) or the first sign of a scrape, and in neither case is the answer “raise the concurrency limit”. It also carries no active_principals, because there is exactly one anonymous principal and dividing anything by it would be theatre.

Fields

§limit: usize

The anonymous ceiling in force, i.e. Admission::max_anonymous. Unlike every other limit reported here this one is not governed or shared — it is the operator’s number, unmodified — which is exactly why it is worth printing: an operator who sees a refusal against 5 on a box with 200 free slots must be able to see immediately that a different knob did it.

§

KeyedReserve

The stranger asked for a slot inside the part of the box that only a keyed identity may hold (D23b).

Its own variant, and specifically not Refusal::AnonymousAtCapacity, because the two say opposite things about the machine and are fixed by opposite knobs. AnonymousAtCapacity means strangers are at their cap — it can fire on an idle box, and the only number that changes it is --max-anonymous-transfers. This one means the box is too busy to spend any of itself on a stranger: the anonymous ceiling is nowhere near reached, and lowering it would do nothing at all. The knob here is the server-wide limit, or the size of the box, or a browse replica.

It also carries no principal and no share, because it is not a statement about this caller at all: it is a statement about occupancy, and the only thing about the caller that entered into it was that it has no key.

Fields

§occupied: usize

Slots occupied as the gate’s own compare-and-swap observed them — the reserve rides inside that atomic (Governor::claim_reserving), so this is the number that actually made the decision and not a second reading taken nearby. Reported so an operator can see the decision rather than reconstruct it: occupied + reserve >= limit is the whole rule, visible in one line of log.

§limit: usize

The governed server-wide limit those slots are out of, i.e. wherever the CoDel controller has moved to inside its band. The configured number would be actively misleading here: the whole reason this gate exists is that the governed limit moves and the anonymous ceiling does not.

§reserve: usize

How many slots at the top of that limit are keyed-only, i.e. Admission::keyed_reserve. Printed because it is derived (CONTENTION_PERCENT) and therefore appears in no config file an operator could look it up in.

§

MemoryBudget

The server’s memory budget is already spoken for (gate 2).

A third reason, kept separate from Refusal::AtCapacity on purpose: an operator who reads “at capacity” raises the concurrency limit, and doing that here makes the problem worse. The numbers travel so the log says which knob to turn.

Fields

§class: OpClass

The class whose estimate did not fit.

§wanted: u64

What [OpClass::estimated_bytes] asked for.

§reserved: u64

What was reserved by operations already in flight.

§budget: u64

The configured budget.

§

Paused

The gate is PAUSED — every transfer is refused, not for want of a slot but because the server asked for a quiet moment: the runtime data-set growth drains the box before it unmounts /data (DATA-SET-GROWTH-FLOW.md §3 step 5, T1/T12). Carries no number because no number was hit; carries the reason, whose words the client reads. Set and cleared by Admission::pause / Admission::unpause — one gate, so all three git fronts pause together.

Fields

§pause: Pause

Why, and in which words.

Implementations§

Source§

impl Refusal

Source

pub fn client_message(&self) -> String

What the client is told, in its own protocol.

Says try again explicitly. “Server busy” with no instruction reads as a permanent failure to a human and to a CI log alike, and this one is transient by definition.

Source

pub const fn reason(&self) -> &'static str

The machine-readable reason, for a log’s reason field.

The sentence above is for the person holding the git prompt; this is for the operator filtering a log, and they need different things. Until the anonymous ceiling existed every refusal here was fairly described by one string — the box was out of something server-wide — and both fronts hard-coded admission-gate-full accordingly. That string is now actively misleading on the one refusal that can fire with the box nearly empty: an operator who greps admission-gate-full, sees a hit, and looks at 59 free slots concludes the gate is broken, which is exactly the “the limit exists but produces no signal an operator can act on” failure the unbounded listener was about, wearing a different hat.

Only the fronts that can actually see an anonymous caller use this. The gRPC control plane keeps its literal, because [gunnar_grpc::auth] refuses the anonymous principal outright: a reason there that could report anonymity would be describing a state that crate makes unreachable.

Trait Implementations§

Source§

impl Clone for Refusal

Source§

fn clone(&self) -> Self

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Copy for Refusal

Source§

impl Debug for Refusal

Source§

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

Formats the value using the given formatter. Read more
Source§

impl Display for Refusal

Source§

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

Formats the value using the given formatter. Read more
Source§

impl Eq for Refusal

Source§

impl PartialEq for Refusal

Source§

fn eq(&self, other: &Self) -> bool

Equality operator ==. Read more
1.0.0 (const: unstable) · Source§

fn ne(&self, other: &Rhs) -> bool

Inequality operator !=. Read more
Source§

impl StructuralPartialEq for Refusal

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> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<Q, K> Equivalent<K> for Q
where Q: Eq + ?Sized, K: Borrow<Q> + ?Sized,

Source§

fn equivalent(&self, key: &K) -> bool

Checks if this value is equivalent to the given key. Read more
Source§

impl<Q, K> Equivalent<K> for Q
where Q: Eq + ?Sized, K: Borrow<Q> + ?Sized,

Source§

fn equivalent(&self, key: &K) -> bool

Compare self to key and return true if they are equal.
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> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T> ToString for T
where T: Display + ?Sized,

Source§

fn to_string(&self) -> String

Converts the given value to a String. Read more
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