Fix CI failure: DB Reopen race and install test drift - #63
Conversation
After swapping atomic pointers in reopenLocked, the old *sql.DB pools were closed immediately. Concurrent readers that had already loaded the old pointer could then query a closed pool and get an error. Defer closing for 5 seconds so in-flight queries can complete. Fixes TestConcurrentReadsWhileReopen CI failure on ubuntu-latest. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace time.AfterFunc(5s) with a retired pool list. Old reader/writer pools are kept open until DB.Close() so concurrent readers that loaded the pointer before the swap can finish without hitting a closed pool. This eliminates the race deterministically rather than relying on a heuristic delay. Addresses review #7559 finding 1 (non-deterministic handoff) and finding 2 (resource accumulation under rapid reopens). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Guard install.sh main() with BASH_SOURCE check so the test can source the file and call get_latest_version directly with a mocked curl. Removes the duplicated parse_tag_name function that could drift from production logic. Also uses printf instead of echo for fixture piping. Addresses review #7558 findings 1 (test drift) and 2 (echo robustness). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…ections - reopenLocked now closes pools from the previous reopen cycle before retiring the current pair, bounding the retired list to 2 entries. - Close() takes db.mu when accessing the retired slice to avoid racing with concurrent Reopen calls. - CloseConnections() drains retired pools, honoring its contract of releasing all file locks. - Add tests: repeated-reopen bounding, CloseConnections+Reopen+Close lifecycle, race detector coverage. Addresses review #7560 findings 1, 2, and 3. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
roborev: Combined Review (
|
roborev: Combined Review (
|
Previously close errors on retired pools were silently discarded. Now they are logged as warnings for observability. Addresses review #7562 finding 2. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Snapshot the current writer and reader pointers while holding db.mu, so a hypothetical concurrent Reopen cannot swap them between the snapshot and the close calls. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
roborev: Combined Review (
|
BASH_SOURCE[0] is unset when piped via stdin, which combined with
set -u caused an unbound variable error. Use ${BASH_SOURCE[0]-}
with an empty-string fallback and treat unset/empty as direct
execution to support both `bash script.sh` and `curl ... | bash`.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
roborev: Combined Review (
|
|
acceptable risk. merging |
## Summary - **Fix DB Reopen race** (`internal/db/db.go`): `reopenLocked()` was closing old `*sql.DB` pools immediately after swapping atomic pointers, causing concurrent readers to hit `sql: database is closed`. Old pools are now retired into a list and closed in `DB.Close()`, eliminating the race deterministically. - **Fix install test drift** (`scripts/install.sh`, `scripts/install_test.sh`): The test duplicated the grep/cut parsing logic from `install.sh`. Added a `BASH_SOURCE` guard to `install.sh` so the test can source it and call `get_latest_version` directly with a mocked `curl`. Also switched from `echo` to `printf` for reliable fixture piping. ## Test plan - [x] `TestConcurrentReadsWhileReopen` passes 5x with `-count=5` - [x] All `TestReopen*`, `TestCloseConnections`, `TestCloseRenameReopen` pass - [x] Full `internal/db` test suite passes - [x] `scripts/install_test.sh` passes (6/6) - [x] `install.sh` syntax check passes (`bash -n`) - [x] `go vet` and `go fmt` clean 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Summary
internal/db/db.go):reopenLocked()was closing old*sql.DBpools immediately after swapping atomic pointers, causing concurrent readers to hitsql: database is closed. Old pools are now retired into a list and closed inDB.Close(), eliminating the race deterministically.scripts/install.sh,scripts/install_test.sh): The test duplicated the grep/cut parsing logic frominstall.sh. Added aBASH_SOURCEguard toinstall.shso the test can source it and callget_latest_versiondirectly with a mockedcurl. Also switched fromechotoprintffor reliable fixture piping.Test plan
TestConcurrentReadsWhileReopenpasses 5x with-count=5TestReopen*,TestCloseConnections,TestCloseRenameReopenpassinternal/dbtest suite passesscripts/install_test.shpasses (6/6)install.shsyntax check passes (bash -n)go vetandgo fmtclean🤖 Generated with Claude Code