Skip to main content

PgEventStore

Struct PgEventStore 

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

The PostgreSQL event store.

Implementations§

Source§

impl PgEventStore

Source

pub async fn ensure_genesis(&self, public_revision: &str) -> Result<(), Refusal>

Append genesis if this log has none. Idempotent: a kernel that already has an epoch is left exactly as it was.

Separate from PgEventStore::open on purpose — opening a store reads, and a constructor that writes would put an append in the path of every replay and every read-only inspection of a log.

Source§

impl PgEventStore

Source

pub async fn recover(&self) -> Result<RecoveryReport, Refusal>

Establish what a restart can prove about the projections.

Writes nothing except on the cold path, where the projections are empty and the log is replayed into them through apply_event — the same writer that would have filled them originally.

It never appends an event. An attempt that was running when the kernel died has an outcome the kernel did not observe, and unknown is a CLAIM about that outcome; minting one here would put a fact into the log that nothing witnessed, and would bury an attempt whose engine is in fact still alive. They are reported instead, and the transition stays an ordinary command with an actor behind it.

Source

pub async fn rebuild_into( &self, scratch: &PgPool, ) -> Result<RebuildReport, Refusal>

Replay the whole log into an EMPTY scratch database and report whether it agrees with the live projections.

This is the only full verification available once the log has moved past its newest checkpoint, and the only place a rebuild can happen at all, since the live tables refuse to be reset. It reads the live log, writes only to scratch, and leaves the decision to replace anything with the operator.

Source§

impl PgEventStore

Source

pub async fn open(pool: PgPool) -> KernelResult<Self>

Bind to an initialized database and claim this boot’s writer epoch.

Claiming here rather than lazily means a superseded process discovers it at startup, not at the first append.

Source

pub async fn with_capacity(pool: PgPool, inflight: usize) -> KernelResult<Self>

open with an explicit admission bound.

Exists so a test can saturate the queue deterministically — proving the bound refuses rather than queues needs a bound small enough to fill.

Source

pub fn open_reader(pool: PgPool) -> Self

A store that can READ the log and cannot write it.

It claims no epoch, and that is the whole point. claim_epoch BUMPS a durable counter, so a verification path that opened an ordinary store would fence the daemon it was verifying out of its own log — the rebuild-into-scratch comparison is meant to run against a live system, not to take it down.

Epoch 0 is never a live epoch, so the fence every mutating transaction already compares refuses this store’s appends by construction. A reader cannot write even by mistake, and the guarantee costs no new check.

Source

pub fn with_blobs(self, blobs: PgBlobStore) -> Self

Attach the blob store a checkpoint writes its records to.

Without it this store never checkpoints, and that is a real state rather than a degraded one: admin init and the certifier drive the log with no filesystem at all, and a snapshot they neither want nor could store is not something to make them configure around. What must not happen is a SERVING kernel in that state, which is why the daemon’s own construction takes the blob store rather than opting into it.

Source

pub fn blobs(&self) -> Option<&PgBlobStore>

The blob store checkpoints write through, if one is attached.

Source

pub async fn checkpoint_at_watermark(&self) -> Result<Option<Seq>, AppendError>

Snapshot the projections at the watermark, whether or not one is due.

The one snapshot no append triggers. Self::checkpoint_if_due rides an append’s transaction and is therefore always AT that append’s sequence; a clean shutdown has no append to ride, so it takes the same writer barrier itself — without it the hash would be taken over projections another process is still moving, and a checkpoint that describes no single moment is worse than none.

This is what makes Verdict::Verified reachable in practice: it requires a checkpoint exactly at the watermark, and the event-interval barrier only ever lands on a multiple of CHECKPOINT_EVENT_INTERVAL. Without a snapshot on the way out, a cleanly stopped kernel would restart into Unverified — honest, but a weaker statement than it was entitled to make.

Ok(None) means there was nothing to snapshot: no blob store to put the records in, or an empty log.

Source

pub fn boot_epoch(&self) -> i64

The epoch this process must present for the rest of its life.

Source

pub fn pool(&self) -> &PgPool

Source§

impl PgEventStore

Source

pub async fn submit(&self, envelope: &CommandEnvelope) -> KernelResult

Apply one command, or answer why not.

A refusal is a value here, exactly as the contract says: this returns KernelResult::Error rather than an Err, so the wire layer has nothing left to translate.

Trait Implementations§

Source§

impl EventStore for PgEventStore

Source§

async fn append( &self, expected_version: u32, fence: Option<FenceToken>, events: Vec<EventEnvelope>, ) -> Result<Vec<EventEnvelope>, AppendError>

Atomically append one aggregate’s batch. Read more
Source§

async fn read_from( &self, cursor: Option<Seq>, limit: usize, ) -> Result<Vec<EventEnvelope>, StorageError>

Read committed events with global_sequence strictly after cursor (None = from the beginning), ascending, at most limit (clamped to MAX_READ_LIMIT). Read more
Source§

async fn watermark(&self) -> Result<Option<Seq>, StorageError>

The highest committed global_sequence, if any event exists.
Source§

async fn grant_fence(&self) -> Result<FenceToken, StorageError>

Grant/rotate the append fence. Each grant returns a token strictly greater than every earlier one and invalidates them.

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