Skip to content

perf: skip unchanged lifecycle reads with SQLite data_version - #219

Merged
bompus merged 3 commits into
mainfrom
perf/data-version-gate-20261029
Oct 30, 2026
Merged

bompus merged 3 commits into
mainfrom
perf/data-version-gate-20261029

Conversation

@bompus

@bompus bompus commented Oct 30, 2026 •

Copy link
Copy Markdown
Owner

Supersedes #218 (closed, not landed): the stat-fingerprint gate could cache a pre-commit WAL snapshot and could survive an outer transaction rollback.

On Linux, Lifecycle.reconcile opens one persistent read-only connection to the source and uses PRAGMA data_version as the commit check. When the value and the agent thread set match the last successful read, it skips the source read and returns the saved result. A changed value does the full read.

The database filename is resolved before its sidecars are located. The connection is reopened when the database, -wal or -shm sidecar changes identity or access mode, so a replaced file, a filename symlink retarget or a sidecar permission change forces a full read. Any stat or query error, a dead connection, a missing or unreadable source, or an unexpected platform falls back to the full read; no path can admit on an unverified cache. Inside a tool's outer transaction a skip writes nothing and reuses the last committed version; a full read there never records a new version, so a transaction rollback cannot leave a newer version behind the restored rows.

Windows does not open a persistent connection and keeps today's full read; the handle behaviour there is untested. The ready/unavailable answers, invalid and unverified row handling, and delivery admission are unchanged; only an unchanged read is skipped.

Evidence

  • Tests: an unchanged source skips the read (the successful-read count does not move), a changed source and a WAL change are read again, a rolled-back admission does not cache, a missing database and a permission error return unavailable, a replaced inode is read again, a dead gate connection falls back to the full read, revoking read permission on the -wal or the -shm (with an external writer holding the shared memory) after the cache is warm returns unavailable, a symlinked database with the target WAL permission revoked returns unavailable, and a non-Linux instance never opens the gate and reads every time. Focused file 82 pass; bun run check pass; full suite 1,468 pass / 0 fail / 7 skip.
  • Copy server, 20 clients renewing a 3 s wait with a reconcile every 2 s, 5 x 30 s windows on the same synthetic source: current idle 0.1378 cores -> gated idle 0.0541; gated at 1 commit/s 0.0603 cores (180 commits), 56% less.
  • The live server was not restarted or attached to.

Limits

  • Linux-only by design. Windows and every other platform read the source every time; the persistent handle risk stays out of scope.
  • The read-only connection is held open while the process runs and holds no transaction. A replacement is detected by inode and ctime; any error disables the skip and falls back to the full read.

On Linux, the lifecycle check keeps one read-only connection open and uses PRAGMA data_version as the engine's commit check. When the value and the agent thread set match the last successful read, it skips the source read. Windows and every other platform keep the full read.

A replaced database is detected by the dev:ino:ctime identity and forces a reopen and full read. A skip inside a tool's outer transaction writes nothing and reuses the last committed version; a full read inside one never records a new version, so a rollback cannot leave a newer version behind restored rows.

Copy-server: idle 0.1378 -> 0.0567 cores; 1 commit/s 0.1378 -> 0.0647.
@bompus

bompus commented Oct 30, 2026

Copy link
Copy Markdown
Owner Author

@coderabbitai full review

@coderabbitai

coderabbitai Bot commented Oct 30, 2026 •

Copy link
Copy Markdown

Important

  • 🔍 Trigger review

This repository does not receive automatic reviews because it has fewer than 10 stars.

Run configuration
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai

coderabbitai Bot commented Oct 30, 2026 •

Copy link
Copy Markdown
⚠️ Action not completed

Review rate limited.


Your included review limit is currently reached under our Fair Usage Limits Policy. This review may still proceed through usage-based billing if eligible. Your next included review will be available in 20 minutes.

@bompus

bompus commented Oct 30, 2026

Copy link
Copy Markdown
Owner Author

CodeRabbit had no quota for this head: its free OSS review limit was reached and its replies say "Review rate limited". Under the standing review exception through 2026-11-10 the review is skipped, with later findings as a follow-up PR. The repository's bompus-ai-review app and the local Sol xhigh review cover the gate.

@bompus-ai-review bompus-ai-review Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Bompus AI Review (GPT-6.1 Sol, xhigh reasoning): 1 finding(s).

Comment thread src/lifecycle.ts Resolved
The gate fingerprinted only the database file, so revoking read permission on the -wal while the writer stayed open left the identity unchanged and the already-open connection returned ready. The fingerprint now covers the WAL sidecar's device, inode, mode and owner, and a missing or unstattable WAL forces the full read. WAL content timestamps stay out of the identity because a commit changes them; data_version reports the commit.

Regression: warm a WAL source, chmod the -wal 000 while the writer is open, reconcile returns unavailable.

@bompus-ai-review bompus-ai-review Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Bompus AI Review (GPT-6.1 Sol, xhigh reasoning): 2 finding(s).

Comment thread src/lifecycle.ts Resolved
Comment thread src/lifecycle.ts Resolved
The gate now resolves the database filename before locating the WAL, so a filename symlink cannot point the fingerprint at a different WAL, and it includes the -shm sidecar's identity and access state. A permission change on either sidecar closes the persistent connection and forces the full read; a missing sidecar is normal and an unstattable one forces the read.

Tests: a symlinked database with the target's WAL read permission revoked returns unavailable, and an external writer holding the shared memory plus a revoked -shm returns unavailable.

@bompus-ai-review bompus-ai-review Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Bompus AI Review (GPT-6.1 Sol, xhigh reasoning): 0 finding(s).

Review 3: only high findings and above are posted from here on.

@bompus
bompus merged commit 02b4a0c into main Oct 30, 2026
3 checks passed
@bompus
bompus deleted the perf/data-version-gate-20261029 branch October 30, 2026 05:02
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