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
impl BudgetEngine
pub fn new() -> Self
Sourcepub fn set_max_reserved_microcents(&self, tenant_id: &str, max_microcents: i64)
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.
Sourcepub fn try_set_max_reserved_microcents(
&self,
tenant_id: &str,
max_microcents: i64,
) -> Result<(), BudgetConfigurationError>
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.
Sourcepub fn snapshot_version(&self) -> u64
pub fn snapshot_version(&self) -> u64
Last emitted tagged recovery allocator fence, or zero before any snapshot.
Sourcepub fn total_committed_microcents(&self) -> i64
pub fn total_committed_microcents(&self) -> i64
Sum of lifetime committed_microcents across all tenants.
Sourcepub fn try_total_committed_microcents(&self) -> Result<i64, ConservationStatus>
pub fn try_total_committed_microcents(&self) -> Result<i64, ConservationStatus>
Checked sum of lifetime committed_microcents across all tenants.
Sourcepub fn committed_since_last_certificate(&self) -> i64
pub fn committed_since_last_certificate(&self) -> i64
Committed total since the last financial certificate was issued.
Sourcepub fn restore_from_snapshot(
&self,
snap: BudgetSnapshot,
) -> Result<(), RestoreError>
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.
Sourcepub fn restore_from_recovery_snapshot(
&self,
snap: BudgetSnapshot,
) -> Result<(), RecoverySnapshotError>
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.
Sourcepub fn ensure_tenant(&self, tenant_id: &str, budget_microcents: i64)
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).
Sourcepub fn try_ensure_tenant(
&self,
tenant_id: &str,
budget_microcents: i64,
) -> Result<(), BudgetConfigurationError>
pub fn try_ensure_tenant( &self, tenant_id: &str, budget_microcents: i64, ) -> Result<(), BudgetConfigurationError>
Checked tenant initialization for external trust boundaries.
Sourcepub fn top_up_tenant(
&self,
tenant_id: &str,
amount_microcents: i64,
) -> TopUpResult
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.
Sourcepub fn initial_microcents(&self, tenant_id: &str) -> Option<i64>
pub fn initial_microcents(&self, tenant_id: &str) -> Option<i64>
Total budget ever granted to a tenant (ensure_tenant + top-ups).
Sourcepub fn committed_microcents(&self, tenant_id: &str) -> Option<i64>
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.
Sourcepub fn reserved_microcents(&self, tenant_id: &str) -> i64
pub fn reserved_microcents(&self, tenant_id: &str) -> i64
Sum of active reservation holds for a tenant.
Sourcepub fn snapshot(&self) -> BudgetSnapshot
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.
Sourcepub fn try_snapshot(&self) -> Result<BudgetSnapshot, SnapshotAllocatorError>
pub fn try_snapshot(&self) -> Result<BudgetSnapshot, SnapshotAllocatorError>
Capture a snapshot, failing closed instead of repeating an allocator fence.
Sourcepub fn verify_conservation(&self) -> ConservationStatus
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.
Sourcepub fn remaining_microcents(&self, tenant_id: &str) -> Option<i64>
pub fn remaining_microcents(&self, tenant_id: &str) -> Option<i64>
Remaining budget for a tenant in microcents.
Sourcepub fn try_reserve(
&self,
tenant_id: &str,
cost_microcents: i64,
) -> (BudgetReservation, Option<u64>)
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.
Sourcepub fn commit(
&self,
reservation_id: u64,
actual_microcents: i64,
) -> BudgetSettlement
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.
Sourcepub fn release(&self, reservation_id: u64) -> BudgetSettlement
pub fn release(&self, reservation_id: u64) -> BudgetSettlement
Release a reservation, returning the full reserved amount to the tenant’s budget.
Sourcepub fn tenant_count(&self) -> usize
pub fn tenant_count(&self) -> usize
Number of registered tenants.
Sourcepub fn active_reservations(&self) -> usize
pub fn active_reservations(&self) -> usize
Number of active (uncommitted, unreleased) reservations.