Skip to main content

charge

Function charge 

Source
pub fn charge(
    state: &mut BucketState,
    rate_bps: Option<u64>,
    burst_bytes: u64,
    bytes: u64,
    now: Instant,
) -> Grant
Expand description

Charge bytes against a bucket and say whether the unit may go.

Pure with respect to the clocknow is a parameter and no clock is read, following release_timer::plan. state is refilled to now before the decision and debited only on Grant::Now; every refusal costs nothing, so re-charging the same unit after its deadline is correct rather than double-billing.

The bound this function upholds, exactly: over any interval, the bytes it grants never exceed rate_bps * elapsed + burst_bytes. That is what makes the rate claim provable arithmetic rather than a measurement, and the_bucket_never_grants_above_rate_plus_burst proves it over 10 001 fabricated steps.

§It is not the bound the shaper upholds

Stated here because the difference is a factor of thousands and a reader of this line will otherwise assume the wrong one. PendingQueue’s release seam checks the unit’s max_hold clamp before it calls acquire, and under the default Expiry::Deliver a clamped unit goes out without a bucket being consulted at all — that is what “a 0-bps class still delivers, at max_hold” means. So the end-to-end ceiling is

min(rate_bps * elapsed + burst_bytes,   <- this function
    depth / max_hold * elapsed)         <- the clamp, per stream

Measured, with rate_bps: Some(0), depth_bytes: 4096 and max_hold: 300 ms: a bucket configured at 0 bytes/s sustained ~25 kB/s. The clamp is the deliberate non-destructive default — a starved unit is delivered late rather than dropped — and not a defect, but a fixture that means to observe this function’s bound has to pin max_hold far enough out that the clamp cannot bind inside its sampling window — which is why every starvation fixture is required to name it.

now is expected to be monotonic. A now earlier than the last one refills nothing and does not rewind the bucket’s clock, so an out-of-order caller under-grants rather than manufacturing tokens.