Skip to content

fix: publish changes once the committing statement finishes - #68

Merged
velocitysystems merged 1 commit into
silvermine:masterfrom
kmccalley:kmccalley/publish-changes-after-commit
Sep 19, 2026
Merged

velocitysystems merged 1 commit into
silvermine:masterfrom
kmccalley:kmccalley/publish-changes-after-commit

Conversation

@kmccalley

Copy link
Copy Markdown
Contributor

SQLite's commit hook runs before the commit is final, so a subscriber notified from it can read pre-commit state through another connection. A concurrent reader saw the stale value on 44 of 50 notifications.

The commit hook now converts and holds the changes. A trace hook, registered with SQLITE_TRACE_PROFILE, publishes them when the statement that committed finishes. The commit is durable by then, and the writer does nothing extra. If the commit fails after the commit hook ran, the rollback hook discards the held changes.

Per-transaction state moves from the shared broker to each connection's hook context, so two connections observing the same database can no longer publish or discard each other's changes. The broker's on_preupdate, on_commit, and on_rollback methods are removed. The CHANGELOG records the break.

Three tests guard this, one per journal mode for visibility and one for cross-connection isolation. All three fail on master.

@kmccalley
kmccalley requested a review from a team September 18, 2026 16:03
Comment thread crates/sqlx-sqlite-observer/src/hooks.rs Outdated
Comment thread crates/sqlx-sqlite-observer/README.md
Comment thread crates/sqlx-sqlite-observer/src/hooks.rs
Comment thread crates/sqlx-sqlite-observer/src/hooks.rs Outdated
Comment thread CHANGELOG.md
SQLite's commit hook runs before the commit is final, so a subscriber notified
from it can read pre-commit state through another connection. A concurrent
reader saw the stale value on 44 of 50 notifications.

The commit hook now converts and holds the changes. A trace hook publishes them
when the statement that committed finishes, and the commit is durable by then.
The trace hook also fires when the next statement starts, which publishes a
commit made during a statement reset: an autocommit INSERT ... RETURNING read
with fetch_one commits inside the reset, after the profile event. The writer
does nothing extra. If the commit fails after the commit hook ran, the rollback
hook discards the held changes.

Publication now happens after SQLite released the write lock, so notifications
keep commit order per connection only. The conn-mgr writer is exclusive, so the
plugin keeps its order.

Per-transaction state moves from the shared broker to each connection's hook
context, so two connections observing the same database can no longer publish
or discard each other's changes. The broker's on_preupdate, on_commit, and
on_rollback methods are removed, and PreUpdateEvent is crate-private. The
CHANGELOG records the breaks.

Five tests guard this: visibility in each journal mode, cross-connection
isolation, a reset commit surviving a later failed write, and a reset commit
published on drop. The first four fail on master.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@kmccalley
kmccalley force-pushed the kmccalley/publish-changes-after-commit branch from e2ef344 to 4aadf33 Compare September 19, 2026 03:30
@velocitysystems
velocitysystems merged commit b83e9e0 into silvermine:master Sep 19, 2026
1 check 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.

2 participants