Help us shape the future of Go! Take the 2026 Go Developer Survey

lru

package
v0.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: May 10, 2026 License: AGPL-3.0 Imports: 6 Imported by: 0

Documentation

Overview

Package lru is an in-process least-recently-used cache with optional TTL + singleflight wrapping. The S36 perf-pass standardizes on this package for every cross-request cache (refs, tree, ahead/ behind, rendered markdown, etc.) so callers don't roll their own eviction story.

Two core types:

  • Cache[K,V] — count-bounded LRU with optional per-entry TTL. The dumb-and-fast variant for value types whose in-memory cost is uniform.

  • SizedCache[K] — byte-bounded LRU. Each entry contributes a caller-supplied size; eviction runs while the total exceeds the cap. For values whose size varies per key (rendered HTML, diff blobs).

Both expose Get / Set / Delete / Len + a Stats accessor for the /metrics surface (S36 baseline asserts hit-rate). Hot-key dogpile prevention lives one layer up in `Group` (singleflight wrapper).

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Cache

type Cache[K comparable, V any] struct {
	// contains filtered or unexported fields
}

Cache is a count-bounded LRU. Construct with New[K,V](capacity).

func New

func New[K comparable, V any](capacity int) *Cache[K, V]

New constructs a count-bounded LRU. capacity must be positive. The TTL defaults to "no expiry"; use NewWithTTL to set one.

func NewWithTTL

func NewWithTTL[K comparable, V any](capacity int, ttl time.Duration) *Cache[K, V]

NewWithTTL is like New plus a per-entry TTL. Entries past their TTL are treated as misses on Get and dropped on access.

func (*Cache[K, V]) Delete

func (c *Cache[K, V]) Delete(key K)

Delete removes key. No-op when absent.

func (*Cache[K, V]) Get

func (c *Cache[K, V]) Get(key K) (V, bool)

Get returns the value for key + true on hit, zero value + false on miss (including TTL-expired entries).

func (*Cache[K, V]) Len

func (c *Cache[K, V]) Len() int

Len reports the live entry count (does NOT scan for TTL expiry — that happens lazily on Get).

func (*Cache[K, V]) Set

func (c *Cache[K, V]) Set(key K, val V)

Set stores key→val, evicting the least-recently-used entry when at capacity. Replacing an existing key resets its TTL.

func (*Cache[K, V]) Stats

func (c *Cache[K, V]) Stats() Stats

Stats returns a snapshot of the hit / miss / eviction counters.

type Group

type Group[K comparable, V any] struct {
	// contains filtered or unexported fields
}

Group wraps a Cache with single-flight semantics so a hot-key miss doesn't spawn N concurrent upstream calls. The fetch function is invoked at most once per (key, in-flight wave) — concurrent callers wait on the same goroutine and receive its result.

Use this whenever the upstream is non-trivial: a `git rev-list` subprocess, an FS walk, a multi-row DB read.

func NewGroup

func NewGroup[K comparable, V any](cache *Cache[K, V], keyer func(K) string) *Group[K, V]

NewGroup wraps cache with singleflight. keyer must produce a stable, unique string for every distinct K (default: `fmt.Sprint`- equivalent for the type). For composite keys (struct), the caller is on the hook for serialization.

func (*Group[K, V]) Do

func (g *Group[K, V]) Do(ctx context.Context, key K, fetch func(ctx context.Context) (V, error)) (V, error)

Do returns the cached value when present, otherwise invokes fetch (single-flighted) and caches the result before returning.

Errors from fetch are NOT cached — a transient failure on key K shouldn't poison subsequent reads. Callers that want negative- caching add their own sentinel value.

func (*Group[K, V]) Invalidate

func (g *Group[K, V]) Invalidate(key K)

Invalidate drops key from the cache. Safe to call from anywhere (push handlers, settings updates) without coordinating with in-flight singleflight callers — the next Do re-fetches.

func (*Group[K, V]) Stats

func (g *Group[K, V]) Stats() Stats

Stats reports the underlying cache's counters.

type SizedCache

type SizedCache[K comparable] struct {
	// contains filtered or unexported fields
}

SizedCache is a byte-bounded LRU. Each entry contributes a caller- supplied size; eviction runs while the running total exceeds the cap. Use this for caches whose values vary widely in memory cost (rendered HTML, diff blobs, response bodies).

func NewSized

func NewSized[K comparable](maxBytes int64) *SizedCache[K]

NewSized constructs a byte-bounded LRU. maxBytes must be positive.

func (*SizedCache[K]) Bytes

func (c *SizedCache[K]) Bytes() int64

Bytes reports the current total payload size.

func (*SizedCache[K]) Delete

func (c *SizedCache[K]) Delete(key K)

Delete removes key. No-op when absent.

func (*SizedCache[K]) Get

func (c *SizedCache[K]) Get(key K) ([]byte, bool)

Get returns the cached bytes + true on hit. The returned slice is the cached buffer (zero-copy) — callers MUST NOT mutate it. Use `append([]byte(nil), v...)` if mutation is needed.

func (*SizedCache[K]) Len

func (c *SizedCache[K]) Len() int

Len reports the entry count.

func (*SizedCache[K]) Set

func (c *SizedCache[K]) Set(key K, val []byte)

Set stores key→val. Replacing an existing key updates its size. Eviction runs after insertion until total bytes ≤ maxBytes.

func (*SizedCache[K]) Stats

func (c *SizedCache[K]) Stats() Stats

Stats returns a snapshot of the hit / miss / eviction counters.

type Stats

type Stats struct {
	Hits      uint64
	Misses    uint64
	Evictions uint64
}

Stats is the per-cache hit / miss / eviction counter set. Counters are atomic so /metrics can read without locking the cache.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL