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>
This commit is contained in:
Ping QiuandClaude Opus 4.6 committed 2026-03-01 10:43:34 -08:00
1 parent 9b7be60b0c
commit 80801b0fac
37 files changed
+6569 -461

No files matched your search

+12
View File
@@ -74,6 +74,10 @@ type VolumeServerOptions struct {
ldbTimeout *int64
debug *bool
debugPort *int
// Block volume (iSCSI) options
blockListen *string
blockDir *string
blockIQNPrefix *string
}
func init() {
@@ -114,6 +118,9 @@ func init() {
v.readBufferSizeMB = cmdVolume.Flag.Int("readBufferSizeMB", 4, "<experimental> larger values can optimize query performance but will increase some memory usage,Use with hasSlowRead normally.")
v.debug = cmdVolume.Flag.Bool("debug", false, "serves runtime profiling data via pprof on the port specified by -debug.port")
v.debugPort = cmdVolume.Flag.Int("debug.port", 6060, "http port for debugging")
v.blockListen = cmdVolume.Flag.String("block.listen", "0.0.0.0:3260", "iSCSI target listen address for block volumes")
v.blockDir = cmdVolume.Flag.String("block.dir", "", "directory containing .blk block volume files. Empty disables iSCSI block service.")
v.blockIQNPrefix = cmdVolume.Flag.String("block.iqn.prefix", "iqn.2024-01.com.seaweedfs:vol.", "IQN prefix for block volume iSCSI targets")
}
var cmdVolume = &Command{
@@ -301,6 +308,9 @@ func (v VolumeServerOptions) startVolumeServer(volumeFolders, maxVolumeCounts, v
// starting the cluster http server
clusterHttpServer := v.startClusterHttpService(volumeMux)
// Start block volume iSCSI service (disabled if block.dir is empty).
blockService := weed_server.StartBlockService(*v.blockListen, *v.blockDir, *v.blockIQNPrefix)
grace.OnReload(volumeServer.LoadNewVolumes)
grace.OnReload(volumeServer.Reload)
@@ -315,6 +325,7 @@ func (v VolumeServerOptions) startVolumeServer(volumeFolders, maxVolumeCounts, v
time.Sleep(time.Duration(*v.preStopSeconds) * time.Second)
}
blockService.Shutdown()
shutdown(publicHttpDown, clusterHttpServer, grpcS, volumeServer)
stopChan <- true
})
@@ -324,6 +335,7 @@ func (v VolumeServerOptions) startVolumeServer(volumeFolders, maxVolumeCounts, v
select {
case <-stopChan:
case <-ctx.Done():
blockService.Shutdown()
shutdown(publicHttpDown, clusterHttpServer, grpcS, volumeServer)
}
} else {