cache

package
v0.0.17 Latest Latest
Warning

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

Go to latest
Published: Apr 27, 2026 License: AGPL-3.0 Imports: 15 Imported by: 0

Documentation

Overview

Package cache provides a unified caching interface for cc-relay.

The cache package abstracts over three cache backends:

  • Single mode (Ristretto): High-performance local in-memory cache
  • HA mode (Olric): Distributed cache for high-availability deployments
  • Disabled mode (Noop): Passthrough when caching is disabled

All implementations are safe for concurrent use.

Basic usage:

cfg := cache.Config{
	Mode: cache.ModeSingle,
	Ristretto: cache.RistrettoConfig{
		NumCounters: 1e6,
		MaxCost:     100 << 20, // 100 MB
		BufferItems: 64,
	},
}

c, err := cache.New(context.Background(), cfg)
if err != nil {
	log.Fatal(err)
}
defer c.Close()

// Store a value with TTL
err = c.SetWithTTL(ctx, "key", []byte("value"), 5*time.Minute)

// Retrieve a value
data, err := c.Get(ctx, "key")
if errors.Is(err, cache.ErrNotFound) {
	// Cache miss
}

Index

Constants

View Source
const (
	// EnvLocal is for local development (fast failure detection).
	EnvLocal = "local"
	// EnvLAN is for LAN environments (default memberlist settings).
	EnvLAN = "lan"
	// EnvWAN is for WAN environments (longer timeouts for higher latency).
	EnvWAN = "wan"
)

Environment constants for Olric memberlist presets.

Variables

View Source
var (
	// ErrNotFound is returned when a key does not exist in the cache.
	ErrNotFound = errors.New("cache: key not found")

	// ErrClosed is returned when operations are attempted on a closed cache.
	ErrClosed = errors.New("cache: cache is closed")
)

Standard errors for cache operations.

Use errors.Is to check for these errors:

data, err := c.Get(ctx, key)
if errors.Is(err, cache.ErrNotFound) {
	// handle cache miss
}
View Source
var (

	// Logger is the package-level logger for cache operations.
	// Uses a no-op logger by default to avoid logging until explicitly configured.
	// The logger is tagged with component: cache for easy filtering.
	Logger = zerolog.Nop()
)

Functions

This section is empty.

Types

type Cache

type Cache interface {
	// Get retrieves a value from the cache.
	// Returns ErrNotFound if the key does not exist.
	// Returns ErrClosed if the cache has been closed.
	Get(ctx context.Context, key string) ([]byte, error)

	// Set stores a value in the cache with no expiration.
	// Returns ErrClosed if the cache has been closed.
	Set(ctx context.Context, key string, value []byte) error

	// SetWithTTL stores a value in the cache with a time-to-live.
	// After the TTL expires, the key will no longer be retrievable.
	// Returns ErrClosed if the cache has been closed.
	SetWithTTL(ctx context.Context, key string, value []byte, ttl time.Duration) error

	// Delete removes a key from the cache.
	// Returns nil if the key does not exist (idempotent).
	// Returns ErrClosed if the cache has been closed.
	Delete(ctx context.Context, key string) error

	// Exists checks if a key exists in the cache.
	// Returns ErrClosed if the cache has been closed.
	Exists(ctx context.Context, key string) (bool, error)

	// Close releases resources associated with the cache.
	// After Close is called, all operations will return ErrClosed.
	// Close is idempotent.
	Close() error
}

Cache defines the interface for cache operations. All implementations must be safe for concurrent use.

func New

func New(ctx context.Context, cfg *Config) (Cache, error)

New creates a new Cache based on the configuration. It returns an error if the configuration is invalid or if the cache backend fails to initialize.

The context is used for initialization of distributed caches (ModeHA). For local caches (ModeSingle, ModeDisabled), the context is not used but is included for API consistency.

Example:

cfg := cache.Config{
	Mode: cache.ModeSingle,
	Ristretto: cache.RistrettoConfig{
		NumCounters: 1e6,
		MaxCost:     100 << 20, // 100 MB
		BufferItems: 64,
	},
}
c, err := cache.New(ctx, cfg)
if err != nil {
	log.Fatal(err)
}
defer c.Close()

type ClusterInfo

type ClusterInfo interface {
	// MemberlistAddr returns the memberlist address of this node.
	// This is the address other nodes should use in their Peers list to join.
	// Returns empty string if not in embedded mode or not yet started.
	MemberlistAddr() string

	// ClusterMembers returns the number of members in the cluster.
	// Returns 0 if not in embedded mode or unable to get stats.
	ClusterMembers() int

	// IsEmbedded returns true if this cache is running an embedded Olric node.
	// Client mode caches return false.
	IsEmbedded() bool
}

ClusterInfo is an optional interface for distributed caches that support clustering. Use type assertion to check if a cache implements this interface:

if ci, ok := c.(cache.ClusterInfo); ok {
	addr := ci.MemberlistAddr()
	members := ci.ClusterMembers()
}

type Config

type Config struct {
	Mode      Mode            `yaml:"mode" toml:"mode"`
	Olric     OlricConfig     `yaml:"olric" toml:"olric"`
	Ristretto RistrettoConfig `yaml:"ristretto" toml:"ristretto"`
}

Config defines cache configuration. Use Validate() to check for configuration errors before creating a cache.

func (*Config) Validate

func (c *Config) Validate() error

Validate checks the configuration for errors. Returns nil if the configuration is valid.

type Mode

type Mode string

Mode represents the cache operating mode.

const (
	// ModeSingle uses local Ristretto cache (default).
	// Best for single-instance deployments with high performance requirements.
	ModeSingle Mode = "single"

	// ModeHA uses distributed Olric cache for high availability.
	// Best for multi-instance deployments requiring shared cache state.
	ModeHA Mode = "ha"

	// ModeDisabled uses noop cache (caching disabled).
	// All operations return immediately without storing data.
	ModeDisabled Mode = "disabled"
)

type OlricConfig

type OlricConfig struct {
	DMapName          string        `yaml:"dmap_name" toml:"dmap_name"`
	BindAddr          string        `yaml:"bind_addr" toml:"bind_addr"`
	Environment       string        `yaml:"environment" toml:"environment"`
	Addresses         []string      `yaml:"addresses" toml:"addresses"`
	Peers             []string      `yaml:"peers" toml:"peers"`
	ReplicaCount      int           `yaml:"replica_count" toml:"replica_count"`
	ReadQuorum        int           `yaml:"read_quorum" toml:"read_quorum"`
	WriteQuorum       int           `yaml:"write_quorum" toml:"write_quorum"`
	LeaveTimeout      time.Duration `yaml:"leave_timeout" toml:"leave_timeout"`
	MemberCountQuorum int32         `yaml:"member_count_quorum" toml:"member_count_quorum"`
	Embedded          bool          `yaml:"embedded" toml:"embedded"`
}

OlricConfig configures the Olric distributed cache. Olric provides a distributed in-memory key/value store with clustering support.

func DefaultOlricConfig

func DefaultOlricConfig() OlricConfig

DefaultOlricConfig returns an OlricConfig with sensible defaults. These defaults match Olric's internal defaults and are suitable for single-node operation. Users can override for HA deployments requiring replication and quorum settings.

func (*OlricConfig) Validate

func (o *OlricConfig) Validate() error

Validate checks OlricConfig for errors.

type Pinger

type Pinger interface {
	// Ping verifies the cache connection is alive.
	// For local caches, this always returns nil.
	// For distributed caches, this validates cluster connectivity.
	Ping(ctx context.Context) error
}

Pinger is an optional interface for caches that support health checks. For local caches, Ping always returns nil. For distributed caches, Ping validates cluster connectivity.

Use type assertion to check if a cache implements this interface:

if p, ok := c.(cache.Pinger); ok {
	if err := p.Ping(ctx); err != nil {
		// handle unhealthy cache
	}
}

type RistrettoConfig

type RistrettoConfig struct {
	// NumCounters is the number of 4-bit access counters.
	// Recommended: 10x expected max items for optimal admission policy.
	// Example: For 100,000 items, use 1,000,000 counters.
	NumCounters int64 `yaml:"num_counters" toml:"num_counters"`

	// MaxCost is the maximum cost (memory) the cache can hold.
	// Cost is measured in bytes of cached values.
	// Example: 100 << 20 for 100 MB.
	MaxCost int64 `yaml:"max_cost" toml:"max_cost"`

	// BufferItems is the number of keys per Get buffer.
	// This controls the size of the admission buffer.
	// Recommended: 64 (default).
	BufferItems int64 `yaml:"buffer_items" toml:"buffer_items"`
}

RistrettoConfig configures the Ristretto local cache. Ristretto is a high-performance, concurrent cache based on research from the Caffeine library.

func DefaultRistrettoConfig

func DefaultRistrettoConfig() RistrettoConfig

DefaultRistrettoConfig returns a RistrettoConfig with sensible defaults. NumCounters: 1,000,000 (for ~100K items). MaxCost: 100 MB. BufferItems: 64.

type Stats

type Stats struct {
	// Hits is the number of cache hits.
	Hits uint64 `json:"hits"`

	// Misses is the number of cache misses.
	Misses uint64 `json:"misses"`

	// KeyCount is the current number of keys in the cache.
	KeyCount uint64 `json:"key_count"`

	// BytesUsed is the approximate memory used by cached values.
	BytesUsed uint64 `json:"bytes_used"`

	// Evictions is the number of keys evicted due to capacity limits.
	Evictions uint64 `json:"evictions"`
}

Stats provides cache statistics for observability.

type StatsProvider

type StatsProvider interface {
	// Stats returns current cache statistics.
	Stats() Stats
}

StatsProvider is an optional interface for caches that support statistics. Use type assertion to check if a cache implements this interface:

if sp, ok := c.(cache.StatsProvider); ok {
	stats := sp.Stats()
	// use stats
}

Jump to

Keyboard shortcuts

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