Put/Delete checked writeStopped then called queue.Submit (which sends on
a channel). Close set writeStopped then closed the channel. With no
synchronization between the check and Submit, a concurrent Close could
close the channel during the window, causing "send on closed channel"
panic in Put/Delete.
The CommitQueue.Close comment said "Callers must stop submitting before
Close" but Put/Delete didn't enforce this.
Changes:
- wal/writer.go: add submitMu sync.RWMutex. Put/Delete construct entry
outside the lock, then hold RLock during writeStopped check + Submit;
release before <-req.Result. Close holds write lock during
writeStopped.Store + queue.Close, guaranteeing no Submit is in progress
when the channel is closed.
- wal/writer_test.go: add TestConcurrentPutCloseNoPanic and
TestConcurrentDeleteCloseNoPanic. 100 goroutines + 1 closer, recover
panics. Run with -count=50 for regression detection.
Verified: all existing tests pass. New concurrent tests pass with
-count=50 (0 panics). go test -race ./... green.
Audit context: docs/audit-3.2.md C7.