store

package
v0.7.0 Latest Latest
Warning

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

Go to latest
Published: Oct 20, 2026 License: Apache-2.0 Imports: 26 Imported by: 0

README

pkg/k8s/store

Two concrete implementations of types.Store: MemoryStore (holds full resources in memory) and CachedStore (holds index references and fetches on demand). Both are thread-safe and support composite-key indexing with prefix-scan lookups.

For the user-facing framing (when to pick which, template-side List/Fetch/GetSingle semantics) see docs/site/docs/watching-resources.md. This README covers the Go API.

Interface

Both stores satisfy pkg/k8s/types.Store:

type Store interface {
    Get(keys ...string) ([]any, error)    // exact match, or prefix scan if len(keys) < numKeys
    List() ([]any, error)                 // everything in the store
    Add(resource any, keys []string) error
    Update(resource any, keys []string) error
    Delete(namespace, name string, keys []string) error
    Clear() error
}

The number of keys is fixed at construction time — it comes from the indexBy JSONPath list. Passing fewer keys to Get does a prefix scan that returns every resource whose ordered index components start with those values (useful for one-to-many relationships like "all EndpointSlices for service X"). Components use the shared length-prefixed encoding from pkg/k8s/indexer, so separators in values can't collide or create false prefixes.

MemoryStore

import "github.com/haproxy-haptic/HAPTIC/pkg/k8s/store"

mem := store.NewMemoryStore(2)          // 2-key composite index (e.g. namespace + name)
mem.Add(ingress, []string{"default", "my-ingress"})
ingresses, _ := mem.Get("default", "my-ingress") // single match
inNs, _      := mem.Get("default")               // prefix scan (all in namespace)
all, _       := mem.List()

Implementation highlights (see pkg/k8s/store/memory.go):

  • Backing data is map[string][]any keyed by the opaque encoded index components. Multiple resources can share a key; Get returns them all.
  • A reverse map from (namespace, name) to the encoded key makes Add, Update, and Delete identity-owned. An update moves that identity between buckets under one write lock.
  • Get with the full key count finds its pre-sorted bucket in O(1), then detaches its resources. Partial-prefix reads aggregate and sort matching buckets before detaching them.
  • List aggregates, sorts, and detaches all resources on every call.
  • An RWMutex protects the data map; concurrent readers don't contend.

CachedStore

cached, _ := store.NewCachedStore(&store.CachedStoreConfig{
    NumKeys:  2,
    CacheTTL: 2*time.Minute + 10*time.Second,
    Client:   dynamicClient,
    GVR:      schema.GroupVersionResource{Group: "", Version: "v1", Resource: "secrets"},
    Indexer:  indexer,          // used by the watcher to extract keys on Add
    Logger:   logger,
})
  • Stores only resourceRef tuples (index keys + namespace/name) in memory, plus the same identity-to-bucket reverse map as MemoryStore.
  • Get cache hits return immediately; cache misses call the dynamic client, cache the result with CacheTTL, and return it.
  • The cache is keyed by the encoded (namespace, name) pair, separate from the index key — multiple references can share the same index key while each has its own cache entry.
  • Each informer mutation advances a local generation for that identity. Cache-hit TTL renewal and cache-miss commit require the captured generation, so a concurrent Update or Delete can't restore invalidated data.
  • List forces a fetch for every reference. Use it only for small collections or debugging; prefer MemoryStore for templates that iterate everything.
  • The implementation releases the store lock before dispatching API calls so one slow fetch doesn't block other lookups.
  • A stale reference whose API object returns NotFound is skipped. Every other API error aborts the read; callers never receive a partial result set.
  • Projected mode (set by the watcher for every on-demand kind): the informer feeding the store delivers body-stripped objects (only indexBy / field-selector / identity fields survive — see ADR-0012). In this mode Add/Update do not cache the stripped body; the value cache is populated solely by the live API GET (full body), and Update/Delete invalidate any stale entry. This shrinks the informer's resident memory without ever serving a husk to a render read.

In the controller the TTL is auto-derived from dataplane.driftPreventionInterval × 2.2 (see pkg/controller/resourcewatcher/watcher.go) — it's not a user-configurable CRD field. That derivation means a cached entry stays warm for slightly longer than the drift prevention window, so it's already there when the next reconciliation fires.

Error Shape

StoreError wraps every failure with the operation name and the keys involved:

var sErr *store.StoreError
if errors.As(err, &sErr) {
    log.Error("store op failed",
        "op", sErr.Operation,
        "keys", sErr.Keys,
        "cause", sErr.Cause)
}

Common .Cause values: errors.New("at least one key required"), key-count mismatch (passed N keys when the store was built for M), fetcher errors (CachedStore only).

Immutability Contract

Public reads return detached resource graphs. Mutating a returned map or slice doesn't change the store or a pinned snapshot. Ordinary MemoryStore.Add and Update inputs are detached too.

Memory-backed watchers construct an ImmutableResource after field filtering and numeric normalization. Its constructor detaches and validates the resource; its API exposes only identity, detached metadata, and configured index/selector queries. The informer, MemoryStore, and pinned snapshots share its private graph. Templates continue to receive complete resource bodies through the existing detached reads and authenticated projections.

Non-Unique Keys

Indexing by labels (e.g. metadata.labels.kubernetes\\.io/service-name for EndpointSlices) is expected to collide — many slices share a service. Get returns every distinct resource in the bucket. Resource identity is namespace + name only, via extractNamespaceName; UID is not consulted. Add and Update replace an existing identity and atomically move it when its index changes. Delete removes only that identity and drops the bucket once its last member leaves, so siblings remain intact and a delete/recreate can't retain an old index entry.

Testing

go test ./pkg/k8s/store/...          # unit tests
go test ./pkg/k8s/store/... -race    # race detector

Tests exercise both stores against the same types.Store interface contract — adding a new implementation means satisfying the same test table.

See Also

  • pkg/k8s/types — Store interface definition
  • pkg/k8s/watcher — Watcher builds these stores from a SharedInformerFactory
  • pkg/k8s/indexer — JSONPath extraction that produces the composite keys
  • pkg/stores/overlay.go — overlay wrapper used by the webhook dry-run path
  • pkg/k8s/store/CLAUDE.md — developer context (adding storage strategies, cache tuning, thread-safety proofs)

License

Apache-2.0 — see root LICENSE.

Documentation

Overview

Package store provides storage implementations for indexed Kubernetes resources.

This package offers two store types: - Memory store: Fast in-memory storage with complete resources - Cached store: Memory-efficient storage with API-backed retrieval and caching

Index

Constants

View Source
const DefaultMaxCacheSize = 256

DefaultMaxCacheSize is the default maximum number of entries in the LRU cache.

Variables

This section is empty.

Functions

This section is empty.

Types

type BranchChange

type BranchChange struct {
	// contains filtered or unexported fields
}

BranchChange identifies an exact replacement or deletion captured from a snapshot.

func (BranchChange) Deleted

func (c BranchChange) Deleted() bool

Deleted reports whether the observed resource no longer exists.

func (BranchChange) Name

func (c BranchChange) Name() string

Name returns the resource name.

func (BranchChange) Namespace

func (c BranchChange) Namespace() string

Namespace returns the resource namespace.

func (BranchChange) Revision

func (c BranchChange) Revision() stores.Revision

Revision identifies the captured observed revision; deletion has no value revision.

type CachedStore

type CachedStore struct {
	// contains filtered or unexported fields
}

CachedStore stores only resource references in memory and fetches resources from the Kubernetes API on access. Fetched resources are cached with a TTL.

This reduces memory usage for large resources (e.g., Secrets) at the cost of API latency on cache misses.

Supports non-unique index keys by storing multiple resource references per composite key.

Thread-safe for concurrent access.

func NewCachedStore

func NewCachedStore(cfg *CachedStoreConfig) (*CachedStore, error)

NewCachedStore creates a new API-backed store with caching.

func (*CachedStore) AcquireSnapshotCommitFence

func (s *CachedStore) AcquireSnapshotCommitFence(ctx context.Context) (func(), error)

func (*CachedStore) Add

func (s *CachedStore) Add(resource any, keys []string) error

Add inserts a resource reference, replacing the same identity if present.

func (*CachedStore) ChangesSince

func (s *CachedStore) ChangesSince(sequence uint64) (uint64, []stores.RevisionChange, bool)

func (*CachedStore) Clear

func (s *CachedStore) Clear() error

Clear removes all resources from the store.

func (*CachedStore) Delete

func (s *CachedStore) Delete(namespace, name string, keys []string) error

Delete removes the single resource identified by namespace/name from its recorded bucket, leaving any siblings in place. The keys validate shape. Deleting a resource that is not present is a no-op.

Only the deleted resource's cache entry is evicted. Purging the whole bucket's entries would drop warm bodies still referenced elsewhere, forcing a live API GET on the next render.

func (*CachedStore) ExactRevisionJournalSource

func (s *CachedStore) ExactRevisionJournalSource() stores.RevisionSource

func (*CachedStore) Get

func (s *CachedStore) Get(keys ...string) ([]any, error)

Get retrieves all resources matching the provided index keys.

func (*CachedStore) GetContext

func (s *CachedStore) GetContext(ctx context.Context, keys ...string) ([]any, error)

GetContext retrieves matching resources and cancels in-flight API fetches with ctx.

func (*CachedStore) GetIdentity

func (s *CachedStore) GetIdentity(namespace, name string) (item any, found bool, err error)

GetIdentity returns one resource through the namespace/name location index.

func (*CachedStore) GetRevision

func (s *CachedStore) GetRevision(keys ...string) stores.Revision

func (*CachedStore) GetSnapshot

func (s *CachedStore) GetSnapshot(
	keys ...string,
) (items []any, revision stores.Revision, sequence uint64, err error)

func (*CachedStore) IdentityRevision

func (s *CachedStore) IdentityRevision(namespace, name string) stores.Revision

func (*CachedStore) IdentitySnapshot

func (s *CachedStore) IdentitySnapshot(
	namespace, name string,
) (item any, found bool, revision stores.Revision, sequence uint64, err error)

func (*CachedStore) List

func (s *CachedStore) List() ([]any, error)

List returns all resources in the store.

func (*CachedStore) ListCached

func (s *CachedStore) ListCached() ([]any, error)

ListCached returns only resources currently warm in the LRU cache — no API fetches. Used by callers that want to prime a per-render snapshot with whatever's free, without paying for the full store-wide List() fan-out. The slice may be a small subset of what's in the cluster (the LRU is `MaxCacheSize` entries; unaccessed references contribute nothing). Expired entries are skipped.

Callers that need cluster-wide iteration should still call List(), accepting the WARN and per-reference API fetch cost.

func (*CachedStore) ListContext

func (s *CachedStore) ListContext(ctx context.Context) ([]any, error)

ListContext returns all resources and cancels in-flight API fetches with ctx.

func (*CachedStore) ListRevision

func (s *CachedStore) ListRevision() stores.Revision

func (*CachedStore) ListSnapshot

func (s *CachedStore) ListSnapshot() (items []any, sequence uint64, err error)

func (*CachedStore) Pin

func (s *CachedStore) Pin() (stores.ReadSnapshot, error)

func (*CachedStore) RevisionSource

func (s *CachedStore) RevisionSource() stores.RevisionSource

func (*CachedStore) Size

func (s *CachedStore) Size() int

Size returns the number of tracked resources in the store.

func (*CachedStore) Update

func (s *CachedStore) Update(resource any, keys []string) error

Update modifies a resource reference and moves it if its index key changed.

type CachedStoreConfig

type CachedStoreConfig struct {
	// NumKeys is the number of index keys (must match indexer configuration)
	NumKeys int

	// CacheTTL is the cache entry time-to-live
	CacheTTL time.Duration

	// MaxCacheSize is the maximum number of entries in the LRU cache.
	// When exceeded, the least recently used entry is evicted.
	// Default: 256
	MaxCacheSize int

	// Client is the Kubernetes dynamic client for fetching resources
	Client dynamic.Interface

	// GVR identifies the resource type to fetch
	GVR schema.GroupVersionResource

	// Indexer processes fetched resources (field filtering)
	Indexer *indexer.Indexer

	// Logger for debug and warning messages (optional, uses slog.Default if nil)
	Logger *slog.Logger

	// Projected indicates the informer feeding this store delivers
	// body-stripped (projected) objects — only identity, indexBy, and
	// fieldSelector fields survive (see pkg/k8s/watcher projection, ADR-0012).
	//
	// In projected mode the store must NOT cache the projected body on
	// Add/Update (a warm render read would otherwise be served a husk).
	// Instead the value cache is populated only by the live API GET in
	// fetchResourceByRef (full body), and Update/Delete invalidate any stale
	// cached body so the next read re-fetches. Off by default; on only for
	// `store: on-demand` (CachedStore) watchers.
	Projected bool
}

CachedStoreConfig configures a CachedStore.

type ImmutableResource

type ImmutableResource struct {
	// contains filtered or unexported fields
}

ImmutableResource owns a resource graph shared by informer and store snapshots.

func NewImmutableResource

func NewImmutableResource(resource map[string]any) (*ImmutableResource, error)

NewImmutableResource detaches the caller's graph before allowing shared ownership.

func (*ImmutableResource) ExtractKeys

func (r *ImmutableResource) ExtractKeys(idx *indexer.Indexer) ([]string, error)

ExtractKeys evaluates configured index expressions without exposing the graph.

func (*ImmutableResource) GetName

func (r *ImmutableResource) GetName() string

GetName returns the resource's name.

func (*ImmutableResource) GetNamespace

func (r *ImmutableResource) GetNamespace() string

GetNamespace returns the resource's namespace.

func (*ImmutableResource) GetObjectMeta

func (r *ImmutableResource) GetObjectMeta() metav1.Object

GetObjectMeta gives client-go detached metadata for indexing and version checks.

func (*ImmutableResource) GetResourceVersion

func (r *ImmutableResource) GetResourceVersion() string

GetResourceVersion returns the resource's watch version.

func (*ImmutableResource) Matches

func (r *ImmutableResource) Matches(matcher *indexer.FieldSelectorMatcher) (bool, error)

Matches evaluates a configured field selector without exposing the graph.

func (*ImmutableResource) ShareUnchanged

func (r *ImmutableResource) ShareUnchanged(previous *ImmutableResource) *ImmutableResource

ShareUnchanged reuses the previous value or its body, preserving this watch version.

type ImmutableSnapshotProjection

type ImmutableSnapshotProjection struct {
	// contains filtered or unexported fields
}

ImmutableSnapshotProjection exposes only detached projections of a built-in snapshot read.

func ProjectImmutableSnapshotGet

func ProjectImmutableSnapshotGet(
	ctx context.Context,
	snapshot stores.ReadSnapshot,
	keys ...string,
) (*ImmutableSnapshotProjection, bool, error)

ProjectImmutableSnapshotGet prepares a built-in keyed read without exposing its owned graph.

func ProjectImmutableSnapshotList

func ProjectImmutableSnapshotList(
	ctx context.Context,
	snapshot stores.ReadSnapshot,
) (*ImmutableSnapshotProjection, bool, error)

ProjectImmutableSnapshotList prepares a built-in snapshot list without exposing its owned graph.

func (*ImmutableSnapshotProjection) Encode

func (p *ImmutableSnapshotProjection) Encode() ([]byte, error)

Encode returns the exact JSON value without exposing the owned resource graph.

func (*ImmutableSnapshotProjection) Len

Len returns the number of resources in the exact projection.

func (*ImmutableSnapshotProjection) ProjectItems

func (p *ImmutableSnapshotProjection) ProjectItems(elementType reflect.Type) ([]reflect.Value, error)

ProjectItems returns fresh typed values, or detached untyped values when elementType is nil.

type MemoryStore

type MemoryStore struct {
	// contains filtered or unexported fields
}

MemoryStore stores complete Kubernetes resources in memory using nested maps.

This provides O(1) lookup performance at the cost of higher memory usage. Resources are stored with their full specification after field filtering.

Supports non-unique index keys by storing multiple resources per composite key.

Thread-safe for concurrent access.

Resource values are owned by the store and detached before public reads.

func NewMemoryStore

func NewMemoryStore(numKeys int) *MemoryStore

NewMemoryStore creates a new memory-backed store.

Parameters:

  • numKeys: Number of index keys (must match indexer configuration)

func (*MemoryStore) AcquireSnapshotCommitFence

func (s *MemoryStore) AcquireSnapshotCommitFence(ctx context.Context) (func(), error)

func (*MemoryStore) Add

func (s *MemoryStore) Add(resource any, keys []string) error

Add inserts a resource, replacing the same namespace/name if already present. Distinct resources with the same index keys share the bucket. The slice is kept sorted by namespace/name for deterministic Get() results.

func (*MemoryStore) ChangesSince

func (s *MemoryStore) ChangesSince(sequence uint64) (uint64, []stores.RevisionChange, bool)

ChangesSince returns retained mutations after sequence.

func (*MemoryStore) Clear

func (s *MemoryStore) Clear() error

Clear removes all resources from the store.

func (*MemoryStore) Delete

func (s *MemoryStore) Delete(namespace, name string, keys []string) error

Delete removes the single resource identified by namespace/name from its recorded bucket, leaving any siblings in place. The keys validate shape. Deleting a resource that is not present is a no-op.

The bucket's map entry is removed once its last resource is deleted — leaving an empty slice behind would leak a map key per churned bucket and still be walked by the prefix scan in Get.

func (*MemoryStore) ExactRevisionJournalSource

func (s *MemoryStore) ExactRevisionJournalSource() stores.RevisionSource

func (*MemoryStore) Get

func (s *MemoryStore) Get(keys ...string) ([]any, error)

Get retrieves all resources matching the provided index keys.

Returned resources are detached from store-owned values.

func (*MemoryStore) GetIdentity

func (s *MemoryStore) GetIdentity(namespace, name string) (item any, found bool, err error)

GetIdentity returns one resource through the namespace/name location index.

func (*MemoryStore) GetRevision

func (s *MemoryStore) GetRevision(keys ...string) stores.Revision

GetRevision returns the revision for one exact or prefix Get result.

func (*MemoryStore) GetSnapshot

func (s *MemoryStore) GetSnapshot(
	keys ...string,
) (items []any, revision stores.Revision, sequence uint64, err error)

GetSnapshot binds a keyed result to its revision and journal sequence.

func (*MemoryStore) IdentityRevision

func (s *MemoryStore) IdentityRevision(namespace, name string) stores.Revision

IdentityRevision returns the revision for one namespace/name identity.

func (*MemoryStore) IdentitySnapshot

func (s *MemoryStore) IdentitySnapshot(
	namespace, name string,
) (item any, found bool, revision stores.Revision, sequence uint64, err error)

IdentitySnapshot binds an identity result to its revision and journal sequence.

func (*MemoryStore) List

func (s *MemoryStore) List() ([]any, error)

List returns all resources in the store. Returns a fresh copy of all resources to avoid race conditions.

func (*MemoryStore) ListRevision

func (s *MemoryStore) ListRevision() stores.Revision

ListRevision returns the revision for List results.

func (*MemoryStore) ListSnapshot

func (s *MemoryStore) ListSnapshot() (items []any, sequence uint64, err error)

ListSnapshot returns a detached List result and its pinned journal sequence.

func (*MemoryStore) Pin

func (s *MemoryStore) Pin() (stores.ReadSnapshot, error)

Pin returns the current immutable store root in constant time.

func (*MemoryStore) RevisionSource

func (s *MemoryStore) RevisionSource() stores.RevisionSource

RevisionSource returns the store's stable cache identity.

func (*MemoryStore) Size

func (s *MemoryStore) Size() int

Size returns the number of resources in the store.

func (*MemoryStore) Update

func (s *MemoryStore) Update(resource any, keys []string) error

Update modifies an existing resource or adds it if it doesn't exist. A changed index key moves the namespace/name identity between buckets. The slice is kept sorted by namespace/name for deterministic Get() results.

type SnapshotBranch

type SnapshotBranch struct {
	// contains filtered or unexported fields
}

SnapshotBranch is an immutable selection of resource revisions from watched snapshots.

func NewSnapshotBranch

func NewSnapshotBranch(numKeys int) *SnapshotBranch

NewSnapshotBranch creates an empty branch with an independent revision journal.

func (*SnapshotBranch) AcquireSnapshotCommitFence

func (b *SnapshotBranch) AcquireSnapshotCommitFence(ctx context.Context) (func(), error)

AcquireSnapshotCommitFence needs no lock because a branch never changes.

func (*SnapshotBranch) Add

func (b *SnapshotBranch) Add(any, []string) error

Add refuses in-place mutations.

func (*SnapshotBranch) Apply

func (b *SnapshotBranch) Apply(changes []BranchChange) *SnapshotBranch

Apply creates a branch containing exactly the supplied changes.

func (*SnapshotBranch) Changes

func (b *SnapshotBranch) Changes(ctx context.Context, snapshot stores.ReadSnapshot, indexBy []string) ([]BranchChange, error)

Changes captures replacements without fetching on-demand resource bodies.

func (*SnapshotBranch) ChangesBetween

func (b *SnapshotBranch) ChangesBetween(from, through uint64) ([]stores.RevisionChange, bool)

ChangesBetween proves ancestry without treating sibling revisions as mutations.

func (*SnapshotBranch) ChangesFrom

func (b *SnapshotBranch) ChangesFrom(ctx context.Context, previous stores.ReadSnapshot) ([]stores.RevisionChange, bool, error)

ChangesFrom compares selected roots without reading lazy resource bodies.

func (*SnapshotBranch) ChangesSince

func (b *SnapshotBranch) ChangesSince(sequence uint64) (uint64, []stores.RevisionChange, bool)

ChangesSince returns exact changes only when sequence is an ancestor of this root.

func (*SnapshotBranch) Clear

func (b *SnapshotBranch) Clear() error

Clear refuses in-place mutations.

func (*SnapshotBranch) Delete

func (b *SnapshotBranch) Delete(string, string, []string) error

Delete refuses in-place mutations.

func (*SnapshotBranch) ExactRevisionJournalSource

func (b *SnapshotBranch) ExactRevisionJournalSource() stores.RevisionSource

ExactRevisionJournalSource certifies the journal's source.

func (*SnapshotBranch) Get

func (b *SnapshotBranch) Get(keys ...string) ([]any, error)

Get returns detached resources matching the configured index keys.

func (*SnapshotBranch) GetContext

func (b *SnapshotBranch) GetContext(ctx context.Context, keys ...string) ([]any, error)

GetContext performs a cancellation-aware index lookup.

func (*SnapshotBranch) GetIdentity

func (b *SnapshotBranch) GetIdentity(namespace, name string) (item any, found bool, err error)

GetIdentity returns a detached resource by namespace/name.

func (*SnapshotBranch) GetIdentityContext

func (b *SnapshotBranch) GetIdentityContext(ctx context.Context, namespace, name string) (item any, found bool, err error)

GetIdentityContext performs a cancellation-aware identity lookup.

func (*SnapshotBranch) GetRevision

func (b *SnapshotBranch) GetRevision(keys ...string) stores.Revision

GetRevision identifies a configured index lookup.

func (*SnapshotBranch) GetSnapshot

func (b *SnapshotBranch) GetSnapshot(keys ...string) (items []any, revision stores.Revision, sequence uint64, err error)

GetSnapshot returns a detached lookup and its exact revision.

func (*SnapshotBranch) IdentityOrderSource

func (b *SnapshotBranch) IdentityOrderSource() stores.RevisionSource

IdentityOrderSource certifies namespace/name ordering.

func (*SnapshotBranch) IdentityRevision

func (b *SnapshotBranch) IdentityRevision(namespace, name string) stores.Revision

IdentityRevision identifies a namespace/name lookup, including absence.

func (*SnapshotBranch) IdentitySnapshot

func (b *SnapshotBranch) IdentitySnapshot(namespace, name string) (item any, found bool, revision stores.Revision, sequence uint64, err error)

IdentitySnapshot returns a detached identity lookup and its exact revision.

func (*SnapshotBranch) List

func (b *SnapshotBranch) List() ([]any, error)

List returns detached resources in namespace/name order.

func (*SnapshotBranch) ListContext

func (b *SnapshotBranch) ListContext(ctx context.Context) ([]any, error)

ListContext performs a cancellation-aware collection read.

func (*SnapshotBranch) ListRevision

func (b *SnapshotBranch) ListRevision() stores.Revision

ListRevision identifies this root's membership and values.

func (*SnapshotBranch) ListSnapshot

func (b *SnapshotBranch) ListSnapshot() (items []any, sequence uint64, err error)

ListSnapshot returns a detached collection and its immutable watermark.

func (*SnapshotBranch) Pin

Pin returns this immutable root.

func (*SnapshotBranch) RevisionSource

func (b *SnapshotBranch) RevisionSource() stores.RevisionSource

RevisionSource identifies this branch family.

func (*SnapshotBranch) Sequence

func (b *SnapshotBranch) Sequence() uint64

Sequence returns this root's immutable watermark.

func (*SnapshotBranch) Update

func (b *SnapshotBranch) Update(any, []string) error

Update refuses in-place mutations.

type StoreError

type StoreError struct {
	Operation string
	Keys      []string
	Cause     error
}

StoreError represents a generic store operation error.

func (*StoreError) Error

func (e *StoreError) Error() string

func (*StoreError) Unwrap

func (e *StoreError) Unwrap() error

Jump to

Keyboard shortcuts

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