fix(storage): race condition when reconnect closes db mid-query (GH#607)

Change reconnectMu from sync.Mutex to sync.RWMutex so read operations
can hold RLock during database access. This prevents reconnect() from
closing the connection while queries are in progress.

- GetIssue and SearchIssues now hold RLock during database operations
- Close() acquires write lock to coordinate with reconnect
- Add TestConcurrentReadsWithReconnect to verify the fix

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Steve Yegge
2025-12-18 11:27:58 -08:00
parent e0d8abe8c3
commit 6087cd438b
3 changed files with 155 additions and 1 deletions

View File

@@ -28,7 +28,7 @@ type SQLiteStorage struct {
connStr string // Connection string for reconnection
busyTimeout time.Duration
freshness *FreshnessChecker // Optional freshness checker for daemon mode
reconnectMu sync.Mutex // Protects reconnection
reconnectMu sync.RWMutex // Protects reconnection and db access (GH#607)
}
// setupWASMCache configures WASM compilation caching to reduce SQLite startup time.
@@ -207,6 +207,9 @@ func NewWithTimeout(ctx context.Context, path string, busyTimeout time.Duration)
// It checkpoints the WAL to ensure all writes are flushed to the main database file.
func (s *SQLiteStorage) Close() error {
s.closed.Store(true)
// Acquire write lock to prevent racing with reconnect() (GH#607)
s.reconnectMu.Lock()
defer s.reconnectMu.Unlock()
// Checkpoint WAL to ensure all writes are persisted to the main database file.
// Without this, writes may be stranded in the WAL and lost between CLI invocations.
_, _ = s.db.Exec("PRAGMA wal_checkpoint(TRUNCATE)")