Sourced.EventStore.Postgres.Event (sourced_postgres v0.2.0)

Copy Markdown View Source

Ecto schema for the sourced events table, and every query the adapter runs against it.

Queries live here rather than beside the repo calls that run them, so Ecto.Query is imported in one place and the read path and the append condition cannot drift apart on what counts as a match.

Summary

Functions

Query asking whether anything matching query has arrived past expected_sequence.

Query returning the sequence of the last event matching query past expected_sequence, or 0 when nothing is past it.

Query returning the sequence of the last event matching query, or 0 when nothing matches.

Bounds query to what the reader is allowed to see: everything at or below the watermark, plus the events the reading transaction appended itself.

Functions

conflict_query(query, expected_sequence)

Query asking whether anything matching query has arrived past expected_sequence.

This is the DCB check, and under SERIALIZABLE it needs no help to be race-free: the read takes SIREAD predicate locks over the range it touched, a concurrent insert into that range creates an rw-conflict, and the dangerous structure detector aborts one side. It needs no ordering against the insert that follows it, and so runs as an ordinary statement of its own.

Phrased as an existence check over the tail rather than as max(sequence) over everything matching, because under SSI the read set is the lock set: this reads only past expected_sequence and can stop at the first row, which is a strictly narrower predicate-lock footprint for an equivalent question.

conflicting_sequence(query, expected_sequence)

Query returning the sequence of the last event matching query past expected_sequence, or 0 when nothing is past it.

Reports what a rejected append conflicted with. Bounded to the same tail as conflict_query/2, so it is only meaningful where something is already known to be in that tail — the 0 it returns otherwise would misreport an empty tail as an empty stream. Where that is not known, use last_sequence/1.

Worth the narrowing because this runs inside the append's own transaction, where a read of the whole matched range would take the wide predicate locks that conflict_query/2 exists to avoid.

filter(query, arg2, sequence)

last_sequence(query)

Query returning the sequence of the last event matching query, or 0 when nothing matches.

readable(query)

Bounds query to what the reader is allowed to see: everything at or below the watermark, plus the events the reading transaction appended itself.

with_query(query)