Documentation
¶
Overview ¶
Package cascache implements a provider-agnostic cache with compare-and-swap (CAS) safety via per-key generations. Single-key reads never return stale values. Bulk results are validated on read (per member) and rejected if any member is stale.
Components:
- Provider: byte store with TTL (e.g. Ristretto, BigCache, Redis).
- Codec[V]: (de)serializes V <-> []byte.
- GenStore: generation counter per logical key. Local (in-process) by default, optional Redis implementation for multi-replica / restart persistence. Custom implementations receive opaque genstore.CacheKey identities, not logical user keys.
Keys:
cas:v1:val:s:<nsLen>:<ns>:<key> - single entries cas:v1:val:b:<nsLen>:<ns>:<sha256-128> - set-shaped entries (128-bit SHA-256 over sorted keys) cas:v1:gen:s:<nsLen>:<ns>:<key> - generation counters (RedisGenStore)
CAS pattern:
obs, err := cache.TrySnapshotGen(ctx, k) // before DB read
v := readFromDB(k)
if err == nil {
_ = cache.SetWithGen(ctx, k, v, obs, 0) // write iff current gen == obs
}
Index ¶
- Variables
- type BulkRejectReason
- type BulkSeedMode
- type CAS
- type Cache
- type Hooks
- type InvalidateError
- type MissingObservedGensError
- type NopHooks
- func (NopHooks) BulkRejected(string, int, BulkRejectReason)
- func (NopHooks) GenBumpError(genstore.CacheKey, error)
- func (NopHooks) GenSnapshotError(int, error)
- func (NopHooks) InvalidateOutage(string, error, error)
- func (NopHooks) LocalGenWithBulk()
- func (NopHooks) ProviderSetRejected(string, bool)
- func (NopHooks) SelfHealSingle(string, SelfHealReason)
- type Op
- type OpError
- type Options
- type SelfHealReason
- type SetCostFunc
Constants ¶
This section is empty.
Variables ¶
var ErrBulkSeedNeedsAdder = errors.New("BulkSeedIfMissing requires Adder")
ErrBulkSeedNeedsAdder identifies an invalid configuration where BulkSeedIfMissing is requested with a provider that does not implement Adder.
var ErrMissingObservedGens = errors.New("missing observed generations")
ErrMissingObservedGens identifies a SetBulkWithGens caller error where at least one item key has no corresponding observed generation.
Functions ¶
This section is empty.
Types ¶
type BulkRejectReason ¶ added in v0.3.1
type BulkRejectReason string
BulkRejectReason classifies why a bulk entry was rejected.
const ( // at least one bulk payload could not be decoded by the codec. BulkRejectReasonValueDecode BulkRejectReason = "value_decode" // bulk entry was missing members or contained stale generations. BulkRejectReasonInvalidOrStale BulkRejectReason = "invalid_or_stale" // bulk wire envelope was invalid. BulkRejectReasonDecodeError BulkRejectReason = "decode_error" // caller omitted at least one observed generation. BulkRejectReasonMissingObservedGen BulkRejectReason = "missing_observed_gen" // current generations could not be loaded. BulkRejectReasonGenSnapshotError BulkRejectReason = "gen_snapshot_error" // one observed generation no longer matched. BulkRejectReasonGenMismatch BulkRejectReason = "gen_mismatch" )
type BulkSeedMode ¶ added in v1.1.0
type BulkSeedMode uint8
BulkSeedMode controls whether a successful bulk read validated members as individual single-key entries. The zero/default value is BulkSeedOff so bulk hits stay read-only unless the caller explicitly opts into warming singles.
const ( // BulkSeedOff returns the bulk hit "as-is" and does not write singles. BulkSeedOff BulkSeedMode = iota // BulkSeedAll seeds singles after the bulk has already passed // generation validation. No additional per-key generation lookup is done. BulkSeedAll // BulkSeedIfMissing seeds singles only when the provider supports // conditional add/set-if-absent with native backend support or // provider-level atomic coordination. Cache construction fails if the // provider does not implement Adder. BulkSeedIfMissing )
type CAS ¶
type CAS[V any] interface { Enabled() bool Close(context.Context) error // Single Get(ctx context.Context, key string) (v V, ok bool, err error) SetWithGen(ctx context.Context, key string, value V, observedGen uint64, ttl time.Duration) error Invalidate(ctx context.Context, key string) error // Bulk (order-agnostic return. Use your own ordering by keys slice) GetBulk(ctx context.Context, keys []string) (values map[string]V, missing []string, err error) SetBulkWithGens(ctx context.Context, items map[string]V, observedGens map[string]uint64, ttl time.Duration) error // Error-aware generation snapshots for CAS writes. // These return an error so the caller can decide whether to proceed. TrySnapshotGen(ctx context.Context, key string) (uint64, error) TrySnapshotGens(ctx context.Context, keys []string) (map[string]uint64, error) // Best-effort generation snapshots. // Failures are reported through Hooks and the generation falls back to zero. SnapshotGen(ctx context.Context, key string) uint64 SnapshotGens(ctx context.Context, keys []string) map[string]uint64 }
CAS is the provider-agnostic cache interface with compare-and-swap safety via per-key generations. V is the caller's value type serialization is handled by the configured Codec[V].
type Hooks ¶ added in v0.0.6
type Hooks interface {
SelfHealSingle(storageKey string, reason SelfHealReason)
BulkRejected(namespace string, requested int, reason BulkRejectReason)
ProviderSetRejected(storageKey string, isBulk bool)
GenSnapshotError(count int, err error)
GenBumpError(cacheKey genstore.CacheKey, err error)
InvalidateOutage(key string, bumpErr, delErr error)
LocalGenWithBulk()
}
Hooks are lightweight callbacks for high-signal events. Implementations MUST be cheap and non-blocking; do not perform I/O. If work may block, buffer it and drop on backpressure (best effort).
Key-bearing callbacks intentionally expose different key kinds:
- SelfHealSingle / ProviderSetRejected: provider storage keys.
- GenBumpError: canonical genstore.CacheKey identity.
func Multi ¶ added in v0.0.9
Multi returns a Hooks implementation that fans out to all provided hooks in order. Nil entries are silently skipped. Panics from any hook propagate to the caller.
Example usage:
logH := sloghook.New(slog.Default(), sloghook.Options{SelfHealEvery: 10}) metH := promhook.New(...) // some kind of metrics adapter auditH := myAuditHook{...} // audit adapter
fan-out mh := cascache.MultiHooks{logH, metH, auditH}
Either: single async queue for the whole fan-out hooks := asynchook.New(mh, 1, 1000)
Or: give each hook its own queue (isolate backpressure)
hooks := cascache.MultiHooks{
asynchook.New(logH, 1, 1000),
asynchook.New(metH, 1, 1000),
asynchook.New(auditH, 1, 1000),
}
type InvalidateError ¶ added in v0.0.5
func (*InvalidateError) Error ¶ added in v0.0.5
func (e *InvalidateError) Error() string
func (*InvalidateError) Unwrap ¶ added in v0.0.5
func (e *InvalidateError) Unwrap() []error
type MissingObservedGensError ¶ added in v0.3.1
type MissingObservedGensError struct {
Missing []string
}
MissingObservedGensError reports which logical keys were missing observed generations.
func (*MissingObservedGensError) Error ¶ added in v0.3.1
func (e *MissingObservedGensError) Error() string
func (*MissingObservedGensError) Unwrap ¶ added in v0.3.2
func (e *MissingObservedGensError) Unwrap() error
type NopHooks ¶ added in v0.0.6
type NopHooks struct{}
NopHooks is a default no-op.
func (NopHooks) BulkRejected ¶ added in v0.0.6
func (NopHooks) BulkRejected(string, int, BulkRejectReason)
func (NopHooks) GenBumpError ¶ added in v0.0.6
func (NopHooks) GenSnapshotError ¶ added in v0.0.6
func (NopHooks) InvalidateOutage ¶ added in v0.0.6
func (NopHooks) LocalGenWithBulk ¶ added in v0.0.6
func (NopHooks) LocalGenWithBulk()
func (NopHooks) ProviderSetRejected ¶ added in v0.0.6
func (NopHooks) SelfHealSingle ¶ added in v0.0.6
func (NopHooks) SelfHealSingle(string, SelfHealReason)
type OpError ¶ added in v1.2.0
type OpError struct {
Op Op
Key string // empty for non-key specific failures such as bulk path failures
// Err is the underlying cause.
// Error panics if Err is nil.
Err error
}
OpError reports an operation failure and, when applicable, the logical key that triggered it.
type Options ¶
type Options[V any] struct { Namespace string // logical namespace to isolate the keyspace Provider pr.Provider Codec c.Codec[V] DefaultTTL time.Duration // singles; 0 => 10m BulkTTL time.Duration // bulks; 0 => 10m CleanupInterval time.Duration // 0 => 1h GenRetention time.Duration // 0 => 30d Disabled bool // default false (enabled) ComputeSetCost SetCostFunc // default 1 GenStore gen.GenStore // nil => LocalGenStore (in-process) DisableBulk bool // default false => bulk enabled // BulkSeed controls single-entry warming after successful GetBulk hits // only. It does not affect SetBulkWithGens, which still seeds singles after // a successful bulk write. BulkSeedIfMissing requires a provider with // native or provider-level atomic add-if-missing support. BulkSeed BulkSeedMode Hooks Hooks }
Options configures the CAS cache. Namespace, Provider, and Codec are required.
type SelfHealReason ¶ added in v0.3.1
type SelfHealReason string
SelfHealReason classifies why a single entry was deleted on read.
const ( // single-entry wire envelope was invalid. SelfHealReasonCorrupt SelfHealReason = "corrupt" // stored generation no longer matched the current generation. SelfHealReasonGenMismatch SelfHealReason = "gen_mismatch" // payload could not be decoded by the configured codec. SelfHealReasonValueDecode SelfHealReason = "value_decode" )
Directories
¶
| Path | Synopsis |
|---|---|
|
hooks
|
|
|
async
usage:
|
usage: |
|
slog
Package sloghook provides a slog-based implementation of cascache.Hooks.
|
Package sloghook provides a slog-based implementation of cascache.Hooks. |
|
internal
|
|
|
wire
Package wire contains the compact, versioned on-the-wire format used by cascache to store values in the underlying Provider.
|
Package wire contains the compact, versioned on-the-wire format used by cascache to store values in the underlying Provider. |
|
Package provider defines the storage abstraction used by cascache.
|
Package provider defines the storage abstraction used by cascache. |