Documentation
¶
Overview ¶
Package lingcache is a lightweight, high-performance, thread-safe in-memory cache.
Design is informed by Otter, Theine, and Caffeine:
- Adaptive W-TinyLFU eviction (window LRU + TinyLFU admission into a segmented main LRU) for high hit ratio across recency- and frequency-biased workloads.
- Sharded hashmap with per-shard RWMutex for concurrent Get/Set.
- BP-Wrapper style buffers: lossy striped read buffer and lossless write buffer, so the eviction policy is updated in batches under a single lock.
- Hierarchical timing wheel for O(1) TTL expiration, plus lazy checks on Get. Wheel buckets are circular lists (no entry[K,V] sentinels).
- Persistence via encoding/gob that stores absolute expiration timestamps, so remaining TTL is preserved across Save/Load (including process downtime).
- Fast path below 50% occupancy: the frequency sketch is lazy and access recording is skipped until the cache is actually competing for space.
The library uses only the Go standard library.
Example ¶
package main
import (
"bytes"
"fmt"
"time"
"github.com/bagualing/lingcache"
)
func main() {
c, err := lingcache.New[string, string](lingcache.Options[string, string]{
Capacity: 10_000,
})
if err != nil {
panic(err)
}
defer c.Close()
c.Set("user:1", "alice")
c.SetWithTTL("session", "tok", time.Hour)
if v, ok := c.Get("user:1"); ok {
fmt.Println(v)
}
var buf bytes.Buffer
if err := c.Save(&buf); err != nil {
panic(err)
}
c2 := lingcache.Must(lingcache.Options[string, string]{Capacity: 10_000})
defer c2.Close()
if err := c2.Load(&buf); err != nil {
panic(err)
}
fmt.Println(c2.Has("session"))
}
Output: alice true
Index ¶
- Variables
- type Cache
- func (c *Cache[K, V]) Capacity() int
- func (c *Cache[K, V]) Clear()
- func (c *Cache[K, V]) Close()
- func (c *Cache[K, V]) Delete(key K) bool
- func (c *Cache[K, V]) Get(key K) (V, bool)
- func (c *Cache[K, V]) Has(key K) bool
- func (c *Cache[K, V]) Len() int
- func (c *Cache[K, V]) Load(r io.Reader) error
- func (c *Cache[K, V]) Peek(key K) (V, bool)
- func (c *Cache[K, V]) Range(fn func(key K, value V) bool)
- func (c *Cache[K, V]) Save(w io.Writer) error
- func (c *Cache[K, V]) Set(key K, value V)
- func (c *Cache[K, V]) SetWithTTL(key K, value V, ttl time.Duration)
- func (c *Cache[K, V]) Stats() Stats
- func (c *Cache[K, V]) Sync()
- func (c *Cache[K, V]) TTL(key K) (time.Duration, bool)
- type Options
- type Reason
- type Stats
Examples ¶
Constants ¶
This section is empty.
Variables ¶
var ( // ErrClosed is returned by Save/Load after Close. ErrClosed = errors.New("lingcache: closed") // ErrInvalidSnapshot is returned when the stream is not a cache snapshot // or the format version is unsupported. ErrInvalidSnapshot = errors.New("lingcache: invalid snapshot") // ErrCorrupt is returned when the checksum does not match. ErrCorrupt = errors.New("lingcache: corrupt snapshot") )
Functions ¶
This section is empty.
Types ¶
type Cache ¶
type Cache[K comparable, V any] struct { // contains filtered or unexported fields }
Cache is a thread-safe in-memory cache with generic keys and values, optional per-entry TTL, W-TinyLFU eviction, and snapshot persistence.
func Must ¶
func Must[K comparable, V any](opts Options[K, V]) *Cache[K, V]
Must is like New but panics on invalid options.
func New ¶
func New[K comparable, V any](opts Options[K, V]) (*Cache[K, V], error)
New constructs a cache from opts. Capacity must be positive.
func (*Cache[K, V]) Clear ¶
func (c *Cache[K, V]) Clear()
Clear removes all entries. OnEvict is invoked with ReasonDeleted for each.
func (*Cache[K, V]) Close ¶
func (c *Cache[K, V]) Close()
Close stops the background janitor, clears the cache, and rejects further mutations. Close is idempotent.
func (*Cache[K, V]) Get ¶
Get returns the value stored for key. Expired entries are treated as misses and removed. A successful Get counts as an access for the eviction policy.
func (*Cache[K, V]) Len ¶
Len returns an estimate of the number of resident entries, including entries that have expired but not yet been reaped.
func (*Cache[K, V]) Load ¶
Load restores entries from r, skipping those whose absolute deadline has already passed. Existing entries with the same key are overwritten. Load should typically be called on an empty cache immediately after New.
func (*Cache[K, V]) Range ¶
Range calls fn for each live (non-expired) entry. If fn returns false, iteration stops. fn must not call methods on c.
func (*Cache[K, V]) Save ¶
Save writes a snapshot to w. Absolute expiration timestamps are stored, so remaining TTL is preserved (wall-clock deadlines survive process downtime). Entries are written hottest-first; Load into a smaller cache keeps the hottest.
Key and value types must be gob-encodable. Save may be called concurrently with other cache operations.
func (*Cache[K, V]) Set ¶
func (c *Cache[K, V]) Set(key K, value V)
Set stores value for key using DefaultTTL (no expiration if DefaultTTL is 0).
func (*Cache[K, V]) SetWithTTL ¶
SetWithTTL stores value for key with the given TTL. A non-positive ttl means the entry does not expire. If the key already exists, its value and TTL are replaced.
type Options ¶
type Options[K comparable, V any] struct { // Capacity is the maximum number of entries. Must be > 0. Capacity int // DefaultTTL is applied by Set. Zero means the entry does not expire. // SetWithTTL ignores this and uses the provided duration. DefaultTTL time.Duration // OnEvict is invoked after an entry is removed, without holding cache locks. // The callback must not block and must not call back into the same Cache. OnEvict func(key K, value V, reason Reason) // ShardCount overrides the number of hashmap shards. Must be a power of two. // Zero selects a default based on GOMAXPROCS. ShardCount int // Clock overrides the time source. Used in tests. Nil uses time.Now. Clock func() time.Time }
Options configures a Cache. Capacity is the only required field.