Commit 1b24a10
committed
Call interrupt before close in disconnect to fix deadlock
When DBConnection times out a long-running query, it calls disconnect/2
on the connection process. Previously, disconnect only called Sqlite3.close(),
which blocks on conn->mutex held by the still-running dirty NIF — deadlocking
the pool permanently.
Now disconnect calls Sqlite3.interrupt(db) first, which sets a flag checked
at every VDBE loop iteration (OP_Next, OP_Prev, etc.). The running query
aborts with SQLITE_INTERRUPT, releases the mutex, and close() proceeds.
This is safe because PR #342 (v0.35.0) added interrupt_mutex to the NIF
layer, which prevents a use-after-free race between interrupt() and close().
The interrupt_mutex ensures interrupt reads the db pointer atomically even
if close() is freeing it concurrently.
Test results before this change:
149 tests, 20 pass, 2 fail (pool recovery test deadlocks at 30s timeout)
Test results after this change:
160 tests, 2 failures
- 21 of 22 cancellation tests now pass (busy handler test still fails as expected)
- The integration test "exceeding timeout" fails with a pattern match error
(expects {:ok, _, _} but gets {:error, "interrupted"} — will be fixed later)
The passing cancellation tests demonstrate that interrupt successfully unblocks
queries stuck in VDBE execution, fixing the primary deadlock issue.
Known limitation: does not fix the case where a query is stuck in SQLite's
busy handler sleep loop (waiting for a lock held by another connection).
That requires a custom busy handler (separate change).
Fixes the primary deadlock described in #192.1 parent 508419e commit 1b24a10
1 file changed
Lines changed: 5 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
212 | 212 | | |
213 | 213 | | |
214 | 214 | | |
| 215 | + | |
| 216 | + | |
| 217 | + | |
| 218 | + | |
| 219 | + | |
215 | 220 | | |
216 | 221 | | |
217 | 222 | | |
| |||
0 commit comments