The library adds a thin layer on top of lru\expirable cache.
| Cache name | Constructor | Defaults | Description |
|---|---|---|---|
| LruCache | lcw.NewLruCache | keys=1000 | LRU cache with limits |
| ExpirableCache | lcw.NewExpirableCache | keys=1000, ttl=5m | TTL cache with limits |
| RedisCache | lcw.NewRedisCache | ttl=5m | Redis cache with limits |
| Nop | lcw.NewNopCache | Do-nothing cache |
Main features:
- LoadingCache (guava style)
- Limit maximum cache size (in bytes)
- Limit maximum key size
- Limit maximum size of a value
- Limit number of keys
- TTL support (
ExpirableCacheandRedisCache) - Callback on eviction event (not supported in
RedisCache) - Functional style invalidation
- Functional options
- Sane defaults
go get -u github.com/go-pkgz/lcw/v2
package main
import (
"fmt"
"github.com/go-pkgz/lcw/v2"
)
func main() {
o := lcw.NewOpts[int]()
cache, err := lcw.NewLruCache(o.MaxKeys(500), o.MaxCacheSize(65536), o.MaxValSize(200), o.MaxKeySize(32))
if err != nil {
panic("failed to create cache")
}
defer cache.Close()
val, err := cache.Get("key123", func() (int, error) {
return 123, nil // load the value from the actual source here
})
if err != nil {
panic("failed to get data")
}
fmt.Println(val) // cached value
}Cache can be created with URIs:
mem://lru?max_key_size=10&max_val_size=1024&max_keys=50&max_cache_size=64000- creates LRU cache with given limitsmem://expirable?ttl=30s&max_key_size=10&max_val_size=1024&max_keys=50&max_cache_size=64000- create expirable cacheredis://10.0.0.1:1234?db=16&password=qwerty&network=tcp4&redis_key_prefix=lcw:- create redis cache, also acceptsdial_timeout,read_timeoutandwrite_timeoutnop://- create Nop cache
Scache provides a wrapper on top of all implementations of LoadingCache with a number of special features:
- Key is not a string, but a composed type made from partition, key-id and list of scopes (tags).
- Value type is generic in v2 and limited to
[]bytein v1. - Added
Flushmethod for scoped/tagged invalidation of multiple records in a given partition. It only touches keys of the requested partition, with no scopes set the whole partition is dropped. - A simplified interface with Get, Stat, Flush and Close only.
Note that RedisCache in v2 stores string-based values only, so it can't back a Scache[[]byte].
In v1 Scache over RedisCache works, values come back as bytes.
The repository holds two modules, the root one for v1 and v2 for the generics-based version. Both have to be
tested:
go test -race ./... && (cd v2 && go test -race ./...)
- In all cache types other than Redis (e.g. LRU and Expirable at the moment) values are stored as-is which means
that mutable values can be changed outside of cache.
ExampleLoadingCache_Mutabilityillustrates that. - All byte-size limits (MaxCacheSize and MaxValSize) work for values implementing the
lcw.Sizerinterface, as well as for[]byteandstringvalues sized by their length. Values of any other type are not limited. MaxCacheSizeis not supported byRedisCache, the option is accepted but ignored andStatreports size 0.MaxKeys(0)means unlimited, as do all other limits set to 0.- Negative limits (max options) rejected
- Concurrent
Getcalls for the same missing key run the loader once, the rest wait for its result. A loader must not callGetfor the same key on the same cache, it would wait for itself. - By default
RedisCacheassumes exclusive ownership of the selected redis database, i.e.Purgeflushes it andKeys,StatandMaxKeyscount every key in it. SetRedisKeyPrefixto keep the cache in its own namespace and leave unrelated keys alone. - The implementation started as a part of remark42
and later on moved to go-pkgz/rest
library and finally generalized to become
lcw.