Files
seaweedfs/weed/storage/blockvol/nvme/bufpool.go
T
Ping QiuandClaude Opus 4.6 3557ae283f feat: Phase 10 CP10-3 -- NVMe/TCP Tier 1 optimizations, WAL admission control, benchmark platform
CP10-3 Tier 1 optimizations (T1-T4):
- TCP_NODELAY + 256KB socket buffers on NVMe/TCP connections
- Response batching: all C2H data chunks + CapsuleResp in single flush
- Tiered buffer pool (4KB/64KB/256KB sync.Pool) for write payloads
- Configurable MaxH2CDataLength wiring through controller/IC/chunking

BUG-CP103-1: NVMe write retry with jittered backoff for transient WAL pressure
- writeWithRetry() with bounded backoff [50/200/800ms]
- throttleOnWALPressure() pre-write delay above 90% WAL usage
- WALPressureProvider interface + NVMeAdapter.WALPressure()

BUG-CP103-2: Volume-level WAL admission control
- WALAdmission with counting semaphore (max concurrent writers)
- Soft watermark (0.7): small delay to desynchronize herd
- Hard watermark (0.9): block until flusher drains
- Single-deadline budget shared across watermark wait + semaphore
- Close-aware during both watermark and semaphore waits
- Wired into BlockVol.WriteLBA() and Trim()

Benchmark platform enhancements:
- NVMe benchmark actions and scenarios (A/B, CW sweep, IOQ sweep)
- Database benchmark actions (SQLite, pgbench)
- K8s operator QA reconciler tests
- New testrunner scenarios for HA, fault injection, CSI lifecycle

Test counts: 213 NVMe + 625 engine + operator + testrunner tests, all passing.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 17:44:01 -07:00

48 lines
1.2 KiB
Go

package nvme
import "sync"
// bufPool provides tiered buffer pools for NVMe I/O.
// Three tiers: 4KB (small I/O), 64KB (medium), 256KB (large).
var bufPool = struct {
small sync.Pool // 4KB
medium sync.Pool // 64KB
large sync.Pool // 256KB
}{
small: sync.Pool{New: func() any { b := make([]byte, 4096); return &b }},
medium: sync.Pool{New: func() any { b := make([]byte, 65536); return &b }},
large: sync.Pool{New: func() any { b := make([]byte, 262144); return &b }},
}
// getBuffer returns a buffer of at least size bytes from the pool.
func getBuffer(size int) []byte {
switch {
case size <= 4096:
bp := bufPool.small.Get().(*[]byte)
return (*bp)[:size]
case size <= 65536:
bp := bufPool.medium.Get().(*[]byte)
return (*bp)[:size]
case size <= 262144:
bp := bufPool.large.Get().(*[]byte)
return (*bp)[:size]
default:
return make([]byte, size) // oversized: don't pool
}
}
// putBuffer returns a buffer to the appropriate pool.
func putBuffer(buf []byte) {
c := cap(buf)
buf = buf[:c]
switch c {
case 4096:
bufPool.small.Put(&buf)
case 65536:
bufPool.medium.Put(&buf)
case 262144:
bufPool.large.Put(&buf)
// Oversized or wrong-sized: let GC collect
}
}