ds-ring-buffer-lockfree
Design – A lock-free SPSC (single producer, single consumer) ring buffer. The buffer is a fixed-size slice rounded up to a power of two. Head and tail are monotonically increasing uint64 counters manipulated only via atomic.LoadUint64/atomic.StoreUint64:
tail+1 (release). head+1 (release). Because Go's atomic operations provide sequential consistency, the release store of tail guarantees the slot write is globally visible before the consumer sees the advanced tail. Similarly, the release store of head guarantees the slot read completes before the producer reuses that slot.
Key implementation (ringbuffer.go):
type RingBuffer struct {
buffer []interface{}
capacity uint64
mask uint64 // capacity-1 (power of two)
head uint64 // written by consumer, read by producer
tail uint64 // written by producer, read by consumer
}
func (rb *RingBuffer) Enqueue(item interface{}) bool {
tail := atomic.LoadUint64(&rb.tail)
head := atomic.LoadUint64(&rb.head)
if tail-head >= rb.capacity {
return false // full
}
rb.buffer[tail&rb.mask] = item
atomic.StoreUint64(&rb.tail, tail+1)
return true
}
func (rb *RingBuffer) Dequeue() (interface{}, bool) {
head := atomic.LoadUint64(&rb.head)
tail := atomic.LoadUint64(&rb.tail)
if head == tail {
return nil, false // empty
}
idx := head & rb.mask
item := rb.buffer[idx]
rb.buffer[idx] = nil // help GC
atomic.StoreUint64(&rb.head, head+1)
return item, true
}
Wrap-around – uint64 counters naturally overflow (after 2⁶⁴ operations), and tail - head remains correct because unsigned subtraction wraps around too. The & mask trick indexes into the circular buffer regardless of the counter values.
All tests pass with the Go race detector (`-race`). Nine test cases covering: | Test | What it checks | |------|----------------| | `TestEnqueueDequeue` | Basic single-item push/pop | | `TestFIFOOrdering` | Strict FIFO order preserved | | `TestFull` | Full buffer rejects new items | | `TestEmptyDequeue` | Empty buffer returns nil,false | | `TestWrapAround` | 100 fill/drain cycles + partial wrap | | `TestConcurrentSPSC` | 10,000 items through separate producer/consumer goroutines, each value delivered exactly once | | `TestLargeWrap` | head/tail initialized to `^uint64(0)-2` (near max), verifies overflow is harmless | | `TestCapacityRounding` | Requests of 0,1,2,3,4,5,100,1024 → correct powers of two | | `TestConcurrentStress` | 50,000 items + sentinel with busy-spin, race detector enabled | ``` $ go test -v -count=1 -race === RUN TestEnqueueDequeue --- PASS === RUN TestFIFOOrdering --- PASS === RUN TestFull --- PASS === RUN TestEmptyDequeue --- PASS === RUN TestWrapAround --- PASS === RUN TestConcurrentSPSC --- PASS === RUN TestLargeWrap --- PASS === RUN TestCapacityRounding --- PASS === RUN TestConcurrentStress --- PASS (enqueue OK: 50000, dequeue OK: 50001) PASS ok ringbuffer 1.050s ``` ---
{"model": "claude-sonnet-4-20250514", "problem_class": "ds-ring-buffer-lockfree", "result": "passed", "tests": 9}