Documentation
¶
Overview ¶
Package metadatacache provides a generic in-memory write-through cache backed by a metadata.Storage. Each key is protected by its own mutex so concurrent updates to different keys never contend. Persistence uses etag-based Compare-And-Swap to detect cross-replica conflicts.
Index ¶
- type Options
- type Store
- func (s *Store[K, V]) Get(ctx context.Context, key K) (V, bool, error)
- func (s *Store[K, V]) IsCached(key K) bool
- func (s *Store[K, V]) Lock(key K) func()
- func (s *Store[K, V]) Persist(ctx context.Context, key K) error
- func (s *Store[K, V]) Set(key K, v V)
- func (s *Store[K, V]) Sync(ctx context.Context, key K) error
- func (s *Store[K, V]) Update(ctx context.Context, key K, createIfNotFound bool, fn func(V) (V, bool, error)) error
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type Options ¶
type Options[K comparable, V any] struct { // Storage is the metadata backend (required). Storage metadata.Storage // Path maps a key to a storage path (required). Path func(K) string // Retries is the maximum number of attempts in Update before giving up. // Defaults to 100 when zero. Retries int // Init returns a valid zero value for V. Required when Update is called // with createIfNotFound=true (e.g. to produce an initialised map rather // than a nil map). Init func() V }
Options configures a Store.
type Store ¶
type Store[K comparable, V any] struct { // contains filtered or unexported fields }
Store is a generic in-memory write-through cache. V must be JSON-serialisable. K must be comparable (map key) and must produce a human-readable string via fmt.Sprint for log/trace attributes.
func New ¶
func New[K comparable, V any](opts Options[K, V]) *Store[K, V]
New returns a ready-to-use Store.
func (*Store[K, V]) Get ¶
Get syncs from storage and returns the current value for key. The caller must hold the per-key lock. Returns (zero, false, nil) when the key does not exist in storage.
func (*Store[K, V]) IsCached ¶
IsCached reports whether key has a cached entry without consulting storage. The caller must hold the per-key lock.
func (*Store[K, V]) Lock ¶
func (s *Store[K, V]) Lock(key K) func()
Lock acquires the per-key mutex and returns an unlock function. The caller must call the returned function exactly once (typically via defer).
func (*Store[K, V]) Persist ¶
Persist writes the cached value for key to storage using etag-based CAS. If the path's parent directory is non-trivial (not "." or "/"), MakeDirIfNotExist is called first. The caller must hold the per-key lock.
func (*Store[K, V]) Set ¶
func (s *Store[K, V]) Set(key K, v V)
Set stores value for key in the in-memory cache without persisting to storage. The etag of the existing entry (if any) is preserved. The caller must hold the per-key lock.
func (*Store[K, V]) Sync ¶
Sync downloads the current state of key from storage and updates the cache. It is a no-op (returns nil) when the key does not exist in storage or when the stored etag matches the cached etag (NotModified). The caller must hold the per-key lock.
func (*Store[K, V]) Update ¶
func (s *Store[K, V]) Update(ctx context.Context, key K, createIfNotFound bool, fn func(V) (V, bool, error)) error
Update atomically reads, transforms, and (conditionally) persists the value for key. It acquires the per-key lock internally; callers must not hold it.
fn receives the current value and returns (newValue, shouldPersist, error). When shouldPersist is false the update is skipped entirely (useful for read-modify-skip-write patterns like GetAppPassword's utime throttle). When err is non-nil the update is abandoned immediately.
createIfNotFound controls whether a missing key is initialised via Options.Init (which must be set) or returned as errtypes.NotFound.
Conflicts (Aborted, PreconditionFailed, AlreadyExists, TooEarly) are retried up to Options.Retries times, re-syncing from storage before each retry.