mirror of
https://github.com/block/buzz.git
synced 2026-08-18 06:50:31 +02:00
Signed-off-by: Tyler Longwell <tlongwell@block.xyz> Co-authored-by: npub1qyvc0c5kl4gqv2fd97fsk46tu378sqgy35vc83rvgfwne90sel7s0ed67d <011987e296fd5006292d2f930b574be47c7801048d1983c46c425d3c95f0cffd@sprout-oss.stage.blox.sqprod.co> Co-authored-by: Tyler Longwell <tlongwell@block.xyz>
75 lines
3.9 KiB
PL/PgSQL
75 lines
3.9 KiB
PL/PgSQL
-- Replica-fence floor: make the ingest-time created_at envelope a commit-time
|
|
-- storage invariant for channel-window rows.
|
|
--
|
|
-- Why: cursor (keyset) pages may be served by a read replica behind a
|
|
-- "fence" timestamp. The fence proof requires that once a replica has
|
|
-- replayed past a sampled writer LSN, no transaction can later commit an
|
|
-- events row whose created_at is older than (commit time - floor). The
|
|
-- ingest handler checks |created_at - now| <= 900s at acceptance time, but
|
|
-- acceptance and commit are separated by unbounded async work, and several
|
|
-- writers (workflow sink, side effects, replace_*) bypass ingest entirely.
|
|
--
|
|
-- Mechanism: a DEFERRABLE INITIALLY DEFERRED constraint trigger runs inside
|
|
-- COMMIT processing, re-evaluating clock_timestamp() (NOT now(), which is
|
|
-- frozen at transaction start) so the bound is measured at commit, not at
|
|
-- INSERT. A transaction that holds an old-created_at insert open past the
|
|
-- floor budget is aborted at COMMIT and can never introduce a below-fence
|
|
-- row. Verified on PostgreSQL 16 against a partitioned table.
|
|
--
|
|
-- Scope: rows with channel_id IS NOT NULL — exactly the rows that channel
|
|
-- windows and thread pagination serve. channel_id-NULL rows (push leases,
|
|
-- profile/discovery snapshots) legitimately carry client-signed historical
|
|
-- timestamps and never appear in keyset-paged windows.
|
|
--
|
|
-- Enforcement is opt-in per session via the buzz.created_at_floor GUC
|
|
-- (seconds). The relay's writer pool sets it on every connection
|
|
-- (after_connect); when the GUC is unset or blank the guard is a no-op so
|
|
-- pg_restore/backfills and test fixtures that legitimately write historical
|
|
-- rows keep working. There is deliberately NO in-band bypass for
|
|
-- channel-bearing rows (the only structural exemption is channel_id IS
|
|
-- NULL, which never appears in keyset-paged windows): any operational
|
|
-- backfill of channel rows must run on a connection without the GUC — i.e.
|
|
-- outside the relay's writer pool — and the operator must hold the replica
|
|
-- breaker closed from before the backfill transaction begins until its WAL
|
|
-- is replayed on the replica (see Db::read routing docs). Disabling
|
|
-- triggers via session_replication_role = replica (pg_restore) is likewise
|
|
-- a breaker-closed operation.
|
|
--
|
|
-- Partition coverage: a constraint trigger created on the partitioned
|
|
-- parent is cloned onto every existing partition and onto partitions
|
|
-- created later (`CREATE TABLE .. PARTITION OF`), so partition rotation
|
|
-- keeps the guard. Row-level triggers also fire for COPY. Coverage across
|
|
-- the partition topology is asserted by a buzz-db test.
|
|
|
|
CREATE FUNCTION events_created_at_floor_guard() RETURNS trigger
|
|
LANGUAGE plpgsql AS $$
|
|
DECLARE
|
|
floor_secs numeric := nullif(current_setting('buzz.created_at_floor', true), '')::numeric;
|
|
BEGIN
|
|
IF floor_secs IS NOT NULL
|
|
AND floor_secs > 0
|
|
AND NEW.channel_id IS NOT NULL
|
|
AND NEW.created_at < clock_timestamp() - make_interval(secs => floor_secs)
|
|
THEN
|
|
RAISE EXCEPTION
|
|
'events.created_at % is more than % s before commit time %; below the replica-fence floor',
|
|
NEW.created_at, floor_secs, clock_timestamp()
|
|
USING ERRCODE = 'check_violation';
|
|
END IF;
|
|
RETURN NULL;
|
|
END
|
|
$$;
|
|
|
|
-- INSERT OR UPDATE OF: an UPDATE can move a previously exempt row into the
|
|
-- guarded set (channel_id NULL -> NOT NULL) or move a channel row's
|
|
-- created_at below the fence, so both mutation paths re-run the guard on the
|
|
-- NEW row. Partition-key note: a created_at rewrite that crosses partition
|
|
-- bounds is executed as DELETE + INSERT, which fires the cloned AFTER INSERT
|
|
-- guard on the destination partition; an in-partition rewrite fires the
|
|
-- UPDATE OF arm. Either way the NEW row is checked.
|
|
CREATE CONSTRAINT TRIGGER events_created_at_floor
|
|
AFTER INSERT OR UPDATE OF created_at, channel_id ON events
|
|
DEFERRABLE INITIALLY DEFERRED
|
|
FOR EACH ROW
|
|
EXECUTE FUNCTION events_created_at_floor_guard();
|