Skip to content

server: support opt-in mutation images for Recorder - #5

Merged
lesomnus merged 3 commits into
mainfrom
feat/recorder-snapshots
Oct 14, 2026
Merged

lesomnus merged 3 commits into
mainfrom
feat/recorder-snapshots

Conversation

@lesomnus

@lesomnus lesomnus commented Oct 14, 2026 •

Copy link
Copy Markdown
Member

Recorder consumers currently receive only a key and patch, so they cannot describe the value immediately before deletion or distinguish intermediate mutations by reading the row later. Add optional Change.Previous and Change.Value, captured inside the write transaction with key-only resource references.

Image capture is explicitly opt-in through SnapshotRecorder.Snapshots(method) SnapshotOptions, independently per generated operation. Ordinary recorders preserve their existing query/locking behavior. Recorders unions the requirements and captures each image once. Payload presence does not identify the operation; Change.By does.

A requested preimage locks the root row on PostgreSQL/MySQL until transaction completion; SQLite relies on write serialization/conflict handling. A requested creation image is read back from the database to preserve timestamp precision, defaults and trigger values, without an explicit row lock. Update postimages reuse the existing response read-back. The root lock does not provide an atomic snapshot of all related tables. Get-less resources are supported.

No publication or payday-specific API is added here. This supplies the optional mutation data needed by lesomnus/payday#74 and lesomnus/payday#75.

Validation:

  • Generator/runtime/integration checks and PostgreSQL tests, including 16 concurrent writers verifying the opted-in preimage chain and stored timestamp precision.
  • SQLite/PostgreSQL SQL-count and FOR UPDATE regression tests for ordinary metadata recorders, postimage-only recorders and both images; nested recorder aggregation and Add-only resource coverage.
  • Confirmed the cost regression test fails when unconditional capture is restored.
  • BenchmarkRecorderSnapshotsPatch compares metadata, postimage-only and both-image modes (single row, no relationships, no contention or audit/outbox/subscriber work). Run with go test -C internal/apptest ./server/bare -run '^$' -bench BenchmarkRecorderSnapshotsPatch -benchmem; set APPTEST_POSTGRES for PostgreSQL.

Measured on Linux amd64 / Ryzen 7 5825U, GOMAXPROCS=4; 3 runs of 2s each, other local test/build jobs stopped. Medians below are a small uncontended ORM-only workload, not end-to-end Watch throughput or a production estimate. PostgreSQL ran in a Docker container over TCP.

Capture mode SQLite µs/op PostgreSQL µs/op PostgreSQL allocations/op
metadata 67.4 443.0 366
value 67.2 441.8 369
both 90.7 638.5 499

@lesomnus lesomnus changed the title server: capture mutation images in Recorder changes server: support opt-in mutation images for Recorder Oct 14, 2026
@lesomnus
lesomnus merged commit 4698cb9 into main Oct 14, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant