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") // ErrTooLarge is returned by Load when the snapshot exceeds the size cap. ErrTooLarge = errors.New("lingcache: snapshot too large") )
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. New starts a background janitor; the caller must Close the cache when finished to stop it. Mutations after Close are no-ops; Save and Load return ErrClosed.
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 required to avoid leaking the janitor goroutine. After Close, Get/Set/Delete are no-ops; Save and Load return ErrClosed. 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 and the previous value is reported via OnEvict as ReasonDeleted. Load should typically be called on an empty cache immediately after New. The snapshot is treated as local/trusted (CRC32 is integrity, not security).
func (*Cache[K, V]) Peek ¶
Peek returns the value without recording an access, updating stats, or removing an expired entry. Expired entries are still reaped by Get and the janitor.
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. // The function must be safe for concurrent use; the cache calls it from // Get/Set as well as the background janitor. Clock func() time.Time }
Options configures a Cache. Capacity is the only required field.
type Stats ¶
type Stats struct {
Hits uint64
Misses uint64
Sets uint64
Deletes uint64
Evictions uint64
Expirations uint64
LoadsExpired uint64 // skipped on Load because ExpireAt is already due
LoadsDropped uint64 // skipped on Load because the cache was at capacity
LoadsSkipped uint64 // LoadsExpired + LoadsDropped
}
Stats is a point-in-time snapshot of cache counters.