threadsafecache

package module
v0.1.0 Latest Latest
Warning

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

Go to latest
Published: May 2, 2026 License: Apache-2.0 Imports: 4 Imported by: 0

README

threadsafecache

Generic LRU cache + per-entry TTL. Thread-safe. One dependency (hashicorp/golang-lru/v2), one type, six methods.

import "github.com/ubgo/threadsafecache"

c, _ := threadsafecache.New[string](
    1024,                     // LRU size
    5 * time.Minute,          // TTL (0 = disabled)
)

c.Set("user:42", payload)

if v, ok := c.Get("user:42"); ok {
    use(v)
}

What you get

  • Generics. Values are stored without boxing through interface{}.
  • LRU bound. When the cache fills, the least-recently-used entry is evicted. (hashicorp/golang-lru/v2 does the heavy lifting.)
  • TTL. Entries older than the TTL miss on Get and are evicted as a side effect of being touched. Set TTL to 0 to disable expiry and use the cache as pure LRU.
  • Lock everything. All operations take the same sync.Mutex — hashicorp's LRU mutates internal state on Get (recency tracking), so splitting reads and writes is unsafe in general. The result is simple and race-clean.

API

Method Purpose
New[T](size, ttl, opts...) Construct a cache. size <= 0 returns ErrInvalidSize.
Set(key, value) Insert or replace. CreatedAt is reset on replace.
Get(key) (T, bool) Returns the value if present and fresh; evicts on expiry.
Remove(key) Delete a key. Missing keys are not an error.
Len() int Current entry count, including expired-but-not-yet-evicted.
Purge() Drop every entry.

Options

threadsafecache.New[int](
    1024, ttl,
    threadsafecache.WithClock[int](myFakeClock),  // tests only
)

License

Apache-2.0 — see LICENSE.

Documentation

Overview

Package threadsafecache is a small wrapper around hashicorp/golang-lru that adds a per-entry TTL on top of LRU eviction.

The cache is generic over the value type; keys are strings. Reads use a read-lock when the entry is fresh and an upgraded write-lock only when the entry has expired and must be evicted, so the common hit path stays concurrent.

Zero-cost generics: the inner LRU is parameterised on the same type, so the cache stores values directly (not via interface{}).

Index

Constants

This section is empty.

Variables

View Source
var ErrInvalidSize = errors.New("threadsafecache: size must be > 0")

ErrInvalidSize is returned by New when size <= 0.

Functions

This section is empty.

Types

type Cache

type Cache[T any] struct {
	// contains filtered or unexported fields
}

Cache is a thread-safe size+TTL bounded cache.

A TTL of 0 disables expiry — entries live until they are evicted by the LRU policy or removed explicitly.

func New

func New[T any](size int, ttl time.Duration, opts ...Option[T]) (*Cache[T], error)

New returns a cache with the given LRU capacity and per-entry TTL. A non-positive size returns ErrInvalidSize; a non-positive ttl disables expiry.

func (*Cache[T]) Get

func (c *Cache[T]) Get(key string) (T, bool)

Get returns the value for key. The boolean is false when the key is missing OR has expired (in the latter case the entry is also evicted as a side effect — touching expired keys cleans them up lazily).

func (*Cache[T]) Len

func (c *Cache[T]) Len() int

Len returns the number of entries currently in the cache, including any that have expired but not yet been evicted.

func (*Cache[T]) Purge

func (c *Cache[T]) Purge()

Purge drops every entry from the cache.

func (*Cache[T]) Remove

func (c *Cache[T]) Remove(key string)

Remove deletes key from the cache. Missing keys are not an error.

func (*Cache[T]) Set

func (c *Cache[T]) Set(key string, value T)

Set stores value under key. An existing entry is replaced; CreatedAt is reset.

type Entry

type Entry[T any] struct {
	Value     T
	CreatedAt time.Time
}

Entry is the on-disk shape stored in the LRU. Exposed so callers that reach into the cache for diagnostics can read CreatedAt without us committing to a separate accessor API.

type Option

type Option[T any] func(*Cache[T])

Option configures a Cache.

func WithClock

func WithClock[T any](now func() time.Time) Option[T]

WithClock overrides the time source. Used in tests; production code rarely needs this.

Jump to

Keyboard shortcuts

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