mirror of
https://github.com/seaweedfs/seaweedfs.git
synced 2026-10-20 13:04:25 +02: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>
94 lines
2.4 KiB
Go
94 lines
2.4 KiB
Go
package storage
|
|
|
|
import (
|
|
"fmt"
|
|
"sync"
|
|
|
|
"github.com/seaweedfs/seaweedfs/weed/glog"
|
|
"github.com/seaweedfs/seaweedfs/weed/storage/blockvol"
|
|
)
|
|
|
|
// BlockVolumeStore manages block volumes (iSCSI-backed).
|
|
// It is a standalone component held by VolumeServer, not embedded into Store,
|
|
// to keep the existing Store codebase unchanged.
|
|
type BlockVolumeStore struct {
|
|
mu sync.RWMutex
|
|
volumes map[string]*blockvol.BlockVol // keyed by volume file path
|
|
}
|
|
|
|
// NewBlockVolumeStore creates a new block volume manager.
|
|
func NewBlockVolumeStore() *BlockVolumeStore {
|
|
return &BlockVolumeStore{
|
|
volumes: make(map[string]*blockvol.BlockVol),
|
|
}
|
|
}
|
|
|
|
// AddBlockVolume opens and registers a block volume.
|
|
func (bs *BlockVolumeStore) AddBlockVolume(path string, cfgs ...blockvol.BlockVolConfig) (*blockvol.BlockVol, error) {
|
|
bs.mu.Lock()
|
|
defer bs.mu.Unlock()
|
|
|
|
if _, ok := bs.volumes[path]; ok {
|
|
return nil, fmt.Errorf("block volume already registered: %s", path)
|
|
}
|
|
|
|
vol, err := blockvol.OpenBlockVol(path, cfgs...)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("open block volume %s: %w", path, err)
|
|
}
|
|
|
|
bs.volumes[path] = vol
|
|
glog.V(0).Infof("block volume registered: %s", path)
|
|
return vol, nil
|
|
}
|
|
|
|
// RemoveBlockVolume closes and unregisters a block volume.
|
|
func (bs *BlockVolumeStore) RemoveBlockVolume(path string) error {
|
|
bs.mu.Lock()
|
|
defer bs.mu.Unlock()
|
|
|
|
vol, ok := bs.volumes[path]
|
|
if !ok {
|
|
return fmt.Errorf("block volume not found: %s", path)
|
|
}
|
|
|
|
if err := vol.Close(); err != nil {
|
|
glog.Warningf("error closing block volume %s: %v", path, err)
|
|
}
|
|
delete(bs.volumes, path)
|
|
glog.V(0).Infof("block volume removed: %s", path)
|
|
return nil
|
|
}
|
|
|
|
// GetBlockVolume returns a registered block volume by path.
|
|
func (bs *BlockVolumeStore) GetBlockVolume(path string) (*blockvol.BlockVol, bool) {
|
|
bs.mu.RLock()
|
|
defer bs.mu.RUnlock()
|
|
vol, ok := bs.volumes[path]
|
|
return vol, ok
|
|
}
|
|
|
|
// ListBlockVolumes returns the paths of all registered block volumes.
|
|
func (bs *BlockVolumeStore) ListBlockVolumes() []string {
|
|
bs.mu.RLock()
|
|
defer bs.mu.RUnlock()
|
|
paths := make([]string, 0, len(bs.volumes))
|
|
for p := range bs.volumes {
|
|
paths = append(paths, p)
|
|
}
|
|
return paths
|
|
}
|
|
|
|
// Close closes all block volumes.
|
|
func (bs *BlockVolumeStore) Close() {
|
|
bs.mu.Lock()
|
|
defer bs.mu.Unlock()
|
|
for path, vol := range bs.volumes {
|
|
if err := vol.Close(); err != nil {
|
|
glog.Warningf("error closing block volume %s: %v", path, err)
|
|
}
|
|
delete(bs.volumes, path)
|
|
}
|
|
glog.V(0).Infof("all block volumes closed")
|
|
}
|