Skip to main content

MemoryStore

Struct MemoryStore 

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

The in-memory reference backend: every store trait behind one mutex.

It implements LeaseAllocator, SnapshotSource, UsageSink, AdminStore, KeyDirectory, KeySource and StoreHealth with the settlement rules every backend must reproduce. It never deletes a record, so it suits development, tests and demos but not long-running load; see the module documentation.

Implementations§

Source§

impl MemoryStore

Source

pub fn new(policy: GrantPolicy) -> Result<Arc<Self>, GrantPolicyError>

Create an empty store that sizes grants with policy.

§Errors

GrantPolicyError when policy fails GrantPolicy::validate.

Source

pub fn create_account(&self, config: AccountConfig)

Test/bootstrap convenience: create a fresh account, panicking on a duplicate. Production paths use AdminStore::create_account.

Source

pub fn try_create_account( &self, config: AccountConfig, ) -> Result<(), CreateAccountError>

Create an account. Never destructive: an existing account (with its balance, ledger totals, fencing sequence, and leases) is left untouched and the caller told (review finding GL-7).

Source

pub fn deposit( &self, account: AccountId, units: CostUnits, ) -> Result<(), AllocateError>

Add balance to an existing account (top-up).

Source

pub fn publish_snapshot( &self, principal: Principal, snapshot: PublishableSnapshot, ) -> Result<(), PublishSnapshotError>

Bind (or replace) a principal’s compiled snapshot and push it to subscribers. Generation-monotonic: a replayed or reordered publish carrying an older (or equal) generation is a no-op — matching the Postgres backend, which enforces the same rule in its upsert (review finding GL-5’s backend-divergence note).

Source

pub fn remove_snapshot(&self, principal: Principal)

Tombstone a principal’s live snapshot at its current generation and push the revocation to subscribers. A principal with no snapshot, or one already tombstoned, is left unchanged and nothing is pushed.

Test/bootstrap convenience beside AdminStore::remove_snapshot, which also returns the audit receipt.

Source

pub fn conservation(&self, account: AccountId) -> Option<Conservation>

The sums are recomputed from the lease records every time. The index narrows which records are read (GL-23) and is never the source of the numbers: this function exists to catch ledger bugs, and one that read a running total maintained by the same writers that might be wrong could not catch them.

Source

pub fn usage_recorded(&self, account: AccountId) -> CostUnits

Every usage unit accepted for account: on active and settled leases, and as overage. Zero for an unknown account.

Source

pub fn settled_event(&self, request_id: RequestId) -> Option<UsageEvent>

The event this store settled for request_id, if it settled one.

The reference implementation keeps whole events — the idempotency map is keyed by request and holds the value — so this reads back what was actually billed rather than a projection of it. PostgresStore keeps only the columns it needs and has no equivalent, which is why a backend-parity assertion on a stored field reads that backend’s column directly instead.

Exists for inspection and tests, beside usage_recorded. It is not part of UsageSink: no request-path code reads settled events back.

Source

pub fn balance(&self, account: AccountId) -> CostUnits

account’s spendable balance, allowance plus top-up, excluding units out on lease. Zero for an unknown account.

Source

pub fn stored_records(&self) -> StoredRecords

What this backend is currently holding — see StoredRecords, and the module docs for why two of the three only ever climb.

Trait Implementations§

Source§

impl AdminStore for MemoryStore

Source§

fn create_account<'life0, 'async_trait>( &'life0 self, config: AccountConfig, ) -> Pin<Box<dyn Future<Output = Result<AdminReceipt<()>, CreateAccountError>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait,

Create an account from config, with its opening balance deposited as a top-up and its fencing sequence starting at one. Read more
Source§

fn create_provisioned_account<'life0, 'async_trait>( &'life0 self, account: AccountId, ) -> Pin<Box<dyn Future<Output = Result<AdminReceipt<()>, CreateAccountError>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait,

Create an account on behalf of a provisioner (#39): zero balance, AccountStatus::Suspended, CapacityClass::BestEffort, and AdminAuthority::Provisioner as both its origin and the author of its status. Read more
Source§

fn deposit<'life0, 'async_trait>( &'life0 self, account: AccountId, units: CostUnits, ) -> Pin<Box<dyn Future<Output = Result<AdminReceipt<()>, AllocateError>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait,

Add units to an existing account as a top-up, which survives period boundaries, raising its balance and its deposited total together. Read more
Source§

fn set_budget_schedule<'life0, 'async_trait>( &'life0 self, account: AccountId, schedule: Option<BudgetSchedule>, ) -> Pin<Box<dyn Future<Output = Result<AdminReceipt<()>, BudgetError>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait,

Give an account a periodic allowance, or take it away. Read more
Source§

fn roll_due_periods<'life0, 'async_trait>( &'life0 self, now: Timestamp, limit: NonZeroUsize, ) -> Pin<Box<dyn Future<Output = Result<RolloverBatch, StoreError>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait,

Cross the period boundary for up to limit accounts that are past it: expire each closed period’s unspent allowance and deposit the next one, one transaction per batch. Read more
Source§

fn set_account_status<'life0, 'async_trait>( &'life0 self, account: AccountId, status: AccountStatus, ) -> Pin<Box<dyn Future<Output = Result<AdminReceipt<StatusChange>, SetStatusError>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait,

Set an existing account’s administrative status, in one transaction: the ledger’s status, and a republication of every live snapshot of that account carrying the new status at generation + 1. Read more
Source§

fn activate_provisioned<'life0, 'async_trait>( &'life0 self, account: AccountId, ) -> Pin<Box<dyn Future<Output = Result<AdminReceipt<StatusChange>, SetStatusError>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait,

Activate an account on behalf of a provisioner (#39), under the same serialization point and with the same republication as set_account_status. Read more
Source§

fn set_capacity_class<'life0, 'async_trait>( &'life0 self, account: AccountId, class: CapacityClass, ) -> Pin<Box<dyn Future<Output = Result<AdminReceipt<StatusChange>, SetStatusError>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait,

Set an existing account’s execution-capacity class, in one transaction: the ledger’s class, and a republication of every live snapshot of that account carrying the new class at generation + 1 (GL-99). Read more
Source§

fn publish_snapshot<'life0, 'async_trait>( &'life0 self, principal: Principal, snapshot: PublishableSnapshot, ) -> Pin<Box<dyn Future<Output = Result<AdminReceipt<()>, PublishSnapshotError>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait,

Publish a principal’s compiled snapshot. Read more
Source§

fn account_view<'life0, 'async_trait>( &'life0 self, account: AccountId, ) -> Pin<Box<dyn Future<Output = Result<Option<AccountView>, StoreError>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait,

One account’s administrative state, or None if no such account (GL-121). Read more
Source§

fn remove_snapshot<'life0, 'async_trait>( &'life0 self, principal: Principal, ) -> Pin<Box<dyn Future<Output = Result<AdminReceipt<()>, StoreError>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait,

Withdraw a principal’s snapshot by tombstoning it at its current generation, and push the revocation to subscribers. The tombstone is durable, so no positive snapshot at or below that generation can resurrect the principal (INVARIANTS.md 15). Read more
Source§

impl KeyDirectory for MemoryStore

Source§

fn credential_activity<'life0, 'life1, 'async_trait>( &'life0 self, keys: &'life1 [KeyId], ) -> Pin<Box<dyn Future<Output = Result<Vec<CredentialActivity>, StoreError>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait,

Inspect requested keys in input order, including repeated IDs and retired keys. Every input has one explicit result or the read fails. This operator read uses O(keys.len()) output memory; backends bound individual queries internally. Multiple chunks need not share an instant.
Source§

fn insert_key<'life0, 'async_trait>( &'life0 self, record: KeyRecord, ) -> Pin<Box<dyn Future<Output = Result<(), KeyError>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait,

Record a minted credential. The caller has already generated the secret and computed its digest; this stores what remains.
Source§

fn revoke_key<'life0, 'async_trait>( &'life0 self, key_id: KeyId, now: Timestamp, ) -> Pin<Box<dyn Future<Output = Result<Revocation, KeyError>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait,

Retire one credential, reporting whether it was live. Read more
Source§

fn publish_key_snapshot<'life0, 'async_trait>( &'life0 self, account: AccountId, key: KeyId, snapshot: PublishableSnapshot, ) -> Pin<Box<dyn Future<Output = Result<AdminReceipt<()>, KeySnapshotError>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait,

Publish snapshot for the principal of account’s credential key, resolved inside the store (GL-143). Read more
Source§

fn publish_key_snapshot_next<'life0, 'async_trait>( &'life0 self, account: AccountId, key: KeyId, snapshot: PublishableSnapshot, ) -> Pin<Box<dyn Future<Output = Result<AdminReceipt<()>, KeySnapshotError>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait,

Publish key policy with a store-allocated generation. The submitted generation is ignored: first publication uses 1, and each later write uses the live snapshot or tombstone’s generation plus one. Allocation, validation, publication and receipt capture are one atomic operation. Overflow fails without changing the snapshot or emitting a push. Read more
Source§

fn remove_key_snapshot<'life0, 'async_trait>( &'life0 self, account: AccountId, key: KeyId, ) -> Pin<Box<dyn Future<Output = Result<AdminReceipt<()>, KeySnapshotError>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait,

Withdraw the snapshot of account’s credential key, tombstoning it as AdminStore::remove_snapshot does. Allowed for a revoked credential: revocation does not withdraw its snapshot, and withdrawal is the safe direction.
Source§

fn revoke_key_audited<'life0, 'async_trait>( &'life0 self, key_id: KeyId, now: Timestamp, ) -> Pin<Box<dyn Future<Output = Result<AdminReceipt<Revocation>, KeyError>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait,

Retire a credential and capture its actual owner, key and predecessor under the mutation lock. A repeated revocation returns equal states.
Source§

fn active_keys<'life0, 'async_trait>( &'life0 self, now: Timestamp, ) -> Pin<Box<dyn Future<Output = Result<Vec<KeyRecord>, StoreError>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait,

Unbounded operator read of every credential valid at now. Serving instances use KeySource pages and an owned, bounded drain instead. Retained for existing direct-store lifecycle tooling; no hidden page cap.
Source§

fn account_keys<'life0, 'async_trait>( &'life0 self, account: AccountId, after: Option<KeyId>, limit: NonZeroUsize, ) -> Pin<Box<dyn Future<Output = Result<Vec<KeySummary>, KeyError>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait,

One account’s credentials, ordered by key_id, for an operator listing (GL-121). Read more
Source§

fn insert_key_within<'life0, 'async_trait>( &'life0 self, record: KeyRecord, max_active: NonZeroUsize, now: Timestamp, ) -> Pin<Box<dyn Future<Output = Result<(), KeyError>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait,

Record a credential only if the account holds fewer than max_active live ones, counting and inserting indivisibly (GL-121). Read more
Source§

fn insert_key_within_audited<'life0, 'async_trait>( &'life0 self, record: KeyRecord, max_active: NonZeroUsize, now: Timestamp, ) -> Pin<Box<dyn Future<Output = Result<AdminReceipt<()>, KeyError>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait,

Bounded issuance with lifecycle evidence captured under the mutation lock. HTTP administrators must use this receipt rather than synthesize history.
Source§

impl KeySource for MemoryStore

Source§

fn active_keys_page<'life0, 'async_trait>( &'life0 self, now: Timestamp, after: Option<KeyId>, limit: NonZeroUsize, ) -> Pin<Box<dyn Future<Output = Result<KeyPage, StoreError>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait,

Read active records in strictly increasing key-id order. Direct stores use now; HTTP servers choose their own clock and return it as as_of. Reads must be coherent with the returned revision, including for an empty result. Never return a partial successful page after a failure.
Source§

impl LeaseAllocator for MemoryStore

Source§

fn acquire<'life0, 'async_trait>( &'life0 self, account: AccountId, requested: CostUnits, ttl: SignedDuration, now: Timestamp, ) -> Pin<Box<dyn Future<Output = Result<Allocation, AllocateError>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait,

Atomically debit a grant from the account. The granted size follows the backend’s GrantPolicy and may be smaller than requested; the fencing token comes from a strictly increasing per-account sequence. It remains a capability for this lease only; allocating a newer token does not invalidate another active lease.
Source§

fn release<'life0, 'async_trait>( &'life0 self, lease_id: LeaseId, fencing_token: FencingToken, unspent: CostUnits, now: Timestamp, ) -> Pin<Box<dyn Future<Output = Result<(), AllocateError>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait,

Graceful return: require the stored (lease_id, fencing_token) pair, credit unspent back, and close the lease. Callers should flush usage first when possible; events arriving after release are accepted only when they fit its provisional settlement loss.
Source§

fn consolidate<'life0, 'async_trait>( &'life0 self, lease_id: LeaseId, fencing_token: FencingToken, unspent: CostUnits, requested: CostUnits, needed: CostUnits, ttl: SignedDuration, now: Timestamp, ) -> Pin<Box<dyn Future<Output = Result<Allocation, AllocateError>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait,

Atomically return an active lease’s unspent units and re-grant against the restored balance: release followed by acquire, in one transaction, for the same account the lease names. Read more
Source§

fn reclaim_expired_batch<'life0, 'async_trait>( &'life0 self, now: Timestamp, limit: NonZeroUsize, ) -> Pin<Box<dyn Future<Output = Result<ReclaimBatch, StoreError>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait,

Settle at most limit active leases whose TTL (plus the policy’s reclaim grace) has lapsed and whose holder never released them. Read more
Source§

fn reclaim_expired<'life0, 'async_trait>( &'life0 self, now: Timestamp, ) -> Pin<Box<dyn Future<Output = Result<Vec<ReclaimedLease>, StoreError>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait,

Settle every currently expired lease through bounded transactions. Read more
Source§

impl SnapshotSource for MemoryStore

Source§

fn principals<'life0, 'async_trait>( &'life0 self, ) -> Pin<Box<dyn Future<Output = Result<Option<Vec<Principal>>, StoreError>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait,

Tombstones included: a revoked principal is one an instance must keep tracking so it keeps knowing about the revocation. Dropping it from the catalogue would make it indistinguishable from a principal that never existed, which is the resurrection INVARIANTS.md GL-15 forbids.

Source§

fn snapshot<'life0, 'async_trait>( &'life0 self, principal: Principal, ) -> Pin<Box<dyn Future<Output = Result<SnapshotResolution, StoreError>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait,

Fetch the authoritative state for a principal. Revocation is distinct from never-known so pull, lag recovery, and restart preserve the generation watermark required for anti-resurrection semantics. Reads used to reconstruct reclaimed local history must be linearizable against durable publications/tombstones. Start a new source operation; an earlier cached response or lagging replica cannot establish that principal’s forgotten generation floor. Return an error if this authority is unavailable. MemoryStore and primary PostgresStore reads supply this ordering; HTTP deployments must preserve it end to end.
Source§

fn subscribe(&self) -> Receiver<SnapshotPush>

Subscribe to pushes. A lagging receiver may miss updates; the contract is that a fresh snapshot() fetch after a lag error observes at least the newest generation.
Source§

impl StoreHealth for MemoryStore

Source§

fn ping<'life0, 'async_trait>( &'life0 self, ) -> Pin<Box<dyn Future<Output = Result<(), StoreError>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait,

Succeed only when the backing store can currently answer. MemoryStore always succeeds; PostgresStore runs a trivial query. Read more
Source§

impl UsageSink for MemoryStore

Source§

fn ingest<'life0, 'life1, 'async_trait>( &'life0 self, events: &'life1 [UsageEvent], _now: Timestamp, ) -> Pin<Box<dyn Future<Output = Result<IngestReport, IngestError>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait,

Record a batch. Idempotent on request_id; every event must match its stored (lease_id, account_id, fencing_token) capability before lease state and accounting capacity are checked. Partial acceptance is normal — the report says what happened. 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> 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, 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<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