Documentation
¶
Overview ¶
Package cache provides multi-index memory cache with Redis support.
This package offers a generic, thread-safe caching solution with the following features:
- Multi-index lookup support (O(1) lookups by different keys)
- Hash-based change detection
- Redis cache adapter for distributed scenarios
- Automatic TTL management
Example usage:
config := cache.DefaultConfig[User]().WithPrimaryKey(func(u User) string { return u.ID })
cache := cache.NewMultiIndexCache[User](config)
cache.AddIndex("email", func(u User) string { return u.Email })
cache.Set(users)
user, ok := cache.GetByIndex("email", "user@example.com")
Index ¶
- func StringSorter[V any](keyFunc func(V) string) func([]V) []V
- type Cache
- type Config
- func (c *Config[V]) WithHashFunc(fn HashFunc[V]) *Config[V]
- func (c *Config[V]) WithNormalizeFunc(fn NormalizeFunc[V]) *Config[V]
- func (c *Config[V]) WithPrimaryKey(fn KeyFunc[V]) *Config[V]
- func (c *Config[V]) WithSortFunc(fn func(values []V) []V) *Config[V]
- func (c *Config[V]) WithValidateFunc(fn ValidateFunc[V]) *Config[V]
- type HashFunc
- type HybridCache
- func (c *HybridCache[V]) AddIndex(name string, keyFunc KeyFunc[V])
- func (c *HybridCache[V]) GetAll() []V
- func (c *HybridCache[V]) GetByIndex(indexName string, key string) (V, bool)
- func (c *HybridCache[V]) LoadFromRedis() error
- func (c *HybridCache[V]) Memory() *MemoryCache[V]
- func (c *HybridCache[V]) Redis() *RedisCache[V]
- func (c *HybridCache[V]) Set(values []V) error
- func (c *HybridCache[V]) SyncToRedis() error
- type KeyFunc
- type MemoryCache
- func (c *MemoryCache[V]) AddIndex(name string, keyFunc KeyFunc[V])
- func (c *MemoryCache[V]) Clear()
- func (c *MemoryCache[V]) Get(key string) (V, bool)
- func (c *MemoryCache[V]) GetAll() []V
- func (c *MemoryCache[V]) GetByIndex(indexName string, key string) (V, bool)
- func (c *MemoryCache[V]) GetHash() string
- func (c *MemoryCache[V]) HasIndex(name string) bool
- func (c *MemoryCache[V]) IndexCount() int
- func (c *MemoryCache[V]) IndexNames() []string
- func (c *MemoryCache[V]) Iterate(fn func(value V) bool)
- func (c *MemoryCache[V]) Len() int
- func (c *MemoryCache[V]) RemoveIndex(name string)
- func (c *MemoryCache[V]) Set(values []V)
- type MultiIndexCache
- type NormalizeFunc
- type RedisCache
- func (c *RedisCache[V]) Clear() error
- func (c *RedisCache[V]) Exists() (bool, error)
- func (c *RedisCache[V]) Get() ([]V, error)
- func (c *RedisCache[V]) GetVersion() (int64, error)
- func (c *RedisCache[V]) Refresh() error
- func (c *RedisCache[V]) Set(values []V) error
- func (c *RedisCache[V]) SetWithTTL(values []V, ttl time.Duration) error
- func (c *RedisCache[V]) TTL() (time.Duration, error)
- type RedisConfig
- func (c *RedisConfig) WithKeyPrefix(prefix string) *RedisConfig
- func (c *RedisConfig) WithMaxValueBytes(n int) *RedisConfig
- func (c *RedisConfig) WithOperationTimeout(timeout time.Duration) *RedisConfig
- func (c *RedisConfig) WithTTL(ttl time.Duration) *RedisConfig
- func (c *RedisConfig) WithVersionKeySuffix(suffix string) *RedisConfig
- type ValidateFunc
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func StringSorter ¶
StringSorter provides a helper for sorting slices by a string key.
Types ¶
type Cache ¶
type Cache[K comparable, V any] interface { // Get retrieves a value by its primary key. Get(key K) (V, bool) // Set stores a value with its primary key. Set(key K, value V) // Delete removes a value by its primary key. Delete(key K) // GetAll returns all cached values. GetAll() []V // Len returns the number of cached items. Len() int // Clear removes all items from the cache. Clear() // GetHash returns a hash representing the current cache state. // Useful for detecting changes. GetHash() string }
Cache provides the basic cache interface.
type Config ¶
type Config[V any] struct { // PrimaryKeyFunc extracts the primary key from a value. // This is required for multi-index cache. PrimaryKeyFunc KeyFunc[V] // HashFunc computes a hash for the cache contents. // If nil, defaultHashFunc is used, which serializes each value with fmt.Sprintf("%v", v). // Warning: the default is not suitable for types containing sensitive fields (passwords, tokens), // as those would be included in the hash input. It may also be non-deterministic for types // with maps or pointer fields. Use WithHashFunc to supply a custom hash (e.g. only stable, // non-sensitive fields in a deterministic order). HashFunc HashFunc[V] // ValidateFunc validates a value before storing. // If nil, all values are accepted. ValidateFunc ValidateFunc[V] // NormalizeFunc normalizes a value before storing. // If nil, values are stored as-is. NormalizeFunc NormalizeFunc[V] // SortFunc is used for deterministic hash calculation. // If nil, values are hashed in insertion order. SortFunc func(values []V) []V }
Config holds configuration for the cache.
func DefaultConfig ¶
DefaultConfig returns a default configuration. Note: PrimaryKeyFunc must be set before use with MultiIndexCache.
func (*Config[V]) WithHashFunc ¶
WithHashFunc sets a custom hash function.
func (*Config[V]) WithNormalizeFunc ¶
func (c *Config[V]) WithNormalizeFunc(fn NormalizeFunc[V]) *Config[V]
WithNormalizeFunc sets a normalization function.
func (*Config[V]) WithPrimaryKey ¶
WithPrimaryKey sets the primary key extraction function.
func (*Config[V]) WithSortFunc ¶
WithSortFunc sets a sort function for deterministic hashing.
func (*Config[V]) WithValidateFunc ¶
func (c *Config[V]) WithValidateFunc(fn ValidateFunc[V]) *Config[V]
WithValidateFunc sets a validation function.
type HybridCache ¶
type HybridCache[V any] struct { // contains filtered or unexported fields }
HybridCache combines memory cache with Redis for distributed scenarios. It uses memory cache for fast local access and Redis for persistence/sharing.
func NewHybridCache ¶
func NewHybridCache[V any](memoryConfig *Config[V], redisClient *redis.Client, redisConfig *RedisConfig) *HybridCache[V]
NewHybridCache creates a new hybrid cache.
func (*HybridCache[V]) AddIndex ¶
func (c *HybridCache[V]) AddIndex(name string, keyFunc KeyFunc[V])
AddIndex registers a new index on the memory cache.
func (*HybridCache[V]) GetAll ¶
func (c *HybridCache[V]) GetAll() []V
GetAll returns all values from memory cache.
func (*HybridCache[V]) GetByIndex ¶
func (c *HybridCache[V]) GetByIndex(indexName string, key string) (V, bool)
GetByIndex retrieves a value from memory cache by index.
func (*HybridCache[V]) LoadFromRedis ¶
func (c *HybridCache[V]) LoadFromRedis() error
LoadFromRedis loads data from Redis into memory cache.
func (*HybridCache[V]) Memory ¶
func (c *HybridCache[V]) Memory() *MemoryCache[V]
Memory returns the underlying memory cache for direct access.
func (*HybridCache[V]) Redis ¶
func (c *HybridCache[V]) Redis() *RedisCache[V]
Redis returns the underlying Redis cache for direct access.
func (*HybridCache[V]) Set ¶
func (c *HybridCache[V]) Set(values []V) error
Set stores values in both memory and Redis. Memory is updated first, then Redis. If Redis.Set fails, memory already holds the new data while Redis may still have the old data; the error is returned and the caller should retry or call LoadFromRedis to reconcile (e.g. clear memory or reload from Redis).
func (*HybridCache[V]) SyncToRedis ¶
func (c *HybridCache[V]) SyncToRedis() error
SyncToRedis saves memory cache data to Redis.
type MemoryCache ¶
type MemoryCache[V any] struct { // contains filtered or unexported fields }
MemoryCache provides a thread-safe, multi-index memory cache.
It supports O(1) lookups by primary key and by any registered index. The cache maintains insertion order and provides hash-based change detection.
func NewMultiIndexCache ¶
func NewMultiIndexCache[V any](config *Config[V]) *MemoryCache[V]
NewMultiIndexCache creates a new multi-index memory cache. The config must have a PrimaryKeyFunc set.
func (*MemoryCache[V]) AddIndex ¶
func (c *MemoryCache[V]) AddIndex(name string, keyFunc KeyFunc[V])
AddIndex registers a new index with a key extraction function. The keyFunc extracts the index key from a value. If an index with the same name exists, it will be replaced.
func (*MemoryCache[V]) Clear ¶
func (c *MemoryCache[V]) Clear()
Clear removes all items from the cache.
func (*MemoryCache[V]) Get ¶
func (c *MemoryCache[V]) Get(key string) (V, bool)
Get retrieves a value by its primary key.
func (*MemoryCache[V]) GetAll ¶
func (c *MemoryCache[V]) GetAll() []V
GetAll returns all cached values in insertion order.
func (*MemoryCache[V]) GetByIndex ¶
func (c *MemoryCache[V]) GetByIndex(indexName string, key string) (V, bool)
GetByIndex retrieves a value by a named index. Returns the value and true if found, zero value and false otherwise.
func (*MemoryCache[V]) GetHash ¶
func (c *MemoryCache[V]) GetHash() string
GetHash returns a hash representing the current cache state.
func (*MemoryCache[V]) HasIndex ¶
func (c *MemoryCache[V]) HasIndex(name string) bool
HasIndex checks if an index exists.
func (*MemoryCache[V]) IndexCount ¶
func (c *MemoryCache[V]) IndexCount() int
IndexCount returns the number of registered indexes.
func (*MemoryCache[V]) IndexNames ¶
func (c *MemoryCache[V]) IndexNames() []string
IndexNames returns the names of all registered indexes.
func (*MemoryCache[V]) Iterate ¶
func (c *MemoryCache[V]) Iterate(fn func(value V) bool)
Iterate applies a function to each cached value in insertion order. If the function returns false, iteration stops. The callback must not panic; if it does, the read lock may block other goroutines until recovery.
func (*MemoryCache[V]) Len ¶
func (c *MemoryCache[V]) Len() int
Len returns the number of cached items.
func (*MemoryCache[V]) RemoveIndex ¶
func (c *MemoryCache[V]) RemoveIndex(name string)
RemoveIndex removes an index by name.
func (*MemoryCache[V]) Set ¶
func (c *MemoryCache[V]) Set(values []V)
Set stores all values and rebuilds all indexes. Values are validated and normalized if the corresponding functions are set. Duplicate primary keys will be updated (last one wins). Panics if PrimaryKeyFunc is nil and len(values) > 0; set PrimaryKeyFunc via config before use with non-empty data.
type MultiIndexCache ¶
type MultiIndexCache[V any] interface { // GetByIndex retrieves a value by a named index. // Returns the value and true if found, zero value and false otherwise. GetByIndex(indexName string, key string) (V, bool) // AddIndex registers a new index with a key extraction function. // The keyFunc extracts the index key from a value. AddIndex(name string, keyFunc func(V) string) // RemoveIndex removes an index by name. RemoveIndex(name string) // HasIndex checks if an index exists. HasIndex(name string) bool // Set stores all values and rebuilds all indexes. Set(values []V) // GetAll returns all cached values in insertion order. GetAll() []V // Len returns the number of cached items. Len() int // Clear removes all items from the cache. Clear() // GetHash returns a hash representing the current cache state. GetHash() string // Iterate applies a function to each cached value. // If the function returns false, iteration stops. Iterate(fn func(value V) bool) }
MultiIndexCache extends Cache with multi-index lookup capabilities.
type NormalizeFunc ¶
type NormalizeFunc[V any] func(value V) V
NormalizeFunc defines a function that normalizes a value. Returns the normalized value.
type RedisCache ¶
type RedisCache[V any] struct { // contains filtered or unexported fields }
RedisCache provides a Redis-based cache implementation. It supports versioning for cache invalidation detection.
func NewRedisCache ¶
func NewRedisCache[V any](client *redis.Client, config *RedisConfig) *RedisCache[V]
NewRedisCache creates a new Redis cache with the given client and configuration. KeyPrefix and VersionKeySuffix must be non-empty; use a unique prefix per cache to avoid key collision.
func NewRedisCacheWithKey ¶
func NewRedisCacheWithKey[V any](client *redis.Client, key string, config *RedisConfig) *RedisCache[V]
NewRedisCacheWithKey creates a new Redis cache with a custom key name. The key must be non-empty; VersionKeySuffix must be non-empty. Use a unique key per cache to avoid key collision.
func (*RedisCache[V]) Clear ¶
func (c *RedisCache[V]) Clear() error
Clear deletes the cache key and the version key. After Clear(), GetVersion() returns 0 (version key is removed).
func (*RedisCache[V]) Exists ¶
func (c *RedisCache[V]) Exists() (bool, error)
Exists checks if the cache key exists.
func (*RedisCache[V]) Get ¶
func (c *RedisCache[V]) Get() ([]V, error)
Get retrieves values from Redis. Returns an empty slice if the key doesn't exist. If the stored value exceeds MaxValueBytes (when set in config), returns an error to prevent OOM.
func (*RedisCache[V]) GetVersion ¶
func (c *RedisCache[V]) GetVersion() (int64, error)
GetVersion returns the current cache version. Returns 0 if the version key doesn't exist.
func (*RedisCache[V]) Refresh ¶
func (c *RedisCache[V]) Refresh() error
Refresh extends the TTL of the cache without changing the data.
func (*RedisCache[V]) Set ¶
func (c *RedisCache[V]) Set(values []V) error
Set stores values in Redis and increments the version.
func (*RedisCache[V]) SetWithTTL ¶
func (c *RedisCache[V]) SetWithTTL(values []V, ttl time.Duration) error
SetWithTTL stores values with a custom TTL.
type RedisConfig ¶
type RedisConfig struct {
// KeyPrefix is prepended to all Redis keys. Use a unique prefix per cache to avoid key collision.
KeyPrefix string
// VersionKeySuffix is appended to the key prefix for version tracking.
// Default: ":version"
VersionKeySuffix string
// TTL is the default time-to-live for cached data. Must be positive; otherwise a default is used at Set time.
// Default: 1 hour
TTL time.Duration
// OperationTimeout is the timeout for Redis operations.
// Default: 5 seconds
OperationTimeout time.Duration
// MaxValueBytes limits the size of the value read from Redis in Get(). If <= 0, no limit is applied.
// Default: 16MB. Prevents OOM from malicious or corrupted oversized values in Redis.
MaxValueBytes int
}
RedisConfig holds configuration for Redis cache.
func DefaultRedisConfig ¶
func DefaultRedisConfig() *RedisConfig
DefaultRedisConfig returns a default Redis configuration.
func (*RedisConfig) WithKeyPrefix ¶
func (c *RedisConfig) WithKeyPrefix(prefix string) *RedisConfig
WithKeyPrefix sets the key prefix.
func (*RedisConfig) WithMaxValueBytes ¶ added in v1.1.0
func (c *RedisConfig) WithMaxValueBytes(n int) *RedisConfig
WithMaxValueBytes sets the maximum allowed size in bytes for a value read from Redis in Get(). Values larger than this are rejected to prevent OOM. Use 0 or negative to disable the limit.
func (*RedisConfig) WithOperationTimeout ¶
func (c *RedisConfig) WithOperationTimeout(timeout time.Duration) *RedisConfig
WithOperationTimeout sets the operation timeout.
func (*RedisConfig) WithTTL ¶
func (c *RedisConfig) WithTTL(ttl time.Duration) *RedisConfig
WithTTL sets the TTL.
func (*RedisConfig) WithVersionKeySuffix ¶
func (c *RedisConfig) WithVersionKeySuffix(suffix string) *RedisConfig
WithVersionKeySuffix sets the version key suffix.
type ValidateFunc ¶
ValidateFunc defines a function that validates a value. Returns an error if the value is invalid.