Keeping backends in sync
Each backend holds replicas of the documents its clients use. To learn
when another backend persisted changes, attach the notification trigger and
LISTEN:
CREATE TRIGGER docs_notify AFTER INSERT OR UPDATE OR DELETE ON docs
FOR EACH ROW EXECUTE FUNCTION automerge_notify('docs_changed', 'id');
LISTEN docs_changed;
-- payloads look like
-- {"table":"public.docs","op":"UPDATE","seq":17,"key":{"id":"…"},
-- "columns":{"doc":{"heads":["79df…"],"prev_heads":["891e…"]}}}On a notification for a document you hold, skip it if you already have
every hash in heads (you probably wrote them), otherwise fetch exactly
what your replica lacks and apply it with loadIncremental /
applyChanges:
SELECT automerge_changes_bytes(doc, $2) FROM docs WHERE id = $1; -- $2: your replica's headsNotifications are sent at commit and only to connected listeners, so after
(re)connecting, LISTEN first and then run the same query for every
document you hold. INSERT and DELETE always notify; an UPDATE notifies only
when a document's heads (or the key) change, so no-op merges are silent.
Payloads over NOTIFY's 8000-byte limit (about 115 heads) drop the heads and
carry "truncated":true; then just fetch. seq (a per-backend counter)
keeps payloads distinct, since NOTIFY would otherwise collapse identical
events of one transaction (e.g. INSERT, DELETE, INSERT of one row). Details in
Change notifications.
A no-op merge still rewrites the row. When re-sends are common, skip them:
UPDATE docs SET doc = merge(doc, $1) WHERE id = $2 AND NOT automerge_contains(doc, $1);This is safe with concurrent writers in READ COMMITTED: a writer that had
to wait for another's row lock re-checks the whole WHERE against the
committed row (EvalPlanQual), so it skips the row if the other writer
already stored the same changes and merges into the new version otherwise.
For bare changes ($1 bytea) the check usually needs no load of the
document; for a full save it needs none when the save is the stored
document's own, and costs one extra load of the stored document when there
is something new.