Documentation ¶
Overview ¶
Package cache defines cache interfaces and provides in-memory implementations.
Index ¶
- Constants
- func GobRegister(values ...interface{})
- func GobTypesHash() uint64
- func GobTypesHashReset()
- func SkipRead(ctx context.Context) bool
- func TTL(ctx context.Context) time.Duration
- func WithSkipRead(ctx context.Context) context.Context
- func WithTTL(ctx context.Context, ttl time.Duration, updateExisting bool) context.Context
- type BinaryEncoding
- type BinaryUnmarshaler
- type Config
- type Deleter
- type Dumper
- type Entry
- type EntryOf
- type ErrWithExpiredItem
- type ErrWithExpiredItemOf
- type EvictionStrategy
- type Failover
- type FailoverConfig
- type FailoverConfigOf
- type FailoverOf
- type HTTPTransfer
- type InvalidationIndex
- func (i *InvalidationIndex) AddCache(name string, deleter Deleter)
- func (i *InvalidationIndex) AddInvalidationLabels(key []byte, labels ...string)
- func (i *InvalidationIndex) AddLabels(cacheName string, key []byte, labels ...string)
- func (i *InvalidationIndex) InvalidateByLabels(ctx context.Context, labels ...string) (int, error)
- type Invalidator
- type Key
- type Logger
- type NoOp
- type ReadWriter
- type ReadWriterOf
- type Reader
- type ReaderOf
- type Restorer
- type SentinelError
- type ShardedMap
- func (c ShardedMap) Delete(ctx context.Context, key []byte) error
- func (c ShardedMap) DeleteAll(ctx context.Context)
- func (c *ShardedMap) Dump(w io.Writer) (int, error)
- func (c ShardedMap) ExpireAll(ctx context.Context)
- func (c ShardedMap) Len() int
- func (c ShardedMap) Load(key []byte) (interface{}, bool)
- func (c ShardedMap) Read(ctx context.Context, key []byte) (interface{}, error)
- func (c *ShardedMap) Restore(r io.Reader) (int, error)
- func (c ShardedMap) Store(key []byte, val interface{})
- func (c ShardedMap) Walk(walkFn func(e Entry) error) (int, error)
- func (c ShardedMap) Write(ctx context.Context, k []byte, v interface{}) error
- type ShardedMapOf
- func (c ShardedMapOf) Delete(ctx context.Context, key []byte) error
- func (c ShardedMapOf) DeleteAll(ctx context.Context)
- func (c *ShardedMapOf[V]) Dump(w io.Writer) (int, error)
- func (c ShardedMapOf) ExpireAll(ctx context.Context)
- func (c ShardedMapOf) Len() int
- func (c ShardedMapOf) Load(key []byte) (val V, loaded bool)
- func (c ShardedMapOf) Read(ctx context.Context, key []byte) (val V, _ error)
- func (c *ShardedMapOf[V]) Restore(r io.Reader) (int, error)
- func (c ShardedMapOf) Store(key []byte, val V)
- func (c ShardedMapOf) Walk(walkFn func(e EntryOf[V]) error) (int, error)
- func (c *ShardedMapOf[V]) WalkDumpRestorer() WalkDumpRestorer
- func (c ShardedMapOf) Write(ctx context.Context, k []byte, v V) error
- type StatsTracker
- type SyncMap
- func (c SyncMap) Delete(ctx context.Context, key []byte) error
- func (c SyncMap) DeleteAll(ctx context.Context)
- func (c *SyncMap) Dump(w io.Writer) (int, error)
- func (c SyncMap) ExpireAll(ctx context.Context)
- func (c SyncMap) Len() int
- func (c SyncMap) Read(ctx context.Context, key []byte) (interface{}, error)
- func (c *SyncMap) Restore(r io.Reader) (int, error)
- func (c SyncMap) Walk(walkFn func(e Entry) error) (int, error)
- func (c SyncMap) Write(ctx context.Context, k []byte, v interface{}) error
- type Trait
- func (c *Trait) NotifyDeleted(ctx context.Context, key []byte)
- func (c *Trait) NotifyDeletedAll(ctx context.Context, start time.Time, cnt int)
- func (c *Trait) NotifyExpiredAll(ctx context.Context, start time.Time, cnt int)
- func (c *Trait) NotifyWritten(ctx context.Context, key []byte, value interface{}, ttl time.Duration)
- func (c *Trait) PrepareRead(ctx context.Context, cacheEntry *TraitEntry, found bool) (interface{}, error)
- func (c *Trait) TTL(ctx context.Context) time.Duration
- type TraitEntry
- type TraitEntryOf
- type TraitOf
- type WalkDumpRestorer
- type Walker
- type WalkerOf
- type Writer
- type WriterOf
Examples ¶
Constants ¶
const ( // DefaultTTL indicates default value (replaced by config.TimeToLive) for entry expiration time. DefaultTTL = time.Duration(0) // UnlimitedTTL indicates unlimited TTL for config TimeToLive. UnlimitedTTL = time.Duration(-1) )
const ( // ErrExpired indicates expired cache entry, // may implement ErrWithExpiredItem to enable stale value serving. ErrExpired = SentinelError("expired cache item") // ErrNotFound indicates missing cache entry. ErrNotFound = SentinelError("missing cache item") // ErrNothingToInvalidate indicates no caches were added to Invalidator. ErrNothingToInvalidate = SentinelError("nothing to invalidate") // ErrAlreadyInvalidated indicates recent invalidation. ErrAlreadyInvalidated = SentinelError("already invalidated") // ErrUnexpectedType is thrown on failed type assertion. ErrUnexpectedType = SentinelError("unexpected type") )
const ( // MetricMiss is a name of a metric to count cache miss events. MetricMiss = "cache_miss" // MetricExpired is a name of a metric to count expired cache read events. MetricExpired = "cache_expired" // MetricHit is a name of a metric to count valid cache read events. MetricHit = "cache_hit" // MetricWrite is a name of a metric to count cache write events. MetricWrite = "cache_write" // MetricDelete is a name of a metric to count cache delete events. MetricDelete = "cache_delete" // MetricItems is a name of a gauge to count number of items in cache. MetricItems = "cache_items" // MetricRefreshed is a name of a metric to count stale refresh events. MetricRefreshed = "cache_refreshed" // MetricBuild is a name of a metric to count value building events. MetricBuild = "cache_build" // MetricFailed is a name of a metric to count number of failed value builds. MetricFailed = "cache_failed" // MetricChanged is a name of a metric to count number of cache builds that changed cached value. MetricChanged = "cache_changed" // MetricEvict is a name of metric to count evictions. MetricEvict = "cache_evict" // MetricEvictionElapsedSeconds is a name of metric to count eviction job time. MetricEvictionElapsedSeconds = "cache_eviction_elapsed_seconds" )
Variables ¶
This section is empty.
Functions ¶
func GobRegister ¶
func GobRegister(values ...interface{})
GobRegister enables cached type transferring.
Example (Transfer_cache) ¶
package main import ( "bytes" "context" "fmt" "github.com/bool64/cache" ) type SomeEntity struct { Parent *SomeEntity SomeField string SomeSlice []int SomeRecursiveMap map[string]SomeEntity unexported string } func main() { // Registering cached type to gob. cache.GobRegister(SomeEntity{}) c1 := cache.NewShardedMap() c2 := cache.NewShardedMap() ctx := context.Background() _ = c1.Write(ctx, []byte("key1"), SomeEntity{ SomeField: "foo", SomeSlice: []int{1, 2, 3}, unexported: "will be lost in transfer", }) w := bytes.NewBuffer(nil) // Transferring data from c1 to c2. _, _ = c1.Dump(w) _, _ = c2.Restore(w) v, _ := c2.Read(ctx, []byte("key1")) fmt.Println(v.(SomeEntity).SomeField) }
Output: foo
func GobTypesHash ¶
func GobTypesHash() uint64
GobTypesHash returns a fingerprint of a group of types to transfer.
func GobTypesHashReset ¶
func GobTypesHashReset()
GobTypesHashReset resets types hash to zero value.
func WithSkipRead ¶
WithSkipRead returns context with cache read ignored.
With such context cache.Reader should always return ErrNotFound discarding cached value.
func WithTTL ¶
WithTTL adds cache time to live information to context.
If there is already ttl in context and updateExisting is true, then ttl value in original context will be updated.
Updating existing ttl can be useful if ttl information is only available internally during cache value build, in such a case value builder can communicate ttl to external cache backend. For example cache ttl can be derived from HTTP response cache headers of value source.
When existing ttl is updated minimal non-zero value is kept. This is necessary to unite ttl requirements of multiple parties.
Types ¶
type BinaryEncoding ¶ added in v0.2.6
type BinaryEncoding interface { Encode(ctx context.Context, value interface{}) ([]byte, error) Decode(ctx context.Context, buf []byte) (interface{}, error) }
BinaryEncoding defines binary transmission protocol.
type BinaryUnmarshaler ¶ added in v0.2.6
type BinaryUnmarshaler func(data []byte) (encoding.BinaryMarshaler, error)
BinaryUnmarshaler implements BinaryEncoding.
type Config ¶
type Config struct { // Logger is an instance of contextualized logger, can be nil. Logger Logger // Stats is a metrics collector, can be nil. Stats StatsTracker // Name is cache instance name, used in stats and logging. Name string // ItemsCountReportInterval is items count metric report interval, default 1m. ItemsCountReportInterval time.Duration // TimeToLive is delay before entry expiration, default 5m. // Use UnlimitedTTL value to set up unlimited TTL. TimeToLive time.Duration // DeleteExpiredAfter is delay before expired entry is deleted from cache, default 24h. DeleteExpiredAfter time.Duration // DeleteExpiredJobInterval is delay between two consecutive cleanups, default 1h. DeleteExpiredJobInterval time.Duration // ExpirationJitter is a fraction of TTL to randomize, default 0.1. // Use -1 to disable. // If enabled, entry TTL will be randomly altered in bounds of ±(ExpirationJitter * TTL / 2). ExpirationJitter float64 // HeapInUseSoftLimit sets heap in use (runtime.MemStats).HeapInuse threshold when eviction will be triggered. HeapInUseSoftLimit uint64 // SysMemSoftLimit sets system memory (runtime.MemStats).Sys threshold when eviction will be triggered. SysMemSoftLimit uint64 // CountSoftLimit sets count threshold when eviction will be triggered. // As opposed to memory soft limits, when count limit is exceeded, eviction will remove items to achieve // the level of CountSoftLimit*(1-EvictFraction), which may be more items that EvictFraction defines. CountSoftLimit uint64 // EvictionNeeded is a user-defined function to decide whether eviction is necessary. // If true is returned, eviction cycle will happen. EvictionNeeded func() bool // EvictFraction is a fraction (0, 1] of total count of items to be evicted when resource is overused, // default 0.1 (10% of items). EvictFraction float64 // EvictionStrategy is EvictMostExpired by default. EvictionStrategy EvictionStrategy }
Config controls cache instance.
type Deleter ¶
type Deleter interface { // Delete removes a cache entry with a given key // and returns ErrNotFound for non-existent keys. Delete(ctx context.Context, key []byte) error }
Deleter deletes from cache.
type ErrWithExpiredItem ¶
ErrWithExpiredItem defines an expiration error with entry details.
type ErrWithExpiredItemOf ¶ added in v0.2.3
ErrWithExpiredItemOf defines an expiration error with entry details.
type EvictionStrategy ¶ added in v0.4.0
type EvictionStrategy uint8
EvictionStrategy defines eviction behavior when soft limit is met during cleanup job.
const ( // EvictMostExpired removes entries with the oldest expiration time. // Both expired and non-expired entries may be affected. // Default eviction strategy, most performant as it does not maintain counters on each serve. EvictMostExpired EvictionStrategy = iota // EvictLeastRecentlyUsed removes entries that were not served recently. // It has a minor performance impact due to update of timestamp on every serve. EvictLeastRecentlyUsed // EvictLeastFrequentlyUsed removes entries that were in low demand. // It has a minor performance impact due to update of timestamp on every serve. EvictLeastFrequentlyUsed )
type Failover ¶
type Failover struct { // Errors caches errors of failed updates. Errors *ShardedMap // contains filtered or unexported fields }
Failover is a cache frontend to manage cache updates in a non-conflicting and performant way.
Please use NewFailover to create instance.
func NewFailover ¶
func NewFailover(options ...func(cfg *FailoverConfig)) *Failover
NewFailover creates a Failover cache instance.
Build is locked per key to avoid concurrent updates, new value is served . Stale value is served during non-concurrent update (up to FailoverConfig.UpdateTTL long).
func (*Failover) Get ¶
func (f *Failover) Get( ctx context.Context, key []byte, buildFunc func(ctx context.Context) (interface{}, error), ) (interface{}, error)
Get returns value from cache or from build function.
Example ¶
package main import ( "context" "log" "github.com/bool64/cache" ) func main() { ctx := context.TODO() f := cache.NewFailover() // Get value from cache or the function. v, err := f.Get(ctx, []byte("my-key"), func(ctx context.Context) (interface{}, error) { // Build value or return error on failure. return "<value>", nil }) if err != nil { log.Fatal(err) } // Assert the type and use value. _ = v.(string) }
Output:
Example (Caching_wrapper) ¶
package main import ( "context" "errors" "fmt" "strconv" "time" "github.com/bool64/cache" ) type Value struct { Sequence int ID int Country string } type Service interface { GetByID(ctx context.Context, country string, id int) (Value, error) } // Real is an instance of real service that does some slow/expensive processing. type Real struct { Calls int } func (s *Real) GetByID(_ context.Context, country string, id int) (Value, error) { s.Calls++ if id == 0 { return Value{}, errors.New("invalid id") } return Value{ Country: country, ID: id, Sequence: s.Calls, }, nil } // Cached is a service wrapper to serve already processed results from cache. type Cached struct { upstream Service storage *cache.Failover } func (s Cached) GetByID(ctx context.Context, country string, id int) (Value, error) { // Prepare string cache key and call stale cache. // Build function will be called if there is a cache miss. cacheKey := country + ":" + strconv.Itoa(id) value, err := s.storage.Get(ctx, []byte(cacheKey), func(ctx context.Context) (interface{}, error) { return s.upstream.GetByID(ctx, country, id) }) if err != nil { return Value{}, err } // Type assert and return result. return value.(Value), nil } func main() { var service Service ctx := context.Background() service = Cached{ upstream: &Real{}, storage: cache.NewFailover(func(cfg *cache.FailoverConfig) { cfg.BackendConfig.TimeToLive = time.Minute }), } fmt.Println(service.GetByID(ctx, "DE", 123)) fmt.Println(service.GetByID(ctx, "US", 0)) // Error increased sequence, but was cached with short-ttl. fmt.Println(service.GetByID(ctx, "US", 0)) // This call did not hit backend. fmt.Println(service.GetByID(ctx, "US", 456)) fmt.Println(service.GetByID(ctx, "DE", 123)) fmt.Println(service.GetByID(ctx, "US", 456)) fmt.Println(service.GetByID(ctx, "FR", 789)) }
Output: {1 123 DE} <nil> {0 0 } invalid id {0 0 } invalid id {3 456 US} <nil> {1 123 DE} <nil> {3 456 US} <nil> {4 789 FR} <nil>
type FailoverConfig ¶
type FailoverConfig struct { // Name is added to logs and stats. Name string // Backend is a cache instance, ShardedMap created by default. Backend ReadWriter // BackendConfig is a configuration for ShardedMap cache instance if Backend is not provided. BackendConfig Config // FailedUpdateTTL is ttl of failed build cache, default 20s, -1 disables errors cache. // Errors cache prevents application from pressuring a failing data source. FailedUpdateTTL time.Duration // UpdateTTL is a time interval to retry update, default 1 minute. // When stale value is being updated to a new one, current (stale) cache entry // is refreshed in cache with this TTL. This unblocks other consumers with stale value, // instead of blocking them to wait for a new one. UpdateTTL time.Duration // SyncUpdate disables update in background, default is background update with stale value served. SyncUpdate bool // SyncRead enables backend reading in the critical section to ensure cache miss // will not trigger multiple updates sequentially. // // Probability of such issue is low, there is performance penalty for enabling this option. SyncRead bool // MaxStaleness is duration when value can be served after expiration. // If value has expired longer than this duration it won't be served unless value update failure. MaxStaleness time.Duration // FailHard disables serving of stale value in case of update failure. FailHard bool // Logger collects messages with context. Logger Logger // Stats tracks stats. Stats StatsTracker // ObserveMutability enables deep equal check with metric collection on cache update. ObserveMutability bool }
FailoverConfig is optional configuration for NewFailover.
func (FailoverConfig) Use ¶
func (fc FailoverConfig) Use(cfg *FailoverConfig)
Use is a functional option for NewFailover to apply configuration.
type FailoverConfigOf ¶ added in v0.2.3
type FailoverConfigOf[V any] struct { // Name is added to logs and stats. Name string // Backend is a cache instance, ShardedMap created by default. Backend ReadWriterOf[V] // BackendConfig is a configuration for ShardedMap cache instance if Backend is not provided. BackendConfig Config // FailedUpdateTTL is ttl of failed build cache, default 20s, -1 disables errors cache. FailedUpdateTTL time.Duration // UpdateTTL is a time interval to retry update, default 1 minute. UpdateTTL time.Duration // SyncUpdate disables update in background, default is background update with stale value served. SyncUpdate bool // SyncRead enables backend reading in the critical section to ensure cache miss // will not trigger multiple updates sequentially. // // Probability of such issue is low, there is performance penalty for enabling this option. SyncRead bool // MaxStaleness is duration when value can be served after expiration. // If value has expired longer than this duration it won't be served unless value update failure. MaxStaleness time.Duration // FailHard disables serving of stale value in case up update failure. FailHard bool // Logger collects messages with context. Logger Logger // Stats tracks stats. Stats StatsTracker // ObserveMutability enables deep equal check with metric collection on cache update. ObserveMutability bool }
FailoverConfigOf is optional configuration for NewFailoverOf.
func (FailoverConfigOf[V]) Use ¶ added in v0.2.3
func (fc FailoverConfigOf[V]) Use(cfg *FailoverConfigOf[V])
Use is a functional option for NewFailover to apply configuration.
type FailoverOf ¶ added in v0.2.3
type FailoverOf[V any] struct { // Errors caches errors of failed updates. Errors *ShardedMapOf[error] // contains filtered or unexported fields }
FailoverOf is a cache frontend to manage cache updates in a non-conflicting and performant way.
Please use NewFailoverOf to create instance.
func NewFailoverOf ¶ added in v0.2.3
func NewFailoverOf[V any](options ...func(cfg *FailoverConfigOf[V])) *FailoverOf[V]
NewFailoverOf creates a FailoverOf cache instance.
Build is locked per key to avoid concurrent updates, new value is served . Stale value is served during non-concurrent update (up to FailoverConfigOf.UpdateTTL long).
func (*FailoverOf[V]) Get ¶ added in v0.2.3
func (f *FailoverOf[V]) Get( ctx context.Context, key []byte, buildFunc func(ctx context.Context) (V, error), ) (V, error)
Get returns value from cache or from build function.
Example ¶
package main import ( "context" "fmt" "log" "github.com/bool64/cache" ) func main() { // Dog is your cached type. type Dog struct { Name string } ctx := context.TODO() f := cache.NewFailoverOf[Dog]() // Get value from cache or the function. v, err := f.Get(ctx, []byte("my-key"), func(ctx context.Context) (Dog, error) { // Build value or return error on failure. return Dog{Name: "Snoopy"}, nil }) if err != nil { log.Fatal(err) } // Use value. fmt.Printf("%s", v.Name) }
Output: Snoopy
Example (Caching_wrapper) ¶
//go:build go1.18 // +build go1.18 package main import ( "context" "fmt" "strconv" "time" "github.com/bool64/cache" ) // CachedGeneric is a service wrapper to serve already processed results from cache. type CachedGeneric struct { upstream Service storage *cache.FailoverOf[Value] } func (s CachedGeneric) GetByID(ctx context.Context, country string, id int) (Value, error) { // Prepare string cache key and call stale cache. // Build function will be called if there is a cache miss. cacheKey := country + ":" + strconv.Itoa(id) return s.storage.Get(ctx, []byte(cacheKey), func(ctx context.Context) (Value, error) { return s.upstream.GetByID(ctx, country, id) }) } func main() { var service Service ctx := context.Background() service = CachedGeneric{ upstream: &Real{}, storage: cache.NewFailoverOf[Value](func(cfg *cache.FailoverConfigOf[Value]) { cfg.BackendConfig.TimeToLive = time.Minute }), } fmt.Println(service.GetByID(ctx, "DE", 123)) fmt.Println(service.GetByID(ctx, "US", 0)) // Error increased sequence, but was cached with short-ttl. fmt.Println(service.GetByID(ctx, "US", 0)) // This call did not hit backend. fmt.Println(service.GetByID(ctx, "US", 456)) fmt.Println(service.GetByID(ctx, "DE", 123)) fmt.Println(service.GetByID(ctx, "US", 456)) fmt.Println(service.GetByID(ctx, "FR", 789)) }
Output: {1 123 DE} <nil> {0 0 } invalid id {0 0 } invalid id {3 456 US} <nil> {1 123 DE} <nil> {3 456 US} <nil> {4 789 FR} <nil>
type HTTPTransfer ¶ added in v0.2.0
type HTTPTransfer struct { Logger Logger Transport http.RoundTripper // contains filtered or unexported fields }
HTTPTransfer exports and imports cache entries via http.
func (*HTTPTransfer) AddCache ¶ added in v0.2.0
func (t *HTTPTransfer) AddCache(name string, c WalkDumpRestorer)
AddCache registers cache into exporter.
func (*HTTPTransfer) CachesCount ¶ added in v0.2.5
func (t *HTTPTransfer) CachesCount() int
CachesCount returns how many caches were added.
func (*HTTPTransfer) Export ¶ added in v0.2.0
func (t *HTTPTransfer) Export() http.Handler
Export creates http handler to export cache entries in encoding/gob format.
Example ¶
package main import ( "context" "fmt" "net/http" "net/http/httptest" "github.com/bool64/cache" ) func main() { ctx := context.Background() cacheExporter := cache.HTTPTransfer{} mux := http.NewServeMux() mux.Handle("/debug/transfer-cache", cacheExporter.Export()) srv := httptest.NewServer(mux) defer srv.Close() // Cached entities must have exported fields to be transferable with reflection-based "encoding/gob". type SomeCachedEntity struct { Value string } // Cached entity types must be registered to gob, this can be done in init functions of cache facades. cache.GobRegister(SomeCachedEntity{}) // Exported cache(s). someEntityCache := cache.NewShardedMap() _ = someEntityCache.Write(ctx, []byte("key1"), SomeCachedEntity{Value: "foo"}) // Registry of caches. cacheExporter.AddCache("some-entity", someEntityCache) // Importing cache(s). someEntityCacheOfNewInstance := cache.NewShardedMap() // Caches registry. cacheImporter := cache.HTTPTransfer{} cacheImporter.AddCache("some-entity", someEntityCacheOfNewInstance) _ = cacheImporter.Import(ctx, srv.URL+"/debug/transfer-cache") val, _ := someEntityCacheOfNewInstance.Read(ctx, []byte("key1")) fmt.Println(val.(SomeCachedEntity).Value) }
Output: foo
Example (Generic) ¶
package main import ( "context" "fmt" "net/http" "net/http/httptest" "github.com/bool64/cache" ) func main() { ctx := context.Background() cacheExporter := cache.HTTPTransfer{} mux := http.NewServeMux() mux.Handle("/debug/transfer-cache", cacheExporter.Export()) srv := httptest.NewServer(mux) defer srv.Close() // Cached entities must have exported fields to be transferable with reflection-based "encoding/gob". type GenericCachedEntity struct { Value string } // With generic cache it is not strictly necessary to register in gob, the transfer will still work. // However, registering to gob also calculates structural hash to avoid cache transfer when the // structures have changed. cache.GobRegister(GenericCachedEntity{}) // Exported cache(s). someEntityCache := cache.NewShardedMapOf[GenericCachedEntity]() _ = someEntityCache.Write(ctx, []byte("key1"), GenericCachedEntity{Value: "foo"}) // Registry of caches. cacheExporter.AddCache("some-entity", someEntityCache.WalkDumpRestorer()) // Importing cache(s). someEntityCacheOfNewInstance := cache.NewShardedMapOf[GenericCachedEntity]() // Caches registry. cacheImporter := cache.HTTPTransfer{} cacheImporter.AddCache("some-entity", someEntityCacheOfNewInstance.WalkDumpRestorer()) _ = cacheImporter.Import(ctx, srv.URL+"/debug/transfer-cache") val, _ := someEntityCacheOfNewInstance.Read(ctx, []byte("key1")) fmt.Println(val.Value) }
Output: foo
func (*HTTPTransfer) ExportJSONL ¶ added in v0.2.0
func (t *HTTPTransfer) ExportJSONL() http.Handler
ExportJSONL creates http handler to export cache entries as JSON lines.
type InvalidationIndex ¶ added in v0.4.1
type InvalidationIndex struct {
// contains filtered or unexported fields
}
InvalidationIndex keeps index of keys labeled for future invalidation.
func NewInvalidationIndex ¶ added in v0.4.1
func NewInvalidationIndex(deleters ...Deleter) *InvalidationIndex
NewInvalidationIndex creates new instance of label-based invalidator.
Example ¶
package main import ( "context" "fmt" "github.com/bool64/cache" ) func main() { // Invalidation index maintains lists of keys in multiple cache instances with shared labels. // For example, when you were building cache value, you used resources that can change in the future. // You can add a resource label to the new cache key (separate label for each resource), so that later, // when resource is changed, invalidation index can be asked to drop cached entries associated // with respective label. i := cache.NewInvalidationIndex() cache1 := cache.NewShardedMap() cache2 := cache.NewShardedMap() cache2a := cache.NewShardedMap() // Each cache instance, that is subject for invalidation needs to be added with a name. i.AddCache("one", cache1) // Multiple instances can share same name. i.AddCache("two", cache2) i.AddCache("two", cache2a) ctx := context.Background() _ = cache1.Write(ctx, []byte("keyA"), "A1") _ = cache1.Write(ctx, []byte("keyB"), "B1") _ = cache2.Write(ctx, []byte("keyA"), "A2") _ = cache2.Write(ctx, []byte("keyB"), "B2") _ = cache2a.Write(ctx, []byte("keyA"), "A2") _ = cache2a.Write(ctx, []byte("keyB"), "B2") // Labeling keyA in both caches. i.AddLabels("one", []byte("keyA"), "A") i.AddLabels("two", []byte("keyA"), "A") // Labeling keyA only in one cache. i.AddLabels("one", []byte("keyB"), "B") // Invalidation will delete keyA in both cache one and two. n, _ := i.InvalidateByLabels(ctx, "A") fmt.Println("Keys deleted for A:", n) // Invalidation will not affect keyB in cache two, but will delete in cache one. n, _ = i.InvalidateByLabels(ctx, "B") fmt.Println("Keys deleted for B:", n) }
Output: Keys deleted for A: 3 Keys deleted for B: 1
func (*InvalidationIndex) AddCache ¶ added in v0.4.7
func (i *InvalidationIndex) AddCache(name string, deleter Deleter)
AddCache adds a named instance of cache with deletable entries.
func (*InvalidationIndex) AddInvalidationLabels ¶ added in v0.4.1
func (i *InvalidationIndex) AddInvalidationLabels(key []byte, labels ...string)
AddInvalidationLabels registers invalidation labels to a cache key in default cache.
func (*InvalidationIndex) AddLabels ¶ added in v0.4.7
func (i *InvalidationIndex) AddLabels(cacheName string, key []byte, labels ...string)
AddLabels registers invalidation labels to a cache key.
func (*InvalidationIndex) InvalidateByLabels ¶ added in v0.4.1
InvalidateByLabels deletes keys from cache that have any of provided labels and returns number of deleted entries. If delete fails, function puts unprocessed keys back in the index and returns.
Example ¶
package main import ( "context" "fmt" "github.com/bool64/cache" ) func main() { c := cache.NewShardedMap() ctx := context.TODO() // Any cache key can be accompanied by invalidation labels. _ = c.Write(ctx, []byte("my-foo"), "foo") c.AddInvalidationLabels([]byte("my-foo"), "my", "f**") _ = c.Write(ctx, []byte("my-bar"), "bar") c.AddInvalidationLabels([]byte("my-bar"), "my", "b**") _ = c.Write(ctx, []byte("my-baz"), "baz") c.AddInvalidationLabels([]byte("my-baz"), "my", "b**") n, _ := c.InvalidateByLabels(ctx, "b**") fmt.Println("deleted items for 'b**':", n) _, err := c.Read(ctx, []byte("my-foo")) fmt.Println("my-foo err:", err) _, err = c.Read(ctx, []byte("my-bar")) fmt.Println("my-bar err:", err) _, err = c.Read(ctx, []byte("my-baz")) fmt.Println("my-baz err:", err) n, _ = c.InvalidateByLabels(ctx, "my", "f**") fmt.Println("deleted items for 'my':", n) _, err = c.Read(ctx, []byte("my-foo")) fmt.Println("my-foo err:", err) }
Output: deleted items for 'b**': 2 my-foo err: <nil> my-bar err: missing cache item my-baz err: missing cache item deleted items for 'my': 1 my-foo err: missing cache item
type Invalidator ¶
type Invalidator struct { sync.Mutex // SkipInterval defines minimal duration between two cache invalidations (flood protection). SkipInterval time.Duration // Callbacks contains a list of functions to call on invalidate. Callbacks []func(ctx context.Context) // contains filtered or unexported fields }
Invalidator is a registry of cache expiration triggers.
func (*Invalidator) Invalidate ¶
func (i *Invalidator) Invalidate(ctx context.Context) error
Invalidate triggers cache expiration.
type Key ¶ added in v0.2.6
type Key []byte
Key os a key of cached entry.
func (Key) MarshalText ¶ added in v0.2.6
MarshalText renders bytes as text.
type Logger ¶ added in v0.2.4
type Logger interface { // Error logs a message. Error(ctx context.Context, msg string, keysAndValues ...interface{}) }
Logger collects contextual information.
This interface matches github.com/bool64/ctxd.Logger.
type NoOp ¶
type NoOp struct{}
NoOp is a ReadWriter stub.
type ReadWriter ¶
ReadWriter reads from and writes to cache.
type ReadWriterOf ¶ added in v0.2.3
ReadWriterOf reads from and writes to cache.
type Reader ¶
type Reader interface { // Read returns cached value or error. Read(ctx context.Context, key []byte) (interface{}, error) }
Reader reads from cache.
type ReaderOf ¶ added in v0.2.3
type ReaderOf[V any] interface { // Read returns cached value or error. Read(ctx context.Context, key []byte) (V, error) }
ReaderOf reads from cache.
type ShardedMap ¶
type ShardedMap struct {
// contains filtered or unexported fields
}
ShardedMap is an in-memory cache backend. Please use NewShardedMap to create it.
func NewShardedMap ¶
func NewShardedMap(options ...func(cfg *Config)) *ShardedMap
NewShardedMap creates an instance of in-memory cache with optional configuration.
Example ¶
package main import ( "context" "fmt" "log" "time" "github.com/bool64/cache" ) func main() { // Create cache instance. c := cache.NewShardedMap(cache.Config{ Name: "dogs", TimeToLive: 13 * time.Minute, // Logging errors with standard logger, non-error messages are ignored. Logger: cache.NewLogger(func(ctx context.Context, msg string, keysAndValues ...interface{}) { log.Printf("cache failed: %s %v", msg, keysAndValues) }, nil, nil, nil), // Tweak these parameters to reduce/stabilize rwMutexMap consumption at cost of cache hit rate. // If cache cardinality and size are reasonable, default values should be fine. DeleteExpiredAfter: time.Hour, DeleteExpiredJobInterval: 10 * time.Minute, HeapInUseSoftLimit: 200 * 1024 * 1024, // 200MB soft limit for process heap in use. EvictFraction: 0.2, // Drop 20% of mostly expired items (including non-expired) on heap overuse. }.Use) // Use context if available, it may hold TTL and SkipRead information. ctx := context.TODO() // Write value to cache. _ = c.Write( cache.WithTTL(ctx, time.Minute, true), // Change default TTL with context if necessary. []byte("my-key"), []int{1, 2, 3}, ) // Read value from cache. val, _ := c.Read(ctx, []byte("my-key")) fmt.Printf("%v", val) // Delete value from cache. _ = c.Delete(ctx, []byte("my-key")) }
Output: [1 2 3]
func (ShardedMap) Delete ¶
Delete removes value by the key.
It fails with ErrNotFound if key does not exist.
func (*ShardedMap) Dump ¶
func (c *ShardedMap) Dump(w io.Writer) (int, error)
Dump saves cached entries and returns a number of processed entries.
Dump uses encoding/gob to serialize cache entries, therefore it is necessary to register cached types in advance with cache.GobRegister.
func (ShardedMap) ExpireAll ¶
ExpireAll marks all entries as expired, they can still serve stale cache.
func (ShardedMap) Load ¶ added in v0.2.2
Load returns the value stored in the map for a key, or nil if no value is present. The ok result indicates whether value was found in the map.
func (*ShardedMap) Restore ¶
func (c *ShardedMap) Restore(r io.Reader) (int, error)
Restore loads cached entries and returns number of processed entries.
Restore uses encoding/gob to unserialize cache entries, therefore it is necessary to register cached types in advance with cache.GobRegister.
func (ShardedMap) Store ¶ added in v0.2.2
func (c ShardedMap) Store(key []byte, val interface{})
Store sets the value for a key.
type ShardedMapOf ¶ added in v0.2.3
type ShardedMapOf[V any] struct { // contains filtered or unexported fields }
ShardedMapOf is an in-memory cache backend. Please use NewShardedMapOf to create it.
func NewShardedMapOf ¶ added in v0.2.3
func NewShardedMapOf[V any](options ...func(cfg *Config)) *ShardedMapOf[V]
NewShardedMapOf creates an instance of in-memory cache with optional configuration.
Example ¶
package main import ( "context" "fmt" "log" "time" "github.com/bool64/cache" ) func main() { // Dog is your cached type. type Dog struct { Name string } // Create cache instance. c := cache.NewShardedMapOf[Dog](cache.Config{ Name: "dogs", TimeToLive: 13 * time.Minute, // Logging errors with standard logger, non-error messages are ignored. Logger: cache.NewLogger(func(ctx context.Context, msg string, keysAndValues ...interface{}) { log.Printf("cache failed: %s %v", msg, keysAndValues) }, nil, nil, nil), // Tweak these parameters to reduce/stabilize rwMutexMap consumption at cost of cache hit rate. // If cache cardinality and size are reasonable, default values should be fine. DeleteExpiredAfter: time.Hour, DeleteExpiredJobInterval: 10 * time.Minute, HeapInUseSoftLimit: 200 * 1024 * 1024, // 200MB soft limit for process heap in use. EvictFraction: 0.2, // Drop 20% of mostly expired items (including non-expired) on heap overuse. }.Use) // Use context if available, it may hold TTL and SkipRead information. ctx := context.TODO() // Write value to cache. _ = c.Write( cache.WithTTL(ctx, time.Minute, true), // Change default TTL with context if necessary. []byte("my-key"), Dog{Name: "Snoopy"}, ) // Read value from cache. val, _ := c.Read(ctx, []byte("my-key")) fmt.Printf("%s", val.Name) // Delete value from cache. _ = c.Delete(ctx, []byte("my-key")) }
Output: Snoopy
func (ShardedMapOf) Delete ¶ added in v0.2.3
Delete removes value by the key.
It fails with ErrNotFound if key does not exist.
func (*ShardedMapOf[V]) Dump ¶ added in v0.2.3
func (c *ShardedMapOf[V]) Dump(w io.Writer) (int, error)
Dump saves cached entries and returns a number of processed entries.
Dump uses encoding/gob to serialize cache entries, therefore it is necessary to register cached types in advance with cache.GobRegister.
func (ShardedMapOf) ExpireAll ¶ added in v0.2.3
ExpireAll marks all entries as expired, they can still serve stale cache.
func (ShardedMapOf) Len ¶ added in v0.2.3
func (c ShardedMapOf) Len() int
Len returns number of elements in cache.
func (ShardedMapOf) Load ¶ added in v0.2.3
Load returns the value stored in the map for a key, or nil if no value is present. The ok result indicates whether value was found in the map.
func (*ShardedMapOf[V]) Restore ¶ added in v0.2.3
func (c *ShardedMapOf[V]) Restore(r io.Reader) (int, error)
Restore loads cached entries and returns number of processed entries.
Restore uses encoding/gob to unserialize cache entries, therefore it is necessary to register cached types in advance with cache.GobRegister.
func (ShardedMapOf) Store ¶ added in v0.2.3
func (c ShardedMapOf) Store(key []byte, val V)
Store sets the value for a key.
func (*ShardedMapOf[V]) WalkDumpRestorer ¶ added in v0.2.5
func (c *ShardedMapOf[V]) WalkDumpRestorer() WalkDumpRestorer
WalkDumpRestorer is an adapter of a non-generic cache transfer interface.
type StatsTracker ¶ added in v0.2.4
type StatsTracker interface { // Add collects additional or observable value. Add(ctx context.Context, name string, increment float64, labelsAndValues ...string) // Set collects absolute value, e.g. number of cache entries at the moment. Set(ctx context.Context, name string, absolute float64, labelsAndValues ...string) }
StatsTracker collects incremental and absolute (gauge) metrics.
This interface matches github.com/bool64/stats.Tracker.
func NewStatsTracker ¶ added in v0.2.4
func NewStatsTracker( add, set func(ctx context.Context, name string, val float64, labelsAndValues ...string), ) StatsTracker
NewStatsTracker creates logger instance from tracking functions.
type SyncMap ¶ added in v0.2.1
type SyncMap struct {
// contains filtered or unexported fields
}
SyncMap is an in-memory cache backend. Please use NewSyncMap to create it.
func NewSyncMap ¶ added in v0.2.1
NewSyncMap creates an instance of in-memory cache with optional configuration.
func (*SyncMap) Dump ¶ added in v0.2.1
Dump saves cached entries and returns a number of processed entries.
Dump uses encoding/gob to serialize cache entries, therefore it is necessary to register cached types in advance with GobRegister.
func (SyncMap) ExpireAll ¶ added in v0.2.1
ExpireAll marks all entries as expired, they can still serve stale values.
func (SyncMap) Len ¶ added in v0.2.1
func (c SyncMap) Len() int
Len returns number of elements including expired.
func (*SyncMap) Restore ¶ added in v0.2.1
Restore loads cached entries and returns number of processed entries.
Restore uses encoding/gob to unserialize cache entries, therefore it is necessary to register cached types in advance with GobRegister.
type Trait ¶ added in v0.2.6
type Trait struct { Closed chan struct{} DeleteExpired func(before time.Time) Len func() int Evict func(fraction float64) int Config Config Stat StatsTracker Log logTrait // contains filtered or unexported fields }
Trait is a shared trait, useful to implement ReadWriter.
func (*Trait) NotifyDeleted ¶ added in v0.2.6
NotifyDeleted collects logs and metrics.
func (*Trait) NotifyDeletedAll ¶ added in v0.2.6
NotifyDeletedAll collects logs and metrics.
func (*Trait) NotifyExpiredAll ¶ added in v0.2.6
NotifyExpiredAll collects logs and metrics.
func (*Trait) NotifyWritten ¶ added in v0.2.6
func (c *Trait) NotifyWritten(ctx context.Context, key []byte, value interface{}, ttl time.Duration)
NotifyWritten collects logs and metrics.
func (*Trait) PrepareRead ¶ added in v0.2.6
func (c *Trait) PrepareRead(ctx context.Context, cacheEntry *TraitEntry, found bool) (interface{}, error)
PrepareRead handles cached entry.
type TraitEntry ¶ added in v0.2.6
type TraitEntry struct { K Key `json:"key" description:"Key."` V interface{} `json:"val" description:"Value."` E int64 `json:"exp" description:"Expiration timestamp (ns)."` C int64 `json:"-" description:"Usage count or last serve timestamp (ns)."` }
TraitEntry is a cache entry.
func (TraitEntry) ExpireAt ¶ added in v0.2.6
func (e TraitEntry) ExpireAt() time.Time
ExpireAt returns entry expiration time.
func (TraitEntry) Value ¶ added in v0.2.6
func (e TraitEntry) Value() interface{}
Value returns entry value.
type TraitEntryOf ¶ added in v0.2.6
type TraitEntryOf[V any] struct { K Key `json:"key" description:"Cache entry key."` V V `json:"val" description:"Cache entry value."` E int64 `json:"exp" description:"Expiration timestamp, ns."` C int64 `json:"-" description:"Usage count or last serve timestamp (ns)."` }
TraitEntryOf is a cache entry.
func (TraitEntryOf[V]) ExpireAt ¶ added in v0.2.6
func (e TraitEntryOf[V]) ExpireAt() time.Time
ExpireAt returns entry expiration time.
func (TraitEntryOf[V]) Key ¶ added in v0.2.6
func (e TraitEntryOf[V]) Key() []byte
Key returns entry key.
func (TraitEntryOf[V]) Value ¶ added in v0.2.6
func (e TraitEntryOf[V]) Value() V
Value returns entry value.
type TraitOf ¶ added in v0.2.6
TraitOf is a parametrized shared trait, useful to implement ReadWriterOf.
func NewTraitOf ¶ added in v0.2.6
NewTraitOf instantiates new TraitOf.
func (*TraitOf[V]) NotifyWritten ¶ added in v0.2.6
NotifyWritten collects logs and metrics.
func (*TraitOf[V]) PrepareRead ¶ added in v0.2.6
func (c *TraitOf[V]) PrepareRead(ctx context.Context, cacheEntry *TraitEntryOf[V], found bool) (v V, err error)
PrepareRead handles cached entry.
type WalkDumpRestorer ¶ added in v0.2.0
WalkDumpRestorer walks, dumps and restores cache.
type Walker ¶
Walker calls function for every entry in cache and fails on first error returned by that function.
Count of processed entries is returned.
type WalkerOf ¶ added in v0.2.3
WalkerOf calls function for every entry in cache and fails on first error returned by that function.
Count of processed entries is returned.