Documentation
¶
Overview ¶
Package kv is a thin, tenant-scoped wrapper over the configured key-value store backend that backs the op-writable key-value ops (txco://kv/*). It is the only general, mutable, op-writable persistence in the chassis — distinct from the immutable filecas/continuation/artifact stores and the secret store.
The same store.Store interface is satisfied by boltdb (embedded, on-disk) and redis (shared, networked — native TTL + atomic ops), selected by --kvstore. This wrapper adds the three things the raw store doesn't give us:
- Tenant + namespace scoping: every key is composed as <tenant>/<namespace>/<userkey>. The tenant comes from the trusted request scope (never the mutable _txc.tenant); the namespace is an organizational prefix (default = the routed stack), not a security boundary.
- JSON values: callers store/retrieve arbitrary JSON, not opaque bytes.
- Uniform TTL: values are wrapped with an optional expiry and lazy-expired on read, AND WriteOptions.TTL is passed so native backends (redis) also GC. Persistent keys (the default) carry no expiry. A configurable max-TTL clamps requested TTLs downward.
Index ¶
- Constants
- func IsReservedNamespace(ns string) bool
- func ParseTTLSeconds(secs int64) time.Duration
- type KV
- func (k *KV) CAS(ctx context.Context, tenant, ns, key string, expectAbsent bool, ...) (swapped bool, current json.RawMessage, err error)
- func (k *KV) Delete(ctx context.Context, tenant, ns, key string) error
- func (k *KV) Get(ctx context.Context, tenant, ns, key string) (value json.RawMessage, found bool, err error)
- func (k *KV) Incr(ctx context.Context, tenant, ns, key string, delta int64, ttl time.Duration) (int64, error)
- func (k *KV) ListKeys(ctx context.Context, tenant, ns string) ([]string, error)
- func (k *KV) ListKeysPage(ctx context.Context, tenant, ns, after string, limit int) (keys []string, next string, err error)
- func (k *KV) ListPairs(ctx context.Context, tenant, ns string) ([]Pair, error)
- func (k *KV) Set(ctx context.Context, tenant, ns, key string, value json.RawMessage, ...) error
- type Pair
Constants ¶
const ( DefaultListLimit = 200 MaxListLimit = 200 )
DefaultListLimit / MaxListLimit bound a single ListKeysPage response. The underlying store.List has no native cursor (it returns the whole namespace), so the window caps the RESPONSE size, not the read. Requests above the max are clamped down; a non-positive request uses the default.
const ReservedNamespacePrefix = "_txc"
ReservedNamespacePrefix marks KV namespaces the chassis owns for its own indexes (e.g. the txco://blob name index lives in "_txc.blob"). Author- facing writers — the txco://kv/* ops, KV/ seed packs — refuse them so a stack can neither read a chassis index as plain KV nor have a pack's delete-missing pass wipe it. Same reservation idiom as the `_txc.*` envelope namespace and the `_sys` tenant slug.
Variables ¶
This section is empty.
Functions ¶
func IsReservedNamespace ¶ added in v0.2.24
IsReservedNamespace reports whether ns is chassis-reserved: exactly the prefix, or the prefix followed by "." (so "_txc", "_txc.blob" are reserved while an author's "_txcfoo" is not).
func ParseTTLSeconds ¶
ParseTTLSeconds converts an integer-seconds WITH param to a Duration. Zero or negative → 0 (persistent).
Types ¶
type KV ¶
type KV struct {
// contains filtered or unexported fields
}
KV is a tenant-scoped view over the underlying key-value store.
func (*KV) CAS ¶ added in v0.2.13
func (k *KV) CAS(ctx context.Context, tenant, ns, key string, expectAbsent bool, expected, newVal json.RawMessage, ttl time.Duration) (swapped bool, current json.RawMessage, err error)
CAS is check-and-set: write newVal at (tenant, ns, key) only if the current value passes the check, using the store's atomic compare so it stays race-safe under concurrency. With expectAbsent=true it writes only if the key is absent (a create-if-missing / lock primitive); otherwise it writes only if the current value equals `expected`. Returns whether it swapped and the value now in the store (newVal if swapped, else the existing value — nil if the key was absent).
func (*KV) Get ¶
func (k *KV) Get(ctx context.Context, tenant, ns, key string) (value json.RawMessage, found bool, err error)
Get returns the JSON value for (tenant, ns, key). found is false for a missing or lazily-expired key (no error in either case).
func (*KV) Incr ¶
func (k *KV) Incr(ctx context.Context, tenant, ns, key string, delta int64, ttl time.Duration) (int64, error)
Incr atomically adds delta to an integer value (creating it at delta if absent or expired) using the store's CAS primitive, and returns the new value. A positive ttl (clamped) is (re)applied on each increment.
func (*KV) ListKeys ¶ added in v0.2.16
ListKeys returns the user keys currently stored under (tenant, ns) — the namespace view the declarative store-seed reconciler needs to find which managed keys a re-applied pack dropped. Lazily-expired keys are filtered (parity with Get); order is unspecified; an empty namespace yields nil.
func (*KV) ListKeysPage ¶ added in v0.2.19
func (k *KV) ListKeysPage(ctx context.Context, tenant, ns, after string, limit int) (keys []string, next string, err error)
ListKeysPage returns a stable, windowed page of the user keys under (tenant, ns), sorted ascending. It returns up to `limit` keys (clamped to MaxListLimit; a non-positive limit uses DefaultListLimit) that sort strictly AFTER the `after` cursor (empty = from the start), plus `next`: the cursor to pass on the following call, or "" when the namespace is exhausted.
The backing store.List has no native cursor (redis SCANs to exhaustion, boltdb walks the bucket), so this fetches all keys then sorts + slices — the window bounds the RESPONSE, not the underlying read. Fine for the modest namespaces this serves; a truly large namespace pays a full in-memory sort per page. Deterministic order makes the `after` cursor a stable resume point even as keys are added/removed between pages.
func (*KV) ListPairs ¶ added in v0.2.24
ListPairs returns every live entry under (tenant, ns) with its value — the read behind a chassis-owned index (the blob name index) that needs the rows, not just the keys. Both backends already fetch values on List, so this costs no extra round trip over ListKeys. Order is unspecified; an empty namespace yields nil.
type Pair ¶ added in v0.2.24
type Pair struct {
Key string
Value json.RawMessage
}
Pair is one live (non-expired) entry of a namespace listing: the bare user key and its JSON value.
Directories
¶
| Path | Synopsis |
|---|---|
|
Package redisstore is the chassis's redis backend for the op-writable KV (txco://kv/*), registered with valkeyrie under the same "redis" name the fleet's TXCO_KVSTORE env selects.
|
Package redisstore is the chassis's redis backend for the op-writable KV (txco://kv/*), registered with valkeyrie under the same "redis" name the fleet's TXCO_KVSTORE env selects. |