Skip to main content

WarmingAllowance

Struct WarmingAllowance 

Source
pub struct WarmingAllowance { /* private fields */ }
Expand description

Bounds speculative warming losses per upstream source node.

See the module docs for the serve-vindicated accounting model.

§Poisoning

Every acquisition of state recovers the inner value rather than propagating the poison. The whole of each critical section is a HashMap entry insert, an Instant read (Instant::elapsed saturates rather than panicking), and saturating i64 arithmetic, so there is no reachable unwind and recovered state is never torn.

Recovering is also the safe direction on each of the three paths that take the lock, which is why it is uniform here rather than split per method. Skipping a Self::debit_speculative would let a source buy speculatively without paying the grief cap for it, and skipping the aggregator’s apply would strand a serve’s realized margin. Refusing on Self::available is the conservative direction for that one call, but it blocks every speculative buy node-wide for the process lifetime with no signal, which is a worse operational failure than the unreachable one it guards against.

Implementations§

Source§

impl WarmingAllowance

Source

pub fn new(budget: u64, refill_per_sec: u64) -> Self

Creates a new allowance tracker. A source with no recorded activity reads as fully available.

Source

pub fn available(&self, source: SourceId) -> bool

Reports whether source currently has any warming allowance left. A source with no recorded activity holds the full budget and is available; an existing ledger is available only while its allowance is still positive.

A zero budget disables warming (Self::enabled): every source reads as unavailable, including never-seen ones, so economic_ceiling never selects the warming regime and no speculative buy is authorized. Without this short-circuit a fresh source would read available (None => true) even with warming off, and buy at the market price for its first hash — the “zero budget disables warming” semantics would hold only after each source’s first buy created its bucket.

Source

pub const fn enabled(&self) -> bool

Whether speculative warming is configured at all. A zero budget disables it: every above-floor buy is refused and no source ever has a positive allowance to spend. Callers gate the “source blocked” telemetry on this so a node with warming deliberately off does not report every source as griefed down.

Source

pub fn blocked_source_count(&self) -> usize

How many sources currently hold no warming allowance — a spent ledger at or below zero once its time refill is projected forward. Read-only: it projects each bucket’s refill without persisting it (unlike Self::available, which refills in place), so a metrics scrape never mutates the ledger. Sampled onto decdn_warming_sources_blocked.

Reads zero when warming is disabled (Self::enabled), even if buckets linger from a config that previously ran warming on: with the budget at zero no source is being griefed down, so the gauge stays at zero across the reload rather than reporting every spent ledger as blocked.

Source

pub fn debit_speculative(&self, source: SourceId, hash: Hash, units: u64)

Debits source’s ledger for a speculative buy of hash and tags the hash with its source so a later serve can credit the right ledger.

The buy loop checks Self::available when it selects a candidate and debits only after the pull completes, so concurrent pulls from one source can each pass the check and drive the ledger below zero: the real spend past the allowance is every speculative buy still in flight when it crossed zero. The ledger is floored at -budget, so however far those buys overshoot, the source needs at most budget + 1 units of credit or refill to warm again. The floor bounds that recovery debt, not the spend.

The tag is published while the bucket lock is held, before the debit. The serve path reads the tag map without that lock, but every credit reaches the ledger through credit_source, which takes it. So a serve that sees the tag has its credit applied only after this debit, and a serve that misses the tag also precedes the debit. Publishing the tag outside the lock would let a credit land on a bucket this debit is about to create full, where the +budget cap discards it; publishing it after the debit would let a serve see a committed debit with no tag and drop its credit.

Source

pub fn forget(&self, hash: Hash)

Drops the hash-to-source tag, e.g. on cache eviction, so a stale hash can never credit a ledger again.

Trait Implementations§

Source§

impl Debug for WarmingAllowance

Source§

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

Formats the value using the given formatter. Read more

Auto Trait Implementations§

Blanket Implementations§

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<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<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> FutureExt for T

Source§

fn with_context(self, otel_cx: Context) -> WithContext<Self> ⓘ

Attaches the provided Context to this type, returning a WithContext wrapper. Read more
Source§

fn with_current_context(self) -> WithContext<Self> ⓘ

Attaches the current Context to this type, returning a WithContext wrapper. Read more
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> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ

Converts self into a Left variant of Either<Self, Self> if into_left is true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
where F: FnOnce(&Self) -> bool,

Converts self into a Left variant of Either<Self, Self> if into_left(&self) returns true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

impl<T> IntoRequest<T> for T

Source§

fn into_request(self) -> Request<T>

Wrap the input message T in a tonic::Request
Source§

impl<Unshared, Shared> IntoShared<Shared> for Unshared
where Shared: FromUnshared<Unshared>,

Source§

fn into_shared(self) -> Shared

Creates a shared type from an unshared type.
Source§

impl<L> LayerExt<L> for L

Source§

fn named_layer<S>(&self, service: S) -> Layered<<L as Layer<S>>::Service, S>
where L: Layer<S>,

Applies the layer to a service and wraps it in Layered.
Source§

impl<T> MaybeSend for T
where T: Send,

Source§

impl<T> PolicyExt for T
where T: ?Sized,

Source§

fn and<P, B, E>(self, other: P) -> And<T, P>
where T: Sized + Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns Action::Follow only if self and other return Action::Follow. Read more
Source§

fn or<P, B, E>(self, other: P) -> Or<T, P>
where T: Sized + Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns Action::Follow if either self or other returns Action::Follow. Read more
Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
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<V, T> VZip<V> for T
where V: MultiLane<T>,

Source§

fn vzip(self) -> V

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