Documentation
¶
Overview ¶
Package cache provides a key-value cache abstraction with a built-in in-memory store. Modelled on Laravel's Cache facade.
The Store interface is small enough to back with Redis, Memcached, or a database — those drivers live in separate sub-packages so the core module has zero extra dependencies.
Usage:
c := cache.NewMemory()
c.Put(ctx, "user:1", []byte("Ada"), 5*time.Minute)
v, ok, _ := c.Get(ctx, "user:1")
c.Forget(ctx, "user:1")
Helper:
v, err := cache.Remember(ctx, c, "users:list", time.Minute, func() ([]byte, error) {
return fetchAndSerializeUsers()
})
Index ¶
- Variables
- func Add(ctx context.Context, s Store, key string, value []byte, ttl time.Duration) (bool, error)
- func Decrement(ctx context.Context, s Store, key string, delta int64) (int64, error)
- func Increment(ctx context.Context, s Store, key string, delta int64) (int64, error)
- func Many(ctx context.Context, s Store, keys ...string) (map[string][]byte, error)
- func Pull(ctx context.Context, s Store, key string) ([]byte, bool, error)
- func PutMany(ctx context.Context, s Store, items map[string][]byte, ttl time.Duration) error
- func Remember(ctx context.Context, s Store, key string, ttl time.Duration, ...) ([]byte, error)
- type Memory
- func (m *Memory) Add(_ context.Context, key string, value []byte, ttl time.Duration) (bool, error)
- func (m *Memory) Close()
- func (m *Memory) Decrement(ctx context.Context, key string, delta int64) (int64, error)
- func (m *Memory) Flush(_ context.Context) error
- func (m *Memory) Forever(ctx context.Context, key string, value []byte) error
- func (m *Memory) Forget(_ context.Context, key string) error
- func (m *Memory) Get(_ context.Context, key string) ([]byte, bool, error)
- func (m *Memory) Has(ctx context.Context, key string) (bool, error)
- func (m *Memory) Increment(_ context.Context, key string, delta int64) (int64, error)
- func (m *Memory) Many(_ context.Context, keys ...string) (map[string][]byte, error)
- func (m *Memory) Pull(_ context.Context, key string) ([]byte, bool, error)
- func (m *Memory) Put(_ context.Context, key string, value []byte, ttl time.Duration) error
- func (m *Memory) PutMany(_ context.Context, items map[string][]byte, ttl time.Duration) error
- type Store
Constants ¶
This section is empty.
Variables ¶
var ErrMiss = errors.New("cache: key not found")
ErrMiss is returned by Get-shaped APIs that signal absence with an error. The basic Store interface uses (value, ok, error) instead, so ErrMiss is mostly informational for higher layers.
var ErrUnsupported = errors.New("cache: operation not supported by store")
ErrUnsupported is returned by free helpers whose semantics cannot be emulated safely on a plain Store. For example, Increment needs an atomic read-modify-write that a basic Get+Put cannot provide without racing, so on stores that do not implement the incrementer optional interface the helper reports ErrUnsupported rather than silently corrupting the counter under concurrency.
Functions ¶
func Add ¶ added in v0.21.0
Add stores value under key only if it is absent. If the store implements adder (e.g. *Memory) the check-and-set is atomic, making this a reliable lock primitive. Otherwise it falls back to a non-atomic Has followed by Put, which may race with a concurrent Add/Put of the same key — acceptable for best-effort caching, not for locking. Returns true when the value was stored.
func Decrement ¶ added in v0.21.0
Decrement atomically subtracts delta from the counter at key. See Increment for store requirements and the ErrUnsupported fallback.
func Increment ¶ added in v0.21.0
Increment atomically adds delta to the integer counter at key and returns the new value. It requires a store that implements incrementer (e.g. *Memory); on any other store it returns ErrUnsupported, because a Get+Put emulation cannot guarantee the atomic read-modify-write a counter needs and would silently lose updates under concurrency.
func Many ¶ added in v0.21.0
Many returns the values for the present keys. If the store implements manyer (e.g. *Memory) the reads happen in one critical section; otherwise it falls back to a per-key Get loop, which is not a consistent snapshot but is otherwise correct. Missing/expired keys are omitted.
func Pull ¶
Pull reads a key and removes it. If the underlying store implements puller (e.g. *Memory) the read-and-delete is atomic; otherwise it falls back to a non-atomic Get followed by Forget, which may race with a concurrent Pull/Put of the same key. Returns (nil, false, nil) on miss.
func PutMany ¶ added in v0.21.0
PutMany stores every item under the same TTL. If the store implements manyer (e.g. *Memory) the writes happen in one critical section; otherwise it falls back to a per-key Put loop and stops at the first error.
func Remember ¶
func Remember(ctx context.Context, s Store, key string, ttl time.Duration, fn func() ([]byte, error)) ([]byte, error)
Remember returns the value for key if present, otherwise calls fn, stores the result with ttl, and returns it. The classic "cache-aside" pattern.
users, err := cache.Remember(ctx, store, "users:list", time.Minute,
func() ([]byte, error) { return json.Marshal(listUsers()) })
Types ¶
type Memory ¶
type Memory struct {
// contains filtered or unexported fields
}
Memory is a process-local Store backed by a sync.RWMutex map. Safe for concurrent use; expiry is lazy (checked on Get/Has) with a background sweeper to keep the map from growing unbounded.
func NewMemory ¶
func NewMemory() *Memory
NewMemory returns a fresh in-memory cache. A goroutine periodically purges expired keys; call Close() when discarding the cache to stop it.
func (*Memory) Add ¶ added in v0.21.0
Add stores value under key only if the key is absent (or expired), returning true when it stored. A return of false means a live value already occupied the key and was left untouched. The check and the write happen in one critical section, so Add is a safe lock primitive: of N concurrent Adds for the same key exactly one wins.
TTL semantics match Put: ttl==0 stores forever, ttl<0 is treated as an already-expired write and stores nothing (Add returns false only when a live value blocks it, so a ttl<0 Add on an absent key returns true without storing).
func (*Memory) Close ¶
func (m *Memory) Close()
Close stops the background sweeper. Subsequent operations remain safe but expired entries will only be evicted on access.
func (*Memory) Decrement ¶ added in v0.21.0
Decrement atomically subtracts delta from the counter at key. It is Increment with a negated delta; see Increment for value encoding and error behaviour.
func (*Memory) Forever ¶ added in v0.21.0
Forever stores value under key with no expiry. It is shorthand for Put(ctx, key, value, 0).
func (*Memory) Increment ¶ added in v0.21.0
Increment atomically adds delta to the integer counter stored at key and returns the new value. A missing or expired key starts from 0. The counter is persisted as its decimal ASCII representation so a plain Get reads it back consistently (e.g. Get after Increment by 5 returns []byte("5")). Incrementing a key whose value is not a base-10 integer returns an error and leaves the value unchanged.
Counters are stored without expiry (forever); use Put/Forget to reset or bound their lifetime.
func (*Memory) Many ¶ added in v0.21.0
Many returns the values for the present, non-expired keys in a single critical section. Missing or expired keys are simply omitted from the result map, so len(result) may be < len(keys). Returned slices are copies; callers may mutate them freely.
func (*Memory) Pull ¶ added in v0.20.0
Pull returns the value for key and removes it in a single critical section, so a concurrent Pull of the same key can succeed at most once. Returns (nil, false, nil) on miss or expiry.
type Store ¶
type Store interface {
// Get returns the value, whether the key existed, and any driver
// error. An expired entry behaves like a miss (ok=false, err=nil).
Get(ctx context.Context, key string) ([]byte, bool, error)
// Put stores value under key with the given TTL. ttl==0 means store
// without expiry (until explicit Forget / Flush); ttl<0 means the
// entry is already expired and is treated as an immediate miss (the
// key is removed rather than stored).
Put(ctx context.Context, key string, value []byte, ttl time.Duration) error
// Forget removes the key (no error if missing).
Forget(ctx context.Context, key string) error
// Flush wipes everything.
Flush(ctx context.Context) error
// Has reports whether the key exists and is not expired.
Has(ctx context.Context, key string) (bool, error)
}
Store is the minimum surface a cache driver must implement.
All methods take a context so callers can cancel slow remote stores. The in-memory implementation ignores the context value but still respects the deadline via the (rare) blocking codepaths.