Documentation
¶
Overview ¶
Package loadingcache provides a way for clients to create a cache capable of loading values on demand, should they get cache misses.
You can configure the cache to expire entries after a certain amount elapses since the last write and/or read.
This project is heavily inspired by Guava Cache (https://github.com/google/guava/wiki/CachesExplained).
All errors are wrapped by github.com/pkg/errors.Wrap. If you which to check the type of it, please use github.com/pkg/errors.Is.
Index ¶
Examples ¶
Constants ¶
This section is empty.
Variables ¶
var ErrAlreadySet = errors.New("Cache already set")
ErrAlreadySet can be returned by Loader to tell the caller that the cache had already been set by its self.
var ErrKeyNotFound = errors.New("Key not found")
ErrKeyNotFound represents an error indicating that the key was not found
var StringFnvHashCodeFunc = func(k any) int { h := fnv.New32a() if _, err := h.Write([]byte(k.(string))); err != nil { panic(err) } return int(h.Sum32()) }
StringFnvHashCodeFunc is a hash code function for strings which uses fnv.New32a
Functions ¶
This section is empty.
Types ¶
type Cache ¶
type Cache interface {
// Get returns the value associated with a given key. If no entry exists for
// the provided key, loadingcache.ErrKeyNotFound is returned.
Get(key any, options ...GetOption) (any, error)
// Put adds a value to the cache identified by a key.
// If a value already exists associated with that key, it
// is replaced.
Put(key, value any)
// Invalidate removes keys from the cache. If a key does not exist it is a noop.
Invalidate(keys ...any)
// InvalidateAll invalidates all keys
InvalidateAll()
// Close cleans up any resources used by the cache
Close()
// Stats returns the current stats
Stats() Stats
// IsSharded tells the implementation is a sharded cache for testing.
IsSharded() bool
}
Cache describe the base interface to interact with a generic cache.
This interface reduces all keys and values to a generic any.
Example (AdvancedUsage) ¶
package main
import (
"fmt"
"time"
"github.com/goldstd/loadingcache"
)
func main() {
cache := loadingcache.Config{
MaxSize: 2,
ExpireAfterRead: 2 * time.Minute,
ExpireAfterWrite: time.Minute,
EvictListeners: []loadingcache.RemovalListener{
func(notification loadingcache.EvictNotification) {
fmt.Printf("Entry removed due to %s\n", notification.Reason)
},
},
Load: loadingcache.LoadFunc(func(key any, _ loadingcache.Cache) (any, error) {
fmt.Printf("Loading key %v\n", key)
return fmt.Sprint(key), nil
}),
}.Build()
cache.Put(1, "1")
val1, _ := cache.Get(1)
fmt.Printf("%v\n", val1)
val2, _ := cache.Get(2)
fmt.Printf("%v\n", val2)
val3, _ := cache.Get(3)
fmt.Printf("%v\n", val3)
}
Output: 1 Loading key 2 2 Loading key 3 Entry removed due to Size 3
Example (SimpleUsage) ¶
package main
import (
"fmt"
"github.com/goldstd/loadingcache"
"github.com/pkg/errors"
)
func main() {
cache := loadingcache.Config{}.Build()
// Adding some values and reading them
cache.Put("a", 1)
cache.Put("b", 2)
cache.Put("c", 3)
val1, _ := cache.Get("a") // Don't forget to check for errors
fmt.Printf("%v\n", val1)
val2, _ := cache.Get("b") // Don't forget to check for errors
fmt.Printf("%v\n", val2)
// Getting a value that does not exist
_, err := cache.Get("d")
if errors.Is(err, loadingcache.ErrKeyNotFound) {
fmt.Println("That key does not exist")
}
// Evicting
cache.Invalidate("a")
cache.Invalidate("b", "c")
cache.InvalidateAll()
}
Output: 1 2 That key does not exist
type CacheOption ¶
type CacheOption func(Cache)
CacheOption describes an option that can configure the cache
type Config ¶
type Config struct {
// Clock allows passing a custom clock to be used with the cache.
//
// This is useful for testing, where controlling time is important.
Clock clock.Clock
// Load configures a loading function
Load Loader
// ShardHashFunc is a function that produces a hashcode of the key.
//
// See https://docs.oracle.com/en/java/javase/15/docs/api/java.base/java/lang/Object.html#hashCode()
// for best practices surrounding hash code functions.
ShardHashFunc func(key any) int
// EvictListeners configures a removal listeners
EvictListeners []RemovalListener
// ExpireAfterWrite configures the cache to expire entries after
// a given duration after writing.
ExpireAfterWrite time.Duration
// ExpireAfterRead configures the cache to expire entries after
// a given duration after reading.
ExpireAfterRead time.Duration
// EvictInterval controls if a background go routine should be created
// which automatically evicts entries that have expired. If not specified,
// no background goroutine will be created.
//
// The background go routine runs with the provided frequency.
// To avoid go routine leaks, use the close function when you're done with the cache.
EvictInterval time.Duration
// MaxSize limits the number of entries allowed in the cache.
// If the limit is achieved, an eviction process will take place,
// this means that eviction policies will be executed such as write
// time, read time or random entry if no eviction policy frees up
// space.
//
// If the cache is sharded, MaxSize is applied to each shard,
// meaning that the overall capacity will be MaxSize * ShardCount.
MaxSize uint32
// ShardCount indicates how many shards will be used by the cache.
// This allows some degree of parallelism in read and writing to the cache.
//
// If the shard count is greater than 1, then ShardHashFunc must be provided
// otherwise the constructor will panic.
ShardCount uint32
// AsyncLoad configures loading in async way after cache expired
AsyncLoad bool
}
Config available options to initialize the cache
type EvictNotification ¶
type EvictNotification struct {
Key any
Value any
Reason EvictReason
}
EvictNotification is passed to listeners everytime an entry is removed
type EvictReason ¶
type EvictReason int
EvictReason is an enum describing the causes for an entry to be removed from the cache.
const ( // EvictReasonExplicit means the entry was explicitly invalidated EvictReasonExplicit EvictReason = iota // EvictReasonReplaced means the entry was replaced by a new one EvictReasonReplaced // EvictReasonReadExpired means the entry read expired, e.g. too much time // since last read/write. EvictReasonReadExpired // EvictReasonWriteExpired means the entry write expired, e.g. too much time // since last read/write. EvictReasonWriteExpired // EvictReasonSize means the entry was removed due to the cache size. EvictReasonSize )
func (EvictReason) String ¶
func (r EvictReason) String() string
type Loader ¶
type Loader interface {
// Load loads the latest value by the key.
// err can be ErrAlreadySet to indicate that the loader had been set the cache.
Load(key any, cache Cache) (any, error)
}
Loader represents an interface for loading cache value.
type RemovalListener ¶
type RemovalListener func(EvictNotification)
RemovalListener represents a removal listener
type Stats ¶
type Stats interface {
// EvictionCount is the number of times an entry has been evicted
EvictionCount() int64
// HitCount the number of times Cache lookup methods have returned a cached value
HitCount() int64
// HitRate is the ratio of cache requests which were hits. This is defined as
// hitCount / requestCount, or 1.0 when requestCount == 0
HitRate() float64
// MissCount is the number of times Cache lookup methods have returned an uncached
// (newly loaded) value
MissCount() int64
// MissRate is the ratio of cache requests which were misses. This is defined as
// missCount / requestCount, or 0.0 when requestCount == 0
MissRate() float64
// RequestCount is the number of times Cache lookup methods have returned either a cached or
// uncached value. This is defined as hitCount + missCount
RequestCount() int64
// LoadSuccessCount is the number of times Cache lookup methods have successfully
// loaded a new value
LoadSuccessCount() int64
// LoadErrorCount is the number of times Cache lookup methods threw an exception while loading
// a new value
LoadErrorCount() int64
// LoadErrorRate is the ratio of cache loading attempts which threw exceptions.
// This is defined as loadExceptionCount / (loadSuccessCount + loadExceptionCount), or 0.0 when
// loadSuccessCount + loadExceptionCount == 0
LoadErrorRate() float64
// LoadCount the total number of times that Cache lookup methods attempted to load new values.
// This includes both successful load operations, and those that threw exceptions.
// This is defined as loadSuccessCount + loadExceptionCount
LoadCount() int64
// LoadTotalTime is the total duration the cache has spent loading new values
LoadTotalTime() time.Duration
// AverageLoadPenalty is the average duration spent loading new values. This is defined as
// totalLoadTime / (loadSuccessCount + loadExceptionCount).
AverageLoadPenalty() time.Duration
}
Stats exposes cache relevant metrics.
Be aware that this interface may be exposing a live stats collector, and as such if you manually calculate rates, values may differ if calls to the cache have occurred between calls.