fix(writer): commit loop reads the connection through the non-throwing path - #929
Open
markaddleman wants to merge 1 commit into
Open
Conversation
…g path Releasing a connection that has transacted raises `Connection has been released.` inside the commit go-loop. It never reaches the caller — `go-try` catches it and hands it to the global supervisor — so it surfaces only as delayed `Supervisor:` output on the stale timeout, which is why it reads as an intermittent flake rather than the deterministic one it is. `release` marks the connection released (`delete-connection!`) before `w/shutdown`; closing the queue unparks `(<?- commit-queue)` and the second recur argument then derefs an already-released connection. `@connection` here was the only bare deref of the connection in this namespace — every other read already goes through `@(:wrapped-atom connection)`. Measured on 0.8.1760, same JVM, only this token differing, over 20 iterations of create -> connect -> transact -> snapshot -> release -> delete: pending supervisor exceptions 20/20 before, 0/20 after, reads correct in both. With zero transactions it never fires either way. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #928.
Releasing a connection that has transacted raises
Connection has been released.inside the commit go-loop. It never reaches the caller —go-trycatches it and hands it to the global supervisor — so it appears only as delayedSupervisor:output on the 10 s stale timeout. That is why it reads as an intermittent flake rather than the deterministic thing it is; we had it filed downstream as a flake for months before measuring@(:pending-exceptions superv.async/S)directly.connector/releasemarks the connection released (delete-connection!) beforew/shutdown. Closing the queue unparks(<?- commit-queue), and the second recur argument then derefs an already-released connection.@connectionat that line was the only bare deref of the connection in the namespace — lines 58, 60, 66, 67, 276, 301, 315 and 328 all read through@(:wrapped-atom connection). This makes it consistent with them.Measurement
Reproducer is in #928 — public API only, 20 iterations of create → connect → transact → snapshot → release → delete. Run on 0.8.1760, same JVM, patched source shadowing the released jar on the classpath so that only this token differs:
With zero transactions it never fires either way, which is what identifies the commit loop specifically rather than the release path in general.
What I have not done
I have not run datahike's own test suite against this. The Java sources need the project's
compile-javastep and it did not build standalone in my environment, so I would rather say so than imply a green suite. The change is one token plus a comment; CI should be the judge.The comment is there because the non-obvious spelling is the point — a later simplification back to
@connectionwould silently reintroduce this. Happy to drop it if you would prefer the bare change.Impact for consumers
Reads are unaffected:
d/qruns over the db value and never re-entersderef-conn, so a consumer holding a snapshot sees correct results throughout. The cost is one tracked exception per released connection accumulating in a global supervisor, and stdout flooding on the stale timeout — which for a long-running process that opens and releases connections is a steady leak.