Files
seaweedfs/weed/storage/blockvol/bug_gc_panic_test.go
T
Ping QiuandClaude Opus 4.6 80801b0fac feat: Phase 3 — performance tuning, iSCSI session refactor, store integration
Phase 3 delivers five checkpoints:

CP1 Engine Tuning: BlockVolConfig tunables, 256-shard DirtyMap, adaptive
group commit (low-watermark immediate flush), WAL pressure handling with
backpressure and ErrWALFull timeout.

CP2 iSCSI Session Refactor: RX/TX goroutine split with respCh (cap 64),
txLoop for serialized response writes, StatSN assignment modes. Login
phase stays single-goroutine; full-duplex after login.

CP3 Store Integration: BlockVolAdapter (iscsi.BlockDevice interface),
BlockVolumeStore management, BlockService in volume_server_block.go,
CLI flags (--block.listen/dir/iqn.prefix), sw-block-attach.sh helper.

CP5 Concurrency Hardening: WAL reuse guard (LSN validation in ReadLBA),
opsOutstanding counter with beginOp/endOp + Close drain, appendWithRetry
shared by WriteLBA and TrimLBA, flusher LSN guard in FlushOnce.

Bug fixes (P3-BUG-2–11): unbounded pending queue cap, Data-Out timeout,
flusher error logging, GroupCommitter panic recovery, Close vs concurrent
ops guard, target shutdown race, WAL-full retry vs Close, WRITE SAME(16)
for XFS, MODE SENSE(10) + VPD 0xB0/0xB2 for Linux kernel compatibility.

797 tests passing (517 engine + 280 iSCSI), go vet clean.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 10:43:34 -08:00

50 lines
1.2 KiB
Go

package blockvol
import (
"testing"
"time"
)
// TestBugGCPanicWaitersHung demonstrates that a panic in syncFunc
// leaves all Submit() waiters permanently blocked.
//
// BUG: Run() has no panic recovery. When syncFunc panics, the batch
// of waiters (each blocked on <-ch in Submit) are never notified.
// They hang forever, leaking goroutines.
//
// FIX: Add defer/recover in Run() that drains pending waiters with
// an error before exiting.
//
// This test FAILS until the bug is fixed.
func TestBugGCPanicWaitersHung(t *testing.T) {
gc := NewGroupCommitter(GroupCommitterConfig{
SyncFunc: func() error {
panic("simulated disk panic")
},
MaxDelay: 10 * time.Millisecond,
})
// Wrap Run() so the panic doesn't kill the test process.
go func() {
defer func() { recover() }()
gc.Run()
}()
// Submit should return an error (not hang forever).
result := make(chan error, 1)
go func() {
result <- gc.Submit()
}()
select {
case err := <-result:
// GOOD: Submit returned (with an error, presumably).
if err == nil {
t.Error("Submit returned nil; expected a panic-related error")
}
t.Logf("Submit returned: %v", err)
case <-time.After(3 * time.Second):
t.Fatal("BUG: Submit hung forever after syncFunc panic -- waiters not drained")
}
}