Implementation of simple local cache.
Features & todos:
- prevents "dogpile effect"
- check data expiration time
- lru policy
- cache hit and enviction stats
Cache limitations:
- keys are always int
- get function returns multiple values
- set function sets multiple keys at once
- to prevent dog pile effect queueKey should be manually set
Create cache instance
import "github.com/sima-land/go-local-cache"
c := cache.New()
Create getter function. Its preferred way to fill the cache because in case of "dog pile" effect getter will be called once.
getter := func(keys Keys) (Result, error) {
r := Result{}
for _, k := range keys {
// haavy call to database
r[k] = db.GetByID(k)
}
return r, nil
}
Obtain data from cache. If there is no data in the cache getter will be called.
Note:
- Next call is concurrently safe
- If too many go-routines in our application are trying to call this getter with same queue key (user-1) then only first call will actually be done
result, err := c.Get(int[]{1}, getter, "user-1")
You can simple use entity name and id as queueKey param of Get function. Eg:
result, err := c.Get(int[]{1}, userGetter, "user-1")
result, err := c.Get(int[]{1}, productGetter, "product-1")
Or if you need to get a page of product's block whole page. If keys 1,2 are in cache but other keys are not then:
- Keys 1 and 2 will be get from cache
- Getter will be called for keys 3,4,5 and 6
- If another getter with same queue key "product-1" was called before and first one will be used instead
result, err := c.Get(int[]{1,2,3,4,5,6}, userGetter, "product-page-1")
Cache has a variety of configuration options:
c := cache.New(cache.Options{
MaxEntries: 1000000, // Specify max number items in cache
TTL: time.Hour, // Time to live for cache entries
})
MacBook 2,7 GHz Intel Core i5
BenchmarkCache_Get-4 500000 2274 ns/op
BenchmarkCache_Get-4 500000 2335 ns/op