Skip to content

golift/cache

Repository files navigation

cache

Go Reference Go Report Card MIT License discord

This module provides a small in-memory key/value cache for Go.

  • Concurrency: Each shard has its own sync.RWMutex over a map[string]*Item. Get takes 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 via sync.Map (uint32 index → shard), populated at startup when Config.Shards is greater than 1. List takes read locks per shard; Stats aggregates 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. If RequestAccuracy is set above 100ms, one goroutine also refreshes a shared clock on that interval (fewer time.Now() calls on hot paths). The optional pruner runs on PruneInterval.
  • Metrics: Hit/miss and other counters are exposed for expvar or your own metrics pipeline.
  • Sharding: Optional Config.Shards (default 1) partitions keys across multiple maps using FNV-1a 64-bit hash(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.

Example: basic use

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)
	}
}

Example: pruning and stats

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.

About

In-memory cache Go module. No locks, integrated statistics.

Topics

Resources

License

Stars

Watchers

Forks

Contributors

Languages