pub const fn throttle_decide(
state: u64,
now_ns: u64,
interval_ns: u64,
) -> Option<u64>Expand description
The whole rule, as a pure function. Both storages call this.
state is the site’s state word — NEVER for a site that has not
emitted, otherwise what an earlier call returned. Returns Some(next) iff a
record raised at now_ns should be EMITTED, and next is the word to store
in its place; None means suppressed and the word is left alone. Returning
the encoded word rather than a bare bool is what keeps the encoding in
ONE place: a caller cannot admit with this rule and then arm with a
different spelling of “last emitted” (issue 1152 was exactly that — the
arming step stored 1 for a clock reading 0, and the rule then measured
u64::MAX of elapsed time against it).
§Two clock pathologies, one rule (issue 1152)
- A WRAPPING clock (a platform counter rolling over, or a
u64derived from a 32-bit counter) must still measure real elapsed time across the wrap, so the elapsed time isnow - lastin modular arithmetic, neverlast + interval(which overflows to a tiny number and admits everything for the rest of the program). - A STUCK clock (a port whose clock is broken and reports a constant —
including
0, which is what a build without the platform clock reports) must admit ONCE and then never, because a stuck clock is exactly when a log flood is most likely. That needsnow == lastto read as zero elapsed, which a sentinel living in the timestamp domain cannot deliver: some real reading has to be displaced to keep the sentinel unambiguous, and a clock stuck on that reading then never equals what was stored.
The word is (last_ns << 1) | ARMED: the flag is bit 0 and the timestamp
keeps 63 bits above it. A clock that wraps at 2^64 also wraps at 2^63, so
reducing both the stored reading and the subtraction mod 2^63 measures
elapsed time exactly across the wrap — the only thing given up is that a
jump of exactly 2^63 ns (292 years) between two records reads as no time
at all.