Skip to main content

BudgetEngine

Struct BudgetEngine 

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

Atomic budget engine.

CAS-based balance updates on Arc<AtomicI64> — the atomic is cloned out of the map before the CAS loop, so no lock is held during the contended operation. Metadata maps are mutex-protected; each operation acquires only the locks it needs. restore_from_snapshot is exclusive recovery — not concurrent with hot-path ops.

Implementations§

Source§

impl BudgetEngine

Source

pub fn new() -> Self

Source

pub fn set_max_reserved_microcents(&self, tenant_id: &str, max_microcents: i64)

Set a per-tenant exposure cap on future reservation holds (0 removes the cap).

Updates are serialized against reservation admission. Lowering a cap is prospective: existing holds are not revoked, while every admission that linearizes after this method returns observes the new cap.

Source

pub fn try_set_max_reserved_microcents( &self, tenant_id: &str, max_microcents: i64, ) -> Result<(), BudgetConfigurationError>

Checked exposure-cap update. Zero removes the cap; negative values are rejected.

Source

pub fn snapshot_version(&self) -> u64

Last emitted tagged recovery allocator fence, or zero before any snapshot.

Source

pub fn total_committed_microcents(&self) -> i64

Sum of lifetime committed_microcents across all tenants.

Source

pub fn try_total_committed_microcents(&self) -> Result<i64, ConservationStatus>

Checked sum of lifetime committed_microcents across all tenants.

Source

pub fn committed_since_last_certificate(&self) -> i64

Committed total since the last financial certificate was issued.

Source

pub fn restore_from_snapshot( &self, snap: BudgetSnapshot, ) -> Result<(), RestoreError>

Rebuild tenant balances from a validated snapshot (no active or ghost reservations).

Must be called during exclusive recovery — no concurrent try_reserve, commit, release, or top_up_tenant on this engine. Concurrent hot-path operations may hold cloned state across a clear/replace and corrupt restored ledgers.

Source

pub fn restore_from_recovery_snapshot( &self, snap: BudgetSnapshot, ) -> Result<(), RecoverySnapshotError>

Restore with precise recovery-format diagnostics.

Use this at new trust boundaries. The compatibility restore_from_snapshot method retains its 0.5.x error type and therefore cannot name the legacy-format case.

Source

pub fn ensure_tenant(&self, tenant_id: &str, budget_microcents: i64)

Initialize a tenant with a budget in microcents.

Idempotent — calling with an existing tenant does nothing (no top-up). Use top_up_tenant to add funds later. initial_microcents is fixed at creation for audit binding; top-ups extend it.

Negative budget_microcents is rejected (no-op).

Source

pub fn try_ensure_tenant( &self, tenant_id: &str, budget_microcents: i64, ) -> Result<(), BudgetConfigurationError>

Checked tenant initialization for external trust boundaries.

Source

pub fn top_up_tenant( &self, tenant_id: &str, amount_microcents: i64, ) -> TopUpResult

Add funds to an existing tenant (extends initial and remaining equally).

Does not reset committed_microcents (lifetime spend is preserved). Returns TopUpResult::MissingTenant if the tenant was never created.

Source

pub fn initial_microcents(&self, tenant_id: &str) -> Option<i64>

Total budget ever granted to a tenant (ensure_tenant + top-ups).

Source

pub fn committed_microcents(&self, tenant_id: &str) -> Option<i64>

Cumulative lifetime spend for a tenant (monotonic; increases on each successful commit).

This is not “currently in-flight committed amount” — active holds live in reserved_microcents.

Source

pub fn reserved_microcents(&self, tenant_id: &str) -> i64

Sum of active reservation holds for a tenant.

Source

pub fn snapshot(&self) -> BudgetSnapshot

Capture a point-in-time ledger snapshot (mutex read — not on hot path).

Lock order: reservations → budgets → initials → committed (matches hot path). This takes the exclusive checkpoint guard, so it waits for in-flight mutations. std::sync::RwLock gives writers no priority on every platform, so a sustained mutation stream can delay a snapshot.

§Panics

Panics when the reservation allocator is exhausted. Prefer Self::try_snapshot at API boundaries that must surface that error.

Source

pub fn try_snapshot(&self) -> Result<BudgetSnapshot, SnapshotAllocatorError>

Capture a snapshot, failing closed instead of repeating an allocator fence.

Source

pub fn verify_conservation(&self) -> ConservationStatus

Verify conservation on a point-in-time snapshot.

The snapshot gate waits for in-flight mutations before the frozen view is read.

Source

pub fn remaining_microcents(&self, tenant_id: &str) -> Option<i64>

Remaining budget for a tenant in microcents.

Source

pub fn try_reserve( &self, tenant_id: &str, cost_microcents: i64, ) -> (BudgetReservation, Option<u64>)

Reserve budget atomically using CAS.

Returns (BudgetReservation::Reserved { .. }, Some(id)) on success, or (BudgetReservation::Insufficient { .. }, None) if the tenant doesn’t have enough balance. Zero or negative amounts are rejected.

Source

pub fn commit( &self, reservation_id: u64, actual_microcents: i64, ) -> BudgetSettlement

Commit a reservation with actual cost. Surplus is refunded.

On successful commit, committed_microcents increases by actual_microcents (lifetime cumulative).

Overrun path: if actual_microcents > reserved, the engine debits the difference. If the tenant cannot afford the overrun, Overrun is returned, the reservation is re-inserted, and the original reserved amount stays deducted (no refund). This is intentional — refunding on failed overrun would violate conservation (create money). Call release to return the hold to spendable balance.

Source

pub fn release(&self, reservation_id: u64) -> BudgetSettlement

Release a reservation, returning the full reserved amount to the tenant’s budget.

Source

pub fn tenant_count(&self) -> usize

Number of registered tenants.

Source

pub fn active_reservations(&self) -> usize

Number of active (uncommitted, unreleased) reservations.

Trait Implementations§

Source§

impl Default for BudgetEngine

Source§

fn default() -> Self

Returns the “default value” for a type. 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, 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> 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, <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.