Fix diagnostics reading live NOMUTEX reader connections#156
Merged
Conversation
resqlite_db_status_total skips readers marked in_use, but that flag has been dead code since exp 030 moved workers to dedicated reader assignment — Database.diagnostics() was calling sqlite3_db_status on reader connections actively executing queries on their worker threads. Connections are NOMUTEX, and SQLITE_DBSTATUS_SCHEMA_USED measures memory via the connection's pnBytesFreed dry-run mechanism; toggling it under a mid-query reader corrupts that reader's allocation accounting (observed as a flaky reader-isolate SEGV in sqlite3VdbeDelete once exp 160's detached admission reads made readers reliably busy at diagnostics-poll time, ~1-in-30 stream_test runs). Read workers now bracket each request with resqlite_reader_set_busy (atomic store, two leaf FFI calls per request), making the existing busy guard real; diagnostics reports those readers as a partial snapshot exactly as the existing in_use contract intended. The sacrifice path clears the bracket before Isolate.exit since exit skips finally. Validated on the exp 160 branch: crash reproduced pre-fix, 100/100 clean stress iterations and 8/8 full-suite runs post-fix. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
danReynolds
added a commit
that referenced
this pull request
Jun 10, 2026
The rebase onto main (which landed the diagnostics race fix via #156) re-applied the function on top of main's copy. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
4 tasks
Merged
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.
Problem
resqlite_db_status_totalskips readers markedin_use— but that flag has been dead code since exp 030 gave workers dedicated readers (exp 051 documented the acquire path as dead).Database.diagnostics()was therefore callingsqlite3_db_statuson live NOMUTEX reader connections from the main isolate.SCHEMA_USEDmeasures memory by toggling the connection'spnBytesFreeddry-run mechanism; doing that under a mid-query reader corrupts the reader's allocation accounting — a latent heap-corruption race on main, observed as a flaky reader-isolate SEGV (sqlite3VdbeDelete→ allocation-size read at null) at ~1-in-30 stream_test runs once exp 160's detached admission reads made readers reliably busy at diagnostics-poll time.Fix
Read workers bracket each request with
resqlite_reader_set_busy(atomic store, two ~ns leaf FFI calls per request), making the existing busy guard real — diagnostics reports busy readers as a partial snapshot exactly as thein_usecontract always intended. The sacrifice path clears the bracket beforeIsolate.exit(exit skipsfinally).Split out of #155 so the crash fix lands on main independently of the IVM review; the investigation record (bisection, crash trace, stress validation) lives in that PR's experiment doc.
Test plan
dart analyzeclean; stream/diagnostics/database tests pass🤖 Generated with Claude Code