Skip to content

perf(server): batch hydrateRows; per-table catch-up reads use the (tbl,seq) index#8

Open
grrowl wants to merge 1 commit into
advisor/001-server-error-path-testsfrom
advisor/004-catchup-sql-batching
Open

perf(server): batch hydrateRows; per-table catch-up reads use the (tbl,seq) index#8
grrowl wants to merge 1 commit into
advisor/001-server-error-path-testsfrom
advisor/004-catchup-sql-batching

Conversation

@grrowl

@grrowl grrowl commented Jun 11, 2026

Copy link
Copy Markdown
Owner

Executes plan 004 from the advisor audit. Stacked on #4 (plan 001) — merge that first, then retarget/merge this; the diff vs its base is src/server/changes.ts + the emitCatchUp call site + two new tests.

What

  • hydrateRows: N+1 (one SELECT … WHERE pk = ? LIMIT 1 per changed key) → chunked IN queries (CHUNK=64, quoted identifiers, bound values, String(row[pk]) keying preserved per ADR-0007/D9).
  • New readChangesSinceFor(sql, tbl, cursor): per-table changelog read that actually uses the _sync_changes_tbl_seq index (whose comment always claimed it "serves per-table catch-up" — now true). emitCatchUp uses it; drainAndBroadcast's deliberate one-scan-all-tables read is untouched.

Why

Cuts SQLite rows-read (billed) and DO wall-clock exactly where reconnect storms concentrate: a 500-key catch-up was 500 queries over a full-log scan; now ~8 queries over an index range.

Verification

Two new falsifiable tests in tests/cdc.test.ts (3-chunk hydration with missing keys; table isolation + mid-stream cursor windowing); catchup/reconnect/multiplex wire tests green; full suite green on the reviewer's re-run.

🤖 Generated with Claude Code

…l,seq) index

Eliminates the N+1 SELECT in hydrateRows by issuing chunked IN queries
(64 keys per chunk), cutting SQLite rows-read on reconnect storms.

Adds readChangesSinceFor for emitCatchUp's per-table read, activating the
_sync_changes_tbl_seq composite index that previously went unused — the
JS .filter() after readChangesSince is gone. drainAndBroadcast's all-tables
readChangesSince call is intentionally unchanged (one scan, N tables).

New tests in cdc.test.ts pin: chunking over 150 rows (no drops/dups, TEXT pk
keying), and readChangesSinceFor table isolation + mid-stream cursor windowing.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
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