This module provides a small in-memory key/value cache for Go.
- Concurrency: Each shard has its own
sync.RWMutexover amap[string]*Item.Gettakes a read lock on that shard;Save,Update,Delete, and the pruner take the write lock. Hit/miss and per-item access metadata use atomics so reads do not serialize on the mutex. Shards are looked up viasync.Map(uint32index → shard), populated at startup whenConfig.Shardsis greater than 1.Listtakes read locks per shard;Statsaggregates atomic counters and per-shard item counts (under contention, counter snapshots can be briefly inconsistent across fields). - Background work: By default each operation uses
time.Now()directly. IfRequestAccuracyis set above 100ms, one goroutine also refreshes a shared clock on that interval (fewertime.Now()calls on hot paths). The optional pruner runs onPruneInterval. - Metrics: Hit/miss and other counters are exposed for
expvaror your own metrics pipeline. - Sharding: Optional
Config.Shards(default 1) partitions keys across multiple maps using FNV-1a 64-bithash(key) % Shards(capped at 65536). Use this to reduce mutex contention under high concurrency.
Items can be marked prunable or not. Prunable entries are removed after they have not been retrieved within PruneAfter.
Non-prunable entries use a separate maximum idle duration (MaxUnused).
I wrote this to cache data from MySQL queries for an nginx auth proxy. It is also useful as a simple global in-process store.
package main
import (
"fmt"
"golift.io/cache"
)
func main() {
c := cache.New(cache.Config{})
defer c.Stop(true)
c.Save("user:42", "Ada", cache.Options{})
item := c.Get("user:42")
if item != nil {
fmt.Println("value:", item.Data)
}
}import (
"fmt"
"time"
"golift.io/cache"
)
func exampleStats() {
c := cache.New(cache.Config{
PruneInterval: 5 * time.Minute,
PruneAfter: 10 * time.Minute,
MaxUnused: 24 * time.Hour,
})
defer c.Stop(false)
c.Save("session:1", "opaque-token", cache.Options{Prune: true})
stats := c.Stats()
fmt.Println("hits:", stats.Hits, "size:", stats.Size)
}See also the package example in cache_test.go.