Skip to main content

BalancerStateValues

Struct BalancerStateValues 

Source
pub struct BalancerStateValues {
    pub target_surb_buffer_size: AtomicU64,
    pub max_surbs_per_sec: AtomicU64,
    pub decay_duration_msec: AtomicU64,
    pub decay_volume_pct: AtomicU8,
    pub buffer_level: AtomicU64,
    pub sustain_on_return_path_loss: AtomicBool,
    pub counterparty_buffer_capacity: AtomicU64,
    pub return_path_degraded_until_ms: AtomicU64,
    pub counterparty_in_surb_distress: AtomicBool,
}
Expand description

Runtime state of the SurbBalancer.

Fields§

§target_surb_buffer_size: AtomicU64§max_surbs_per_sec: AtomicU64§decay_duration_msec: AtomicU64§decay_volume_pct: AtomicU8§buffer_level: AtomicU64§sustain_on_return_path_loss: AtomicBool

Whether this session opted into sustaining production through return-path loss.

§counterparty_buffer_capacity: AtomicU64

How many SURBs the counterparty can physically hold, or 0 when unknown.

The estimate is produced - consumed, and consumption is only observed once a reply arrives – so a return path that drops replies lets the believed level grow without bound. The counterparty’s store is a ring buffer that evicts the oldest entry on overflow, so everything above its capacity was discarded on arrival and was never a real level. Measured during an outage: 51 917 believed against a 15 000-entry store.

§Why evictions are not subtracted from the level

The counterparty reports its evictions (num_evicted_surbs on the incoming packet), so the level could be corrected to the exact truth instead of merely bounded here. It deliberately is not, because the clamp below is max(capacity, target) rather than capacity: a level inflated past a full buffer still climbs to the target and shuts organic production off, whereas an accurate level pins at the counterparty’s real capacity. If that capacity is below the target – which nothing prevents, since this figure is the local store size and the counterparty may be smaller – the accurate level never reaches the target, production never stops, and the buffer evicts forever. The imprecise estimate fails safe and the precise one does not, so the eviction count stays an observability signal.

§return_path_degraded_until_ms: AtomicU64

Milliseconds from the crate-internal EPOCH monotonic origin until which the return path counts as degraded.

A deadline rather than a flag: it is set by a layer that observes the return path and read here, and nothing is guaranteed to come back and clear it. Expiring on its own bounds the damage of a marker that is never withdrawn to a short over-production instead of a session that mints forever.

§counterparty_in_surb_distress: AtomicBool

Whether the counterparty’s last packet said it was running low on SURBs of its own.

A plain flag with no deadline, unlike return_path_degraded_until_ms above, because the two fail in opposite directions: a degraded-path marker that is never withdrawn makes this side mint forever, whereas a distress flag that is never withdrawn merely keeps organic production at one SURB per packet — the behaviour that predates the gate. A flag whose stuck state is the old behaviour does not need to expire.

It clears on its own in the normal case: the counterparty recomputes both SURB signals on every return packet and strips them once its pool recovers, so the next healthy packet resets this.

Last write wins, and the signal is recorded at dispatch – ahead of Session sequencing – so a reordered clean packet can clear a distress signal the counterparty sent after it. That costs the safety valve rather than the recovery: surb_decay subtracts from the level estimate on a timer regardless of what any packet says, so once the estimate falls back under target both this gate and the keep-alives reopen on their own.

How long that takes is a property of the configuration, not a guarantee of this type. It scales with the decay rate and with how far above target the estimate sits, and the max(capacity, target) clamp bounds the latter only while counterparty_buffer_capacity is known – its 0 (“unknown”) arm leaves the estimate unclamped. With decay switched off the estimate does not drain on its own at all, and only a fresh distress signal or observed consumption reopens the gate.

Sequencing the flag would buy a faster reopen, at the cost of making a hot-path signal depend on the Session’s reassembly.

Implementations§

Source§

impl BalancerStateValues

Source

pub fn new(cfg: SurbBalancerConfig) -> Self

Constructor from a SurbBalancerConfig.

Source

pub fn update(&self, cfg: &SurbBalancerConfig)

Performs update of the BalancerStateValues from the SurbBalancerConfig and enables it.

Source

pub fn set_counterparty_buffer_capacity(&self, capacity: u64)

Declares how many SURBs the counterparty’s store can hold, bounding the level estimate.

Taken from the session manager’s maximum_surb_buffer_size, which is the same capacity already used to clamp a counterparty’s requested target. Zero leaves the estimate unbounded.

Source

fn clamp_to_counterparty_capacity(&self, level: u64) -> u64

Caps level at what the counterparty can actually hold.

Never below the configured target: a target above the counterparty’s capacity is unreachable by construction, and clamping to capacity there would hold the error permanently negative and pin production at maximum forever – a worse failure than the unbounded estimate this exists to prevent. In that configuration the capacity figure is simply not usable for this session.

Source

pub fn observe_counterparty_signals(&self, signals: PacketSignals)

Records what the counterparty’s latest packet said about its own SURB supply.

Takes the whole signal set rather than a bool so the containment rule lives here: OutOfSurbs is a superset of SurbDistress on the wire, so contains catches both, whereas an equality match against SurbDistress would silently ignore the more severe of the two.

Source

pub fn organic_surbs_per_packet(&self) -> usize

Returns the number of organic SURBs to attach to an outgoing Session data packet.

Only the Entry uses this value. Return 0 when the estimated counterparty buffer has reached its target. Return 1 when balancing is disabled, the estimate is below target, or the counterparty signals SURB distress.

This method uses the raw buffer estimate. During return-path loss, a zero estimate correctly keeps organic SURB production enabled.

Source

pub fn mark_return_path_degraded(&self, grace: Duration)

Marks the return path as degraded for the next grace period.

Called by whichever layer can actually tell a dead return path from a quiet peer – from here the two are indistinguishable, since neither delivers replies. Re-marking simply extends the window.

Source

pub fn return_path_estimate_is_stale(&self) -> bool

Whether buffer_level is currently an instruction rather than a measurement.

While this holds, the controller deliberately writes 0 into the level to drive production to its maximum. That zero says “produce flat out”, not “the counterparty holds nothing”, so anything reading the level as a supply ceiling must consult this first or it will read the instruction as an order to send nothing.

True only when both the opt-in (sustain_on_return_path_loss) and live evidence (mark_return_path_degraded, within its window) are present: without the opt-in this is not our behaviour to change, and without evidence there is nothing to tell a dead return path from an idle one.

pub because it is not only the controller’s business — hence the emphasis above on what the flag does not mean. It is not a general “the return path is degraded” signal.

Source

fn should_sustain_through_return_path_loss(&self) -> bool

Source

pub fn as_config(&self) -> SurbBalancerConfig

Extracts the SurbBalancerConfig from the BalancerStateValues.

Source

pub fn is_disabled(&self) -> bool

Checks if SURB balancing is disabled (no target buffer size set).

Source

pub fn surb_decay(&self) -> Option<(Duration, f64)>

Extracts the SURB decay configuration from the BalancerStateValues.

Source

pub fn buffer_level(&self) -> u64

Gets the current estimated SURB buffer level.

Source

pub fn controller_bounds(&self) -> BalancerControllerBounds

Returns the current BalancerControllerBounds from the BalancerStateValues.

Trait Implementations§

Source§

impl Debug for BalancerStateValues

Source§

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

Formats the value using the given formatter. Read more
Source§

impl Default for BalancerStateValues

Source§

fn default() -> BalancerStateValues

Returns the “default value” for a type. Read more
Source§

impl From<SurbBalancerConfig> for BalancerStateValues

Source§

fn from(cfg: SurbBalancerConfig) -> Self

Converts to this type from the input type.

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
§

impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
where ST: ?Sized, DT: ?Sized,

§

impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
where ST: ?Sized, DT: ?Sized,

§

impl<T> Conv for T

§

fn conv<T>(self) -> T
where Self: Into<T>,

Converts self into T using Into<T>. Read more
§

impl<T> FmtForward for T

§

fn fmt_binary(self) -> FmtBinary<Self>
where Self: Binary,

Causes self to use its Binary implementation when Debug-formatted.
§

fn fmt_display(self) -> FmtDisplay<Self>
where Self: Display,

Causes self to use its Display implementation when Debug-formatted.
§

fn fmt_lower_exp(self) -> FmtLowerExp<Self>
where Self: LowerExp,

Causes self to use its LowerExp implementation when Debug-formatted.
§

fn fmt_lower_hex(self) -> FmtLowerHex<Self>
where Self: LowerHex,

Causes self to use its LowerHex implementation when Debug-formatted.
§

fn fmt_octal(self) -> FmtOctal<Self>
where Self: Octal,

Causes self to use its Octal implementation when Debug-formatted.
§

fn fmt_pointer(self) -> FmtPointer<Self>
where Self: Pointer,

Causes self to use its Pointer implementation when Debug-formatted.
§

fn fmt_upper_exp(self) -> FmtUpperExp<Self>
where Self: UpperExp,

Causes self to use its UpperExp implementation when Debug-formatted.
§

fn fmt_upper_hex(self) -> FmtUpperHex<Self>
where Self: UpperHex,

Causes self to use its UpperHex implementation when Debug-formatted.
§

fn fmt_list(self) -> FmtList<Self>
where &'a Self: for<'a> IntoIterator,

Formats each item in a sequence. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

§

impl<T> FutureExt for T

§

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

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

fn with_current_context(self) -> WithContext<Self>

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

impl<T> Instrument for T

§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided [Span], returning an Instrumented wrapper. Read more
§

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
§

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

§

fn pipe<R>(self, func: impl FnOnce(Self) -> R) -> R
where Self: Sized,

Pipes by value. This is generally the method you want to use. Read more
§

fn pipe_ref<'a, R>(&'a self, func: impl FnOnce(&'a Self) -> R) -> R
where R: 'a,

Borrows self and passes that borrow into the pipe function. Read more
§

fn pipe_ref_mut<'a, R>(&'a mut self, func: impl FnOnce(&'a mut Self) -> R) -> R
where R: 'a,

Mutably borrows self and passes that borrow into the pipe function. Read more
§

fn pipe_borrow<'a, B, R>(&'a self, func: impl FnOnce(&'a B) -> R) -> R
where Self: Borrow<B>, B: 'a + ?Sized, R: 'a,

Borrows self, then passes self.borrow() into the pipe function. Read more
§

fn pipe_borrow_mut<'a, B, R>( &'a mut self, func: impl FnOnce(&'a mut B) -> R, ) -> R
where Self: BorrowMut<B>, B: 'a + ?Sized, R: 'a,

Mutably borrows self, then passes self.borrow_mut() into the pipe function. Read more
§

fn pipe_as_ref<'a, U, R>(&'a self, func: impl FnOnce(&'a U) -> R) -> R
where Self: AsRef<U>, U: 'a + ?Sized, R: 'a,

Borrows self, then passes self.as_ref() into the pipe function.
§

fn pipe_as_mut<'a, U, R>(&'a mut self, func: impl FnOnce(&'a mut U) -> R) -> R
where Self: AsMut<U>, U: 'a + ?Sized, R: 'a,

Mutably borrows self, then passes self.as_mut() into the pipe function.
§

fn pipe_deref<'a, T, R>(&'a self, func: impl FnOnce(&'a T) -> R) -> R
where Self: Deref<Target = T>, T: 'a + ?Sized, R: 'a,

Borrows self, then passes self.deref() into the pipe function.
§

fn pipe_deref_mut<'a, T, R>( &'a mut self, func: impl FnOnce(&'a mut T) -> R, ) -> R
where Self: DerefMut<Target = T> + Deref, T: 'a + ?Sized, R: 'a,

Mutably borrows self, then passes self.deref_mut() into the pipe function.
§

impl<T> Pointable for T

§

const ALIGN: usize

The alignment of pointer.
§

type Init = T

The type for initializers.
§

unsafe fn init(init: <T as Pointable>::Init) -> usize

Initializes a with the given initializer. Read more
§

unsafe fn deref<'a>(ptr: usize) -> &'a T

Dereferences the given pointer. Read more
§

unsafe fn deref_mut<'a>(ptr: usize) -> &'a mut T

Mutably dereferences the given pointer. Read more
§

unsafe fn drop(ptr: usize)

Drops the object pointed to by the given pointer. Read more
§

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

§

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
§

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
§

impl<T> Read<Exclusive, BecauseExclusive> for T
where T: ?Sized,

Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
§

impl<T> Tap for T

§

fn tap(self, func: impl FnOnce(&Self)) -> Self

Immutable access to a value. Read more
§

fn tap_mut(self, func: impl FnOnce(&mut Self)) -> Self

Mutable access to a value. Read more
§

fn tap_borrow<B>(self, func: impl FnOnce(&B)) -> Self
where Self: Borrow<B>, B: ?Sized,

Immutable access to the Borrow<B> of a value. Read more
§

fn tap_borrow_mut<B>(self, func: impl FnOnce(&mut B)) -> Self
where Self: BorrowMut<B>, B: ?Sized,

Mutable access to the BorrowMut<B> of a value. Read more
§

fn tap_ref<R>(self, func: impl FnOnce(&R)) -> Self
where Self: AsRef<R>, R: ?Sized,

Immutable access to the AsRef<R> view of a value. Read more
§

fn tap_ref_mut<R>(self, func: impl FnOnce(&mut R)) -> Self
where Self: AsMut<R>, R: ?Sized,

Mutable access to the AsMut<R> view of a value. Read more
§

fn tap_deref<T>(self, func: impl FnOnce(&T)) -> Self
where Self: Deref<Target = T>, T: ?Sized,

Immutable access to the Deref::Target of a value. Read more
§

fn tap_deref_mut<T>(self, func: impl FnOnce(&mut T)) -> Self
where Self: DerefMut<Target = T> + Deref, T: ?Sized,

Mutable access to the Deref::Target of a value. Read more
§

fn tap_dbg(self, func: impl FnOnce(&Self)) -> Self

Calls .tap() only in debug builds, and is erased in release builds.
§

fn tap_mut_dbg(self, func: impl FnOnce(&mut Self)) -> Self

Calls .tap_mut() only in debug builds, and is erased in release builds.
§

fn tap_borrow_dbg<B>(self, func: impl FnOnce(&B)) -> Self
where Self: Borrow<B>, B: ?Sized,

Calls .tap_borrow() only in debug builds, and is erased in release builds.
§

fn tap_borrow_mut_dbg<B>(self, func: impl FnOnce(&mut B)) -> Self
where Self: BorrowMut<B>, B: ?Sized,

Calls .tap_borrow_mut() only in debug builds, and is erased in release builds.
§

fn tap_ref_dbg<R>(self, func: impl FnOnce(&R)) -> Self
where Self: AsRef<R>, R: ?Sized,

Calls .tap_ref() only in debug builds, and is erased in release builds.
§

fn tap_ref_mut_dbg<R>(self, func: impl FnOnce(&mut R)) -> Self
where Self: AsMut<R>, R: ?Sized,

Calls .tap_ref_mut() only in debug builds, and is erased in release builds.
§

fn tap_deref_dbg<T>(self, func: impl FnOnce(&T)) -> Self
where Self: Deref<Target = T>, T: ?Sized,

Calls .tap_deref() only in debug builds, and is erased in release builds.
§

fn tap_deref_mut_dbg<T>(self, func: impl FnOnce(&mut T)) -> Self
where Self: DerefMut<Target = T> + Deref, T: ?Sized,

Calls .tap_deref_mut() only in debug builds, and is erased in release builds.
§

impl<T> TryConv for T

§

fn try_conv<T>(self) -> Result<T, Self::Error>
where Self: TryInto<T>,

Attempts to convert self into T using TryInto<T>. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

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.
§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

§

fn vzip(self) -> V

§

impl<T> WithSubscriber for T

§

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
§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a [WithDispatch] wrapper. Read more