ringbuffer

package
v0.2.0-alpha.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 5, 2026 License: Apache-2.0 Imports: 1 Imported by: 0

README

pkg/events/ringbuffer

Fixed-size thread-safe ring buffer using Go generics. When it fills up, new items overwrite the oldest. Used by pkg/controller/debug for the /debug/vars/events endpoint. pkg/controller/commentator has its own specialised (non-generic) ring buffer with richer queries — if you're looking for how insights / correlation work, look there instead.

No dependencies beyond the standard library — the package could be lifted out verbatim.

API

import "gitlab.com/haproxy-haptic/haptic/pkg/events/ringbuffer"

buf := ringbuffer.New[Event](1000)   // capacity, not starting length

buf.Add(evt)                          // O(1); overwrites oldest when full

recent := buf.GetLast(100)            // up to 100 newest items, oldest-first
all    := buf.GetAll()                // everything currently held, oldest-first
n      := buf.Len()                   // current count (≤ capacity)

All four operations are safe for concurrent use (sync.RWMutex). GetLast / GetAll return freshly allocated slices — mutating the returned slice does not affect the buffer, but the elements themselves are shared: if T has pointer fields, deep-copy before mutating.

Behaviour

  • The buffer is always returned in chronological order (oldest first), regardless of where the internal write head happens to be.
  • GetLast(n) where n > Len() returns everything — it doesn't pad.
  • Add never allocates after construction; the backing slice is reused in place.

Sizing

Target capacity = rate × retention-window:

Use case Rate Window Size
Debug /debug/vars/events event bus throughput operator-friendly replay ~1000
Sliding-window metric 1/s 60s 60

For large T, store pointers so the fixed-size backing array only holds one pointer per slot instead of the full struct.

See Also

  • pkg/controller/debug — primary consumer; exposes the buffer via /debug/vars/events
  • pkg/controller/commentator — domain-specific ring buffer (separate implementation) used for log-line event correlation
  • pkg/events/ringbuffer/CLAUDE.md — developer context (wrap-around semantics, concurrency tests)

License

Apache-2.0 — see root LICENSE.

Documentation

Overview

Package ringbuffer provides a thread-safe generic ring buffer implementation.

A ring buffer (circular buffer) is a fixed-size buffer that wraps around when full. This implementation uses Go generics to support any type and provides thread-safe operations through mutex locking.

Example usage:

type Event struct {
    Timestamp time.Time
    Message   string
}

buffer := ringbuffer.New[Event](100)
buffer.Add(Event{Timestamp: time.Now(), Message: "Event 1"})
recent := buffer.GetLast(10)  // Get last 10 events

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type RingBuffer

type RingBuffer[T any] struct {
	// contains filtered or unexported fields
}

RingBuffer is a thread-safe circular buffer that stores a fixed number of items. When the buffer is full, new items overwrite the oldest items.

The buffer uses Go generics to support any type T.

func New

func New[T any](size int) *RingBuffer[T]

New creates a new ring buffer with the specified capacity.

The size parameter determines the maximum number of items the buffer can hold. Once full, adding new items will overwrite the oldest items.

Example:

buffer := ringbuffer.New[string](100)  // Can hold up to 100 strings

func (*RingBuffer[T]) Add

func (rb *RingBuffer[T]) Add(item T)

Add inserts an item into the buffer.

If the buffer is full, the oldest item is overwritten. This operation is thread-safe.

Example:

buffer.Add("event 1")
buffer.Add("event 2")

func (*RingBuffer[T]) GetAll

func (rb *RingBuffer[T]) GetAll() []T

GetAll returns all items currently in the buffer, in chronological order.

The returned slice is ordered from oldest to newest. This operation is thread-safe.

Example:

all := buffer.GetAll()

func (*RingBuffer[T]) GetLast

func (rb *RingBuffer[T]) GetLast(n int) []T

GetLast returns the n most recently added items, in chronological order.

If n is greater than the number of items in the buffer, all items are returned. The returned slice is ordered from oldest to newest. This operation is thread-safe.

Example:

buffer.Add("event 1")
buffer.Add("event 2")
buffer.Add("event 3")
recent := buffer.GetLast(2)  // Returns ["event 2", "event 3"]

func (*RingBuffer[T]) Len

func (rb *RingBuffer[T]) Len() int

Len returns the current number of items in the buffer.

This operation is thread-safe.

Example:

count := buffer.Len()  // Returns number of items currently stored

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL