pub enum OpClass {
LsRemote,
Fetch,
Clone,
Push,
Gc,
}Expand description
Which kind of user-level git operation is being admitted.
The classes exist for one reason: a sojourn measured across a mixed queue is a number about whichever operation happened to be slowest, so the delay signal must be split even though the queue is not.
Variants§
LsRemote
A ref advertisement and nothing else. The canary: fastest, cheapest, and the first to notice a queue that has started to stand.
Fetch
An incremental fetch — a negotiated pack over an existing history.
Clone
A full clone. The expensive one, in time and (today, badly) in memory.
Push
A push, including LFS upload.
Gc
Repository maintenance.
Implementations§
Source§impl OpClass
impl OpClass
Sourcepub const ALL: [OpClass; 5]
pub const ALL: [OpClass; 5]
Every class, in index order. The per-class arrays are sized from this, so a new variant that is not added here fails to compile rather than silently sharing another class’s window.
Sourcepub const fn target(self) -> Duration
pub const fn target(self) -> Duration
The sojourn this class may stand at before the shared limit shrinks.
Half the class’s measured median service time
(measured on the reference desktop,
2026-08-13): a client of
this class may be made to wait at most long enough to add 50 % to its own
latency. That rule, not a table of round numbers, is what stops a slow
class from shrinking the limit on a fast class’s behalf — and it lands
OpClass::LsRemote exactly on TARGET, because its measured median
is 10 ms.
Sourcepub const fn admission_bytes(self) -> u64
pub const fn admission_bytes(self) -> u64
What this class reserves at admission, before it knows its size.
§This used to be the whole footprint, and that was the ceiling
Until 2026-08-30 this returned a per-class constant equal to the whole
operation’s measured peak — 320 MiB for a push, 2 GiB for a clone —
and MemoryLedger refused anything that did not fit in
DEFAULT_MEMORY_BUDGET_BYTES. That is an arithmetic ceiling nobody
chose: 8 GiB / 320 MiB = 25 concurrent pushes on any box, whatever
its RAM, and a three-object push-create reserved exactly as much as a
linux.git mirror.
MEASURED on the native desktop rig (gunnar-solo pinned to 4 cpus / 8 GiB,
2026-08-30): 500 push-creates at 64 concurrent clients → 118–132 of
them refused MemoryBudget while the server’s RSS never passed
1.6 GB of its 8 GiB. The gate was refusing three quarters of the work to
protect a budget that was 20 % used.
§So the reservation starts small and GROWS with the bytes on the wire
This is the entry cost — the session, the state machine, the ref
advertisement, the first buffers — and it is what admission is decided
on. Everything proportional to the transfer is added afterwards by
crate::AdmissionGuard::reserve_more, which the transport calls as
the pack actually arrives (WIRE_MEMORY_NUMERATOR). A gate that
charges a small push for a large one refuses work the box can do; a
gate that never charges the large one takes the box down. Charging what
has actually moved is the only rule that is right in both directions.
The numbers below are marginal RSS per concurrent transfer, measured on
the same rig by walking the concurrency up with the gate wide open
(rss-slope.tsv, a scratch capture outside the repository), rounded up
to the next power of
two.
Sourcepub const fn lane(self) -> Lane
pub const fn lane(self) -> Lane
The lane this class is metered in.
One queue is still one queue, but a lane may not be starved by another:
an ls-remote that costs 4 MiB and 10 ms must not wait behind an 8 GiB
mirror push, and on a saturated box it did — every class shared one
counter against one limit, so a push storm took every slot.
Three lanes, because there are three cost shapes: the ref advertisement (no pack), a read (a pack out of the store, mostly page cache), and a write (a pack in, plus the indexer behind it).
Sourcepub fn for_ssh_service(service: GitService) -> OpClass
pub fn for_ssh_service(service: GitService) -> OpClass
The class an SSH exec request belongs to.
§What SSH cannot tell you, and it matters
clone, fetch and ls-remote are the same exec line:
git-upload-pack '<path>'. Which of the three it turns out to be is
decided later, by the protocol-v2 command the client sends inside the
stream (ls-refs versus fetch), and by whether the client had any
history to negotiate from. The admission gate runs before any of that,
by design — the entire value of this gate is refusing before the cost is
paid.
So over SSH, git-upload-pack is classified OpClass::Fetch: the
middle of the three, chosen deliberately rather than by accident.
Classifying it as Clone would give every ls-remote a 2 GiB
reservation and a 186 ms delay target; as LsRemote it would give every
clone a 4 MiB reservation and a 5 ms target, which is the poisoned signal
this module exists to avoid.
Callers that do know — the HTTP smart transport, which sees
GET /info/refs separately from POST /git-upload-pack, and gunnar gc,
which is not a transport at all — pass the exact class to
Admission::try_admit instead of going
through this function.
Trait Implementations§
impl Copy for OpClass
impl Eq for OpClass
Source§impl Ord for OpClass
impl Ord for OpClass
1.21.0 (const: unstable) · Source§fn max(self, other: Self) -> Selfwhere
Self: Sized,
fn max(self, other: Self) -> Selfwhere
Self: Sized,
1.21.0 (const: unstable) · Source§fn min(self, other: Self) -> Selfwhere
Self: Sized,
fn min(self, other: Self) -> Selfwhere
Self: Sized,
Source§impl PartialOrd for OpClass
impl PartialOrd for OpClass
impl StructuralPartialEq for OpClass
Auto Trait Implementations§
impl Freeze for OpClass
impl RefUnwindSafe for OpClass
impl Send for OpClass
impl Sync for OpClass
impl Unpin for OpClass
impl UnsafeUnpin for OpClass
impl UnwindSafe for OpClass
Blanket Implementations§
impl<T> Allocation for T
Source§impl<'a, T, E> AsTaggedExplicit<'a, E> for Twhere
T: 'a,
impl<'a, T, E> AsTaggedExplicit<'a, E> for Twhere
T: 'a,
Source§impl<'a, T, E> AsTaggedImplicit<'a, E> for Twhere
T: 'a,
impl<'a, T, E> AsTaggedImplicit<'a, E> for Twhere
T: 'a,
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
impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
Source§impl<Q, K> Comparable<K> for Q
impl<Q, K> Comparable<K> for Q
Source§impl<Q, K> Equivalent<K> for Q
impl<Q, K> Equivalent<K> for Q
Source§impl<Q, K> Equivalent<K> for Q
impl<Q, K> Equivalent<K> for Q
Source§fn equivalent(&self, key: &K) -> bool
fn equivalent(&self, key: &K) -> bool
key and return true if they are equal.