Skip to main content

PostgresStore

Struct PostgresStore 

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

Fixture reset is available only in the opt-in test_support module, never as a method on a normal store handle.

ⓘ
fn reset(store: &PostgresStore) {
    let _ = store.truncate_all();
}

Query-plan inspection, which refreshes database statistics, is likewise absent from the operational handle:

ⓘ
fn explain(store: &PostgresStore) {
    let _ = store.explain_active_lease_sum(AccountId(1));
}

The same holds for the two sweep plans (GL-65):

ⓘ
fn explain_sweep(store: &PostgresStore) {
    let _ = store.explain_reclaim_due_leases(jiff::Timestamp::UNIX_EPOCH, 256);
}
ⓘ
fn explain_rollover(store: &PostgresStore) {
    let _ = store.explain_due_periods("daily", 0, 256);
}

Implementations§

Source§

impl PostgresStore

Source

pub async fn connect( url: &str, policy: GrantPolicy, ) -> Result<Arc<Self>, StoreError>

Connect with default pool bounds and run pending migrations.

Source

pub async fn connect_with( url: &str, policy: GrantPolicy, pool_config: PoolConfig, ) -> Result<Arc<Self>, StoreError>

Connect and run pending migrations (versioned under ./migrations, tracked by sqlx’s _sqlx_migrations table — review finding GL-11).

Note the limits of what a pool bound can promise: acquire_timeout covers waiting for a connection, including establishing one, but a query already in flight on a healthy connection is bounded only by a server-side statement_timeout. Callers must still bound their own calls (INVARIANTS.md GL-18).

Source

pub async fn balance(&self, account: AccountId) -> Result<CostUnits, StoreError>

The account’s unspent balance, read in one statement outside any transaction. An unknown account reads as zero, as in MemoryStore.

A negative stored value is reported as a StoreError, never clamped (INVARIANTS.md 11). For figures that must agree with each other, use conservation, which reads them from one snapshot.

Source

pub async fn usage_recorded( &self, account: AccountId, ) -> Result<CostUnits, StoreError>

Total usage accepted into the account’s billing ledger, including overage usage, read in one statement outside any transaction. An unknown account reads as zero, as in MemoryStore.

A negative stored value is reported as a StoreError, never clamped (INVARIANTS.md 11).

Source

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

The terms of the account’s ledger equation, for reconciliation against the ledger contract in INVARIANTS.md. None when the account does not exist.

The account totals and the sums over its active leases are read in one REPEATABLE READ, READ ONLY transaction, so both come from the same snapshot and a concurrent commit cannot land between them. The transaction writes nothing.

Stored state that cannot be a valid ledger is reported as a StoreError, never clamped or panicked on: a negative unit column (INVARIANTS.md 11), or active-lease usage exceeding recorded usage. Whether the returned terms balance is for the caller to check with Conservation::holds.

Trait Implementations§

Source§

impl AdminStore for PostgresStore

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 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 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 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 PostgresStore

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 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 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 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 PostgresStore

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 PostgresStore

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 'life0: 'async_trait, Self: 'async_trait,

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

impl SnapshotSource for PostgresStore

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, for the reason MemoryStore::principals gives: forgetting a revoked principal is how one gets resurrected.

A primary-key scan, so no new index — the table holds one row per principal, not per request, and ORDER BY makes the result stable so a caller diffing two enumerations sees real changes rather than storage order.

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 PostgresStore

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 PostgresStore

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<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
where ST: ?Sized, DT: ?Sized,

Source§

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

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> 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> Read<Exclusive, BecauseExclusive> for T
where T: ?Sized,

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