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

memcache

package
v0.56.0 Latest Latest
Warning

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

Go to latest
Published: Oct 11, 2026 License: MIT Imports: 4 Imported by: 0

Documentation

Overview

Package memcache is filex's ONE in-process cache for small state and settings that live in the database: a bounded, expiring map (Cache), and the same map kept in front of a durable store, written through it in both directions (Through).

The owner's ruling (2026-10-06, #184): keep it in the database, and where the database is not fast enough keep a simple in-memory cache in front of it - not Redis, nothing outside the process - for this kind of state and setting, both ways.

Why one package

The tree grew its process-local caches one at a time, each a map, a mutex and a hand-written expiry: the storage usage card's (api/handlers quota_storages.go, now a Cache), the S3 etag memo, the protocol sessions' grant sets, the document server's record of who opened a session. Every one of them answers the same three questions - how big may it get, how long is an entry true, how does it forget one - and every hand-written answer is a place to get one wrong (a map with no ceiling is a memory incident). New state goes here; the older ones move here when they are next touched.

The rule that keeps it honest (Through)

⚠⚠ The cache is a READ ACCELERATOR, never the authority. Behind several filex instances sharing one database, another instance's write is not in this instance's cache, so an entry can be stale for up to its TTL:

  • a write goes to the store FIRST and to the cache only when the store took it (Set, Add, Delete): the cache never says something the store does not;
  • a read for speed may be answered from the cache (Get);
  • a read that DECIDES something another instance may have changed - may this save go over the file? - is read from the store (Fresh), which also refreshes the cache. When the store cannot answer, Fresh says so (err) and the caller chooses; it does not quietly fall back to a possibly stale entry.

A nil Backing is a cache with nothing behind it: every call works on memory alone (a unit test, a Service built without a database).

Index

Constants

View Source
const DefaultMaxEntries = 4096

DefaultMaxEntries bounds a Cache whose Options leave MaxEntries at 0.

Variables

This section is empty.

Functions

This section is empty.

Types

type Backing

type Backing[K comparable, V any] interface {
	// Load reads k; ok is false when there is nothing stored.
	Load(ctx context.Context, k K) (v V, ok bool, err error)
	// Store creates or overwrites k.
	Store(ctx context.Context, k K, v V) error
	// Add stores v for k unless something is stored already, and returns
	// what is stored now (the first writer's value).
	Add(ctx context.Context, k K, v V) (V, error)
	// Remove deletes k; nothing stored is not an error.
	Remove(ctx context.Context, k K) error
}

Backing is the durable store a Through keeps a Cache in front of.

type Cache

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

Cache is a bounded map with an expiry and a least-recently-used eviction. Safe for concurrent use; the zero value is not usable (New). Every method is nil-safe: a nil *Cache holds nothing and remembers nothing.

func New

func New[K comparable, V any](o Options) *Cache[K, V]

New builds a Cache.

func (*Cache[K, V]) Delete

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

Delete forgets k.

func (*Cache[K, V]) DeleteFunc

func (c *Cache[K, V]) DeleteFunc(match func(K, V) bool) int

DeleteFunc forgets every entry match says yes to (an invalidation by content: every entry of one node, say); n = entries forgotten.

func (*Cache[K, V]) Expire

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

Expire forgets the entries past their TTL now (Get forgets them as it meets them; this is for a sweep); n = entries forgotten.

func (*Cache[K, V]) Get

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

Get returns the entry for k while it is fresh, and marks it used.

func (*Cache[K, V]) Len

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

Len is the number of entries held, fresh or not yet swept.

func (*Cache[K, V]) Purge

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

Purge forgets everything.

func (*Cache[K, V]) Put

func (c *Cache[K, V]) Put(k K, v V)

Put stores v for k (fresh from now), evicting the least recently used entries beyond the ceiling.

type Options

type Options struct {
	// MaxEntries is the most entries held; when full, the least recently
	// used goes. 0 = DefaultMaxEntries.
	MaxEntries int
	// TTL is how long an entry is served after it was written; 0 = until it
	// is evicted or deleted.
	TTL time.Duration
	// Now is the clock; nil = time.Now. Tests move it.
	Now func() time.Time
}

Options shape a Cache.

type Through

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

Through is a Cache in front of a Backing, written through in both directions (see the package doc for the rule).

func NewThrough

func NewThrough[K comparable, V any](back Backing[K, V], o Options) *Through[K, V]

NewThrough keeps a Cache shaped by o in front of back (nil: memory only).

func (*Through[K, V]) Add

func (t *Through[K, V]) Add(ctx context.Context, k K, v V) (V, error)

Add stores v for k unless something is stored already, and returns what is stored now; the cache holds that. Memory only: the cache's entry when it has a fresh one.

func (*Through[K, V]) Cache

func (t *Through[K, V]) Cache() *Cache[K, V]

Cache is the memory half, for an invalidation the store does not drive.

func (*Through[K, V]) Delete

func (t *Through[K, V]) Delete(ctx context.Context, k K) error

Delete removes k from the store and then from the cache. A delete the store refuses still forgets the cache's entry: the next read asks the store.

func (*Through[K, V]) Fresh

func (t *Through[K, V]) Fresh(ctx context.Context, k K) (V, bool, error)

Fresh answers from the store, and refreshes (or clears) the cache with what it said. The read for a decision another instance's write may change. Memory only (no Backing): the cache's answer.

func (*Through[K, V]) Get

func (t *Through[K, V]) Get(ctx context.Context, k K) (V, bool, error)

Get answers from the cache, else from the store (and fills the cache). For a read whose answer may be a few seconds old; see Fresh.

func (*Through[K, V]) Set

func (t *Through[K, V]) Set(ctx context.Context, k K, v V) error

Set writes v for k to the store and then to the cache. A write the store refuses changes neither.

Jump to

Keyboard shortcuts

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