mirror of
https://github.com/seaweedfs/seaweedfs.git
synced 2026-09-26 18:04:33 +00:00
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>
50 lines
1.2 KiB
Go
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")
|
|
}
|
|
}
|