Documentation
¶
Overview ¶
Package cache — hosts the compile-time interface assertions, keeping them out of the production source so the runtime binary carries no diagnostic-only declarations.
Package cache — the L1/L2 chain.
Package cache — the NewChain constructor configuration.
Package cache — range 0.3.48.* (ADR 0049 service/cache block).
Package cache provides the concrete cache stores implementing internal/core/cache: a tagged, stampede-protected memory store over the kernel LRU+TTL primitive, and the chain that puts one store in front of another. Stdlib-only, cross-OS. ADR 0049.
Package cache — declares the sentinel *errs.Error values the chained store emits. Each var's name equals its errs.Define Reason in SCREAMING_SNAKE form.
Package cache — the tagged, stampede-protected in-memory store.
Package cache — what the underlying primitive actually stores.
Package cache — the refusals every store shares, and the wrapping rule for a caller's fill error.
Package cache — the two-way tag index behind InvalidateTag.
Package cache — one level of a chained store.
Index ¶
Constants ¶
const CodeCacheChainMisconfigured errs.Code = 0x00_03_30_01 // 0.3.48.1
CodeCacheChainMisconfigured identifies a NewChain refused AT CONSTRUCTION: fewer than two tiers, a nil tier, or a tier that cannot answer the whole contract a tier must answer (see the errors.go sentinel for why that is checked once, up front, rather than discovered per call).
const CodeCacheTierFailed errs.Code = 0x00_03_30_02 // 0.3.48.2
CodeCacheTierFailed identifies a chained operation that failed inside one specific tier.
It is distinct from core's CACHE_BACKEND_FAILED because a chain has more than one backend, and "the cache is broken" and "the far tier is broken" are different incidents with different responses: the first is an outage, the second is a degradation the near tier is still absorbing.
Variables ¶
var ( // CacheChainMisconfigured is returned by NewChain for a tier set it cannot // honour. // // The interesting refusal is the third one. Every tier must implement // core/cache.EntryFetcher and core/cache.Tagger, and that is checked ONCE, // at construction, rather than per call. The reason is the whole point of // tagging: promoting a value into a nearer tier WITHOUT its tags produces // a copy that InvalidateTag can no longer reach, so the invalidation // reports success, the far tier forgets the entry, and the near tier keeps // serving it until its TTL runs out. A tag invalidation that silently // misses one copy is worse than one that was never offered — so the chain // refuses to be built rather than degrade at the moment nobody is looking. CacheChainMisconfigured = errs.Define(CodeCacheChainMisconfigured, "CACHE_CHAIN_MISCONFIGURED", "The cache chain cannot be built from the given tiers", "service/cache: NewChain received fewer than two tiers, a nil tier, or a tier that does not implement EntryFetcher and Tagger; the fields name the position and the missing capability", errs.WithExitCode(exitChainConfig)) // CacheTierFailed is returned when a chained operation failed inside one // tier. Its fields name the tier's position and the operation, because a // chain's caller holds one Store and would otherwise have no way to tell // which of two backends broke. CacheTierFailed = errs.Define(CodeCacheTierFailed, "CACHE_TIER_FAILED", "A tier of the cache chain could not serve the operation", "service/cache: one tier of a chained store returned an error; the fields name the tier position, the operation and the key") )
Functions ¶
func NewChain ¶
func NewChain[V any](cfg ChainConfig, stores ...corecache.Store[V]) (chain corecache.Store[V], err error)
NewChain puts each store in front of the next: tiers[0] is the nearest and is consulted first, the last is the authority.
Every tier MUST implement corecache.EntryFetcher and corecache.Tagger. That is checked here, once, and refused with CacheChainMisconfigured rather than discovered per call — see that sentinel for the reasoning.
The returned value is a corecache.Store and also implements corecache.EntryFetcher, corecache.Tagger and corecache.Loader.
IFACE-PLUGIN: the concrete chain stays unexported behind this constructor.
func NewMemory ¶
func NewMemory[V any](cfg MemoryConfig) (store corecache.Store[V], err error)
NewMemory builds an in-process cache store from cfg.
The returned value is a corecache.Store. It also implements corecache.EntryFetcher, corecache.Tagger and corecache.Loader; reach them by type assertion, which is the ADR 0039 way a port grows without breaking anyone who implemented it.
A non-positive MaxEntries is REFUSED, not defaulted. ADR 0031 splits on whether the SDK can supply a value without inventing the caller's requirement, and a cache capacity is the requirement: it is the whole statement of how much memory the caller is willing to spend. Worse, the value the primitive gives a zero — unbounded — is the dangerous reading, and it is dangerous twice over here, because an unbounded store also grows an unbounded tag index.
IFACE-PLUGIN: the concrete store stays unexported behind this constructor.
Types ¶
type ChainConfig ¶
type ChainConfig struct {
// OnPromoteError, if non-nil, is called when a value served from a FAR
// tier could not be written into a nearer one.
//
// A failed promotion is not a failed read: the caller already has the
// value, and failing the call would turn a degraded cache into a degraded
// service. But it is also not nothing — a near tier that rejects every
// promotion is a tier that will never be used again, and with this hook nil
// that is completely invisible. Wire it.
OnPromoteError func(key string, err error)
}
ChainConfig parameterises NewChain. Its zero value builds a working chain; the one field is an observation hook, not a policy.
type MemoryConfig ¶
type MemoryConfig struct {
// MaxEntries caps the live entry count; the least-recently-used entry is
// evicted above it. It MUST be positive.
MaxEntries int
// DefaultTTL applies to every entry whose own TTL is zero. Zero means the
// default is "no deadline", so entries leave only by eviction, by Delete,
// or by tag invalidation. Negative is refused.
DefaultTTL time.Duration
// Clock is the time source, injectable so TTL is testable. nil means
// clock.System. Only the reading half of the port is used — a cache reads
// time, it never waits for it (ADR 0039).
Clock clock.Clock
}
MemoryConfig parameterises NewMemory.
Its zero value is deliberately NOT a working cache: MaxEntries must be stated. See NewMemory for why that refusal, and not a default, is the right ADR 0031 half here.