mirror of
https://github.com/seaweedfs/seaweedfs.git
synced 2026-10-30 00:40:44 +01: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>
87 lines
3.2 KiB
Go
87 lines
3.2 KiB
Go
package blockvol
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"time"
|
|
)
|
|
|
|
// BlockVolConfig configures tunable parameters for a BlockVol engine.
|
|
// A zero-value config is valid and will use defaults via applyDefaults().
|
|
type BlockVolConfig struct {
|
|
GroupCommitMaxDelay time.Duration // max wait before flushing a partial batch (default 1ms)
|
|
GroupCommitMaxBatch int // flush immediately when this many waiters (default 64)
|
|
GroupCommitLowWatermark int // skip delay if fewer than this many pending (default 4)
|
|
WALPressureThreshold float64 // fraction of WAL used that triggers urgent flush (default 0.8)
|
|
WALFullTimeout time.Duration // max retry time when WAL is full (default 5s)
|
|
FlushInterval time.Duration // flusher periodic interval (default 100ms)
|
|
DirtyMapShards int // number of dirty map shards, must be power-of-2 (default 256)
|
|
}
|
|
|
|
// DefaultConfig returns a BlockVolConfig with production defaults.
|
|
func DefaultConfig() BlockVolConfig {
|
|
return BlockVolConfig{
|
|
GroupCommitMaxDelay: 1 * time.Millisecond,
|
|
GroupCommitMaxBatch: 64,
|
|
GroupCommitLowWatermark: 4,
|
|
WALPressureThreshold: 0.8,
|
|
WALFullTimeout: 5 * time.Second,
|
|
FlushInterval: 100 * time.Millisecond,
|
|
DirtyMapShards: 256,
|
|
}
|
|
}
|
|
|
|
// applyDefaults fills zero-value fields with production defaults.
|
|
func (c *BlockVolConfig) applyDefaults() {
|
|
d := DefaultConfig()
|
|
if c.GroupCommitMaxDelay == 0 {
|
|
c.GroupCommitMaxDelay = d.GroupCommitMaxDelay
|
|
}
|
|
if c.GroupCommitMaxBatch == 0 {
|
|
c.GroupCommitMaxBatch = d.GroupCommitMaxBatch
|
|
}
|
|
if c.GroupCommitLowWatermark == 0 {
|
|
c.GroupCommitLowWatermark = d.GroupCommitLowWatermark
|
|
}
|
|
if c.WALPressureThreshold == 0 {
|
|
c.WALPressureThreshold = d.WALPressureThreshold
|
|
}
|
|
if c.WALFullTimeout == 0 {
|
|
c.WALFullTimeout = d.WALFullTimeout
|
|
}
|
|
if c.FlushInterval == 0 {
|
|
c.FlushInterval = d.FlushInterval
|
|
}
|
|
if c.DirtyMapShards == 0 {
|
|
c.DirtyMapShards = d.DirtyMapShards
|
|
}
|
|
}
|
|
|
|
var errInvalidConfig = errors.New("blockvol: invalid config")
|
|
|
|
// Validate checks that config values are within acceptable ranges.
|
|
func (c *BlockVolConfig) Validate() error {
|
|
if c.DirtyMapShards <= 0 || (c.DirtyMapShards&(c.DirtyMapShards-1)) != 0 {
|
|
return fmt.Errorf("%w: DirtyMapShards must be a positive power-of-2, got %d", errInvalidConfig, c.DirtyMapShards)
|
|
}
|
|
if c.WALPressureThreshold <= 0 || c.WALPressureThreshold > 1 {
|
|
return fmt.Errorf("%w: WALPressureThreshold must be in (0,1], got %f", errInvalidConfig, c.WALPressureThreshold)
|
|
}
|
|
if c.GroupCommitMaxDelay <= 0 {
|
|
return fmt.Errorf("%w: GroupCommitMaxDelay must be positive, got %v", errInvalidConfig, c.GroupCommitMaxDelay)
|
|
}
|
|
if c.GroupCommitMaxBatch <= 0 {
|
|
return fmt.Errorf("%w: GroupCommitMaxBatch must be positive, got %d", errInvalidConfig, c.GroupCommitMaxBatch)
|
|
}
|
|
if c.GroupCommitLowWatermark < 0 {
|
|
return fmt.Errorf("%w: GroupCommitLowWatermark must be >= 0, got %d", errInvalidConfig, c.GroupCommitLowWatermark)
|
|
}
|
|
if c.WALFullTimeout <= 0 {
|
|
return fmt.Errorf("%w: WALFullTimeout must be positive, got %v", errInvalidConfig, c.WALFullTimeout)
|
|
}
|
|
if c.FlushInterval <= 0 {
|
|
return fmt.Errorf("%w: FlushInterval must be positive, got %v", errInvalidConfig, c.FlushInterval)
|
|
}
|
|
return nil
|
|
}
|