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 ¶
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 ¶
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
}
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 ¶
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.
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
}