Skip to content

Experimental: changelog table for crdb#3211

Draft
ecordell wants to merge 16 commits into
authzed:mainfrom
ecordell:evan/crdbchangetbl
Draft

Experimental: changelog table for crdb#3211
ecordell wants to merge 16 commits into
authzed:mainfrom
ecordell:evan/crdbchangetbl

Conversation

@ecordell

@ecordell ecordell commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

Note: for reference, hasn't been validated

Description

CockroachDB changefeeds stop emitting resolved timestamps during bulk loads, which stalls SpiceDB's CRDB Watch (it relies on changefeed resolved checkpoints to know a revision is complete). This adds an experimental, opt-in, CRDB-only Watch path that doesn't depend on the changefeed for correctness, so Watch keeps advancing under bulk load.

Behind --datastore-experimental-crdb-changelog-watch (default off — when off, behavior is unchanged):

  • Creates an append-only relationship_changelog table (hash-sharded PK on the HLC commit timestamp, row-level TTL) at init.
  • Relationship, schema, and bulk-load writes dual-write into it in the same transaction.
  • Watch polls the table at present time instead of consuming a changefeed. The table is append-only, so a present read sees every committed row; completeness comes from the cluster's max clock offset (checkpoint/cursor advances only to clusterNow − maxOffset), not changefeed resolved, so no write is skipped. A lightweight changefeed on the table is used only as a low-latency nudge, with the poll interval as the correctness backstop.

Notes:

  • Checkpoint floor ≈ maxOffset (--datastore-experimental-crdb-changelog-watch-max-offset, default 250ms). Must be ≥ the cluster's --max-offset (CRDB default 500ms) or Watch can miss commits.
  • Prototype scope: no cutover backfill, no integrity metadata in the changelog.

Testing

Extensive unit and integration tests, but the impact to write throughput has not been measured, that could make this a dealbreaker.

TODO: run with --datastore-engine cockroachdb --datastore-experimental-crdb-changelog-watch and exercise Watch during a bulk load.

ecordell added 16 commits July 1, 2026 11:20
appendRelationshipChangelogBatch built one multi-row INSERT with 14
columns per relationship. Postgres/pgx cap bound parameters at 65535,
so a BulkLoad of more than ~4600 relationships would overflow the
limit and fail the whole transaction, defeating the point of the
feature. Split the insert into chunks of changelogInsertChunkSize
(default 4000) executed within the same transaction, keeping the
per-transaction ordinal counter continuous across chunks so
(change_ts, ordinal) uniqueness is preserved.

Adds a regression test that lowers the chunk size and bulk-loads
across multiple chunks, asserting every row is observed over the
changelog watch.
AddChangedDefinition's *core.CaveatDefinition branch looked up a
prior entry under nsPrefix+name to decrement its byte size, but
caveats are stored under caveatPrefix+name. The mismatch meant
re-changing the same caveat within one buffering window never found
the prior entry, over-counting currentByteSize on every repeat
change. Shared by all datastores' watch path (Postgres, MySQL, and
the CRDB changelog path); not data loss, but a real accounting bug.

Adds a regression test mirroring the existing namespace-replacement
test, which fails against the prior code.
…watch

watchViaChangelog always buffers and dedups changes per poll interval
via common.NewChanges and does not honor opts.EmissionStrategy, even
though the CRDB datastore advertises WatchEmitsImmediately support.
A caller requesting EmitImmediatelyStrategy silently gets buffered,
checkpoint-grouped delivery instead, and Creates are reported as
Touch. Document this as an accepted limitation of the experimental
path rather than re-architecting it; immediate emission is moot given
the follower-read latency floor anyway.
delete(record.caveatsDeleted, t.Name)

if existing, ok := record.definitionsChanged[nsPrefix+t.Name]; ok {
if existing, ok := record.definitionsChanged[caveatPrefix+t.Name]; ok {

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this looks like a latent bug to me

@github-actions github-actions Bot added area/cli Affects the command line area/datastore Affects the storage system area/tooling Affects the dev or user toolchain (e.g. tests, ci, build tools) labels Jul 2, 2026
@codecov

codecov Bot commented Jul 2, 2026

Copy link
Copy Markdown

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/cli Affects the command line area/datastore Affects the storage system area/tooling Affects the dev or user toolchain (e.g. tests, ci, build tools)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant