roll back a read acquire's open transaction when its SELECT fails#575
Merged
Conversation
4d6aeda to
09af867
Compare
Contributor
Author
|
Thanks for the review and merge. |
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.
The SQLite read/write lock takes a read lock in two steps: it issues a deferred BEGIN that grabs no database lock, and only the SELECT that follows actually takes the shared lock. The trouble is that if a writer takes the exclusive lock in the gap between those two statements, the SELECT fails with "database is locked" while the BEGIN's transaction is already open on the shared connection. The acquire path turns that error into a Timeout and releases its transaction mutex but never rolls the connection back, so it stays mid-transaction; from then on every acquire on that instance hits BEGIN again and dies with "cannot start a transaction within a transaction", wedging the lock for good (and for the async wrapper, the single worker thread it is pinned to). I came across it while reading how the release path was serialised in #563 and realised the acquire-failure path has no rollback at all. Rolling the connection back on failure, while the transaction mutex is still held, clears the half-open transaction and leaves a successful acquire untouched, so I kept the change inside _acquire.