Fix critical double-release race in importInProgress flag
CRITICAL BUG: The previous fix had a race condition where the importInProgress flag could be released twice, allowing two goroutines to think they both hold the lock. Bug scenario: 1. Goroutine A: acquires lock (CAS true) 2. Goroutine A: manually releases at line 208 for git dirty skip 3. Goroutine B: CAS succeeds, acquires lock 4. Goroutine A: defer runs, releases flag AGAIN (clears B lock) 5. Goroutine C: CAS succeeds - now TWO goroutines have lock Root cause: Using both manual Store(false) AND defer Store(false) created a window where the flag could be cleared twice. Fix: Use a shouldDeferRelease flag to disable the deferred release when we manually release early. This ensures exactly one release per acquisition. Testing: All auto-import tests still passing 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2
.beads/daemon-stderr.log
Normal file
2
.beads/daemon-stderr.log
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
Error: daemon already running (PID 27867)
|
||||||
|
Use 'bd daemon --stop' to stop it first
|
||||||
@@ -196,7 +196,15 @@ func (s *Server) checkAndAutoImportIfStale(req *Request) error {
|
|||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
defer s.importInProgress.Store(false)
|
|
||||||
|
// Track whether we should release the lock via defer
|
||||||
|
// Set to false if we manually release early to avoid double-release bug
|
||||||
|
shouldDeferRelease := true
|
||||||
|
defer func() {
|
||||||
|
if shouldDeferRelease {
|
||||||
|
s.importInProgress.Store(false)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
// Check if git has uncommitted changes that include beads files (bd-8931)
|
// Check if git has uncommitted changes that include beads files (bd-8931)
|
||||||
// If JSONL files are uncommitted, skip auto-import to avoid conflicts
|
// If JSONL files are uncommitted, skip auto-import to avoid conflicts
|
||||||
@@ -204,8 +212,9 @@ func (s *Server) checkAndAutoImportIfStale(req *Request) error {
|
|||||||
dbDir := filepath.Dir(dbPath)
|
dbDir := filepath.Dir(dbPath)
|
||||||
workspaceRoot := filepath.Dir(dbDir) // Go up from .beads to workspace root
|
workspaceRoot := filepath.Dir(dbDir) // Go up from .beads to workspace root
|
||||||
if hasUncommittedBeadsFiles(workspaceRoot) {
|
if hasUncommittedBeadsFiles(workspaceRoot) {
|
||||||
// CRITICAL: Must release lock before returning to avoid race condition
|
// CRITICAL: Release lock and disable defer to avoid double-release race
|
||||||
s.importInProgress.Store(false)
|
s.importInProgress.Store(false)
|
||||||
|
shouldDeferRelease = false
|
||||||
|
|
||||||
if os.Getenv("BD_DEBUG") != "" {
|
if os.Getenv("BD_DEBUG") != "" {
|
||||||
fmt.Fprintf(os.Stderr, "Debug: skipping auto-import, .beads files have uncommitted changes\n")
|
fmt.Fprintf(os.Stderr, "Debug: skipping auto-import, .beads files have uncommitted changes\n")
|
||||||
|
|||||||
Reference in New Issue
Block a user