Skip to main content

Module quota

Module quota 

Source
Expand description

Per-user quotas (D37): how much of the node one credential may hold.

D33 gave the node a record of who did what (crate::limits::Access) and a bound on how often anyone did it (crate::limits::RateLimiter). Neither bounds how large one request may be or how much durable state one user may accumulate, and a rate limit does not imply either: one push a minute is still an unbounded pack, and one workspace a minute is still unbounded disk.

Two ceilings, sharing only the identity they key on — the authenticated username string, exactly as crate::limits::RateLimiter::check keys on it. Nothing here reads the auth file or asks any user store whether a name exists: the string arrives from the request’s credentials and is used as an opaque key.

§Where the push ceiling is enforced, and why it is there

read_bounded runs on the request thread before git http-backend is spawned, which is the whole design rather than an implementation detail. Git applies no ref until the pre-receive hook exits zero, so a size check inside that hook would already have submitted ops for the refs it did reach — ops for refs git will never create — and would have to drive the compensating retraction pass Node::create_repo documents. Refusing before the CGI starts means no hook ran, no op was submitted, and the retraction path is not entered at all. The bound is on the transfer; the sequencer never learns the push was attempted.

The cost is stated rather than hidden: an over-limit body is drained to a sink before the refusal is written, so the client always reads a 413 instead of a broken connection, and so tiny_http’s own reader does not try to swallow the remainder in one allocation on drop. The bytes still cross the network. What the ceiling buys is that they never reach memory beyond the ceiling, never reach git, and never reach the log.

§Where the workspace ceiling gets its count, and why that survives a

restart

WorkspaceTally is not a new persisted file. It is a projection folded out of the op log during the replay the platform already performs at startup, keyed on the attribution channel each workspace-creating entry already carries in its signature-covered channel field. the build log left this item out of D33 calling a surviving tally “a persisted-state question”; it is one, and the answer is that the persisted state already exists and needed a reader rather than a writer. A restart rebuilds the tally from the same log that rebuilds the view, with no new format, no new file and no second durability barrier.

§Examples

use choir_node::quota::{channel_for, Quotas};

// The tally's key is derived from the authenticated username and
// nothing else.
assert_eq!(channel_for("alice"), "git/alice");

// Both ceilings are off unless the operator sets them.
let none = Quotas::default();
assert!(none.push_bytes.is_none() && none.workspaces.is_none());
assert!(!none.is_active());

Structs§

Quotas
The operator’s per-user ceilings. Either may be left unset, and unset means unlimited — the same shape as the D33 rate-limit flags.
WorkspaceTally
Which channel holds which workspace, folded from the op log.

Enums§

Body
What read_bounded found in a request body.

Functions§

channel_for
The attribution channel a request-authenticated user’s operations are submitted under.
read_bounded
Reads a request body, stopping at limit bytes.