Documentation
¶
Overview ¶
Package cache implements the Stage 1 exact cache for the BubbleFish Nexus 6-stage retrieval cascade. It provides a zero-dependency generic LRU bounded by total byte capacity, scope-isolated cache entries, monotonic watermark invalidation, and Prometheus hit/miss counters.
Reference: Tech Spec Section 3.4 — Stage 1.
Index ¶
- Constants
- func BuildKey(sourceScope, dest, profile, namespace, subject, q string, limit, offset int, ...) [32]byte
- func SemanticScopeKey(sourceName, dest, profile, namespace string) [32]byte
- type CacheEntry
- type ExactCache
- type LRU
- type SemanticCache
- func (sc *SemanticCache) Get(scope [32]byte, queryVec []float32, dest string, threshold float64) (SemanticCacheEntry, bool)
- func (sc *SemanticCache) InvalidateDest(dest string)
- func (sc *SemanticCache) Len() int
- func (sc *SemanticCache) Put(scope [32]byte, queryVec []float32, dest string, entry SemanticCacheEntry)
- type SemanticCacheEntry
- type SemanticStats
- type Stats
- type WatermarkStore
Constants ¶
const ( // DefaultMaxBytes is the default maximum byte capacity for the exact cache // (50 MiB). Configurable via daemon.toml in later phases. DefaultMaxBytes = 50 * 1024 * 1024 )
const DefaultSemanticMaxEntries = 1000
DefaultSemanticMaxEntries is the default maximum number of entries in the semantic cache. Configurable via daemon.toml in later phases.
Variables ¶
This section is empty.
Functions ¶
func BuildKey ¶
func BuildKey(sourceScope, dest, profile, namespace, subject, q string, limit, offset int, policyHash string) [32]byte
BuildKey derives the 32-byte cache key for a query.
Key = SHA256(sourceScope | dest | profile | namespace | subject | q | limit | offset | policyHash)
sourceScope is the source's unique identity (typically source.Name). Including it in the key enforces scope isolation: source A and source B derive different keys for identical query parameters.
policyHash is a caller-provided digest of the policy fields that affect result shape (max_results, field_visibility, etc.). A policy change produces a different key, preventing stale policy-shaped results from being served.
Reference: Tech Spec Section 3.4 — Stage 1 (cache key derivation).
func SemanticScopeKey ¶
SemanticScopeKey derives the scope hash for semantic cache entries.
Key = SHA256(sourceName | "\x00" | dest | "\x00" | profile | "\x00" | namespace)
Including the source name enforces scope isolation: source A and source B derive different scope keys even for identical query parameters.
Types ¶
type CacheEntry ¶
type CacheEntry struct {
Records []destination.TranslatedPayload
NextCursor string
HasMore bool
// Watermark is the destination's monotonic write counter at Put time.
// A value of 0 is valid for destinations that have never been written to.
Watermark uint64
}
CacheEntry is the value stored in the exact cache for a single query result. Watermark records the destination's write watermark at insertion time; an entry is stale when the destination's current watermark exceeds this value.
type ExactCache ¶
type ExactCache struct {
// contains filtered or unexported fields
}
ExactCache is the Stage 1 exact cache. It provides:
- Scope isolation: cache keys encode the source identity so source A cannot retrieve source B's cached results even for identical queries.
- Watermark invalidation: entries become stale when the destination watermark advances (i.e., a new write was delivered).
- LRU eviction: bounded by maxBytes; oldest entries evicted when full.
- Prometheus counters: hit and miss events are reported via Stats.
All methods are safe for concurrent use by multiple goroutines.
Reference: Tech Spec Section 3.4 — Stage 1.
func NewExactCache ¶
func NewExactCache(maxBytes int64, stats *Stats) *ExactCache
NewExactCache creates an ExactCache with the given byte capacity and Prometheus registry. Pass DefaultMaxBytes for the 50 MiB default. stats may be nil (counters are skipped) — useful in tests that don't set up a Prometheus registry.
func (*ExactCache) BytesUsed ¶
func (c *ExactCache) BytesUsed() int64
BytesUsed returns the total estimated byte footprint of cached entries.
func (*ExactCache) Evictions ¶
func (c *ExactCache) Evictions() int64
Evictions returns the total number of LRU evictions since creation.
func (*ExactCache) Get ¶
func (c *ExactCache) Get(key [32]byte, dest string) (CacheEntry, bool)
Get retrieves a cached result for key. It returns the entry and true on a hit, or a zero CacheEntry and false on:
- key not present (miss)
- entry watermark < current dest watermark (stale miss)
On a miss the miss counter is incremented. On a hit the hit counter is incremented and the entry is promoted to most-recently-used.
Reference: Tech Spec Section 3.4 — Stage 1 (watermark freshness check, semantic short-circuit).
func (*ExactCache) InvalidateDest ¶
func (c *ExactCache) InvalidateDest(dest string)
InvalidateDest advances the watermark for dest, instantly staling all existing cache entries for that destination. Called by the write path after a payload is successfully delivered.
Reference: Tech Spec Section 3.4 (watermark freshness check), Section 3.7.
func (*ExactCache) Len ¶
func (c *ExactCache) Len() int
Len returns the number of entries currently in the LRU.
func (*ExactCache) Put ¶
func (c *ExactCache) Put(key [32]byte, dest string, entry CacheEntry)
Put stores a cache entry for key. The entry's Watermark is set to the current watermark for dest so that future writes invalidate it automatically. Size is estimated from the entry's record fields to enforce the byte cap.
type LRU ¶
type LRU[K comparable, V any] struct { // contains filtered or unexported fields }
LRU is a generic, thread-safe least-recently-used cache bounded by total byte capacity. Keys must be comparable. Values can be any type.
All exported methods are safe for concurrent use by multiple goroutines. There are no package-level variables — all state lives in struct fields.
Implementation: doubly-linked list (container/list) + map[K]*list.Element. Add is O(1) amortised. Get is O(1). Eviction is O(1) per evicted entry.
Reference: Tech Spec Section 3.4 (zero-dep LRU, Go generics). CRITICAL: Do NOT replace with hashicorp/golang-lru (MPL 2.0 licence).
func NewLRU ¶
func NewLRU[K comparable, V any](maxBytes int64) *LRU[K, V]
NewLRU creates an LRU bounded to maxBytes of total capacity. maxBytes must be positive; callers that pass ≤0 will get an always-evicting cache.
func (*LRU[K, V]) Add ¶
Add inserts or updates key with value. bytes is the caller's estimate of the entry's memory footprint; it must be ≥1. If the cache is full after the insert the least-recently-used entries are evicted until capacity is satisfied. Updating an existing key moves it to the front (most recent).
func (*LRU[K, V]) Get ¶
Get retrieves the value for key and promotes it to most-recently-used. Returns the zero value of V and false when the key is absent.
type SemanticCache ¶
type SemanticCache struct {
// contains filtered or unexported fields
}
SemanticCache is the Stage 2 semantic cache. It stores recent query results keyed by embedding vector. A new query hits the cache when its embedding is within cosine-similarity threshold of a stored query vector.
Scope isolation: entries carry a scope hash derived from source + dest + profile + namespace. Source A cannot retrieve source B's cached results even for identical query text.
Watermark invalidation: entries become stale when a write is delivered to the destination, matching the ExactCache invalidation strategy.
Eviction: bounded by maxEntries using FIFO eviction (oldest entry removed when the cache is full).
All methods are safe for concurrent use by multiple goroutines.
Reference: Tech Spec Section 3.4 — Stage 2.
func NewSemanticCache ¶
func NewSemanticCache(maxEntries int, stats *SemanticStats) *SemanticCache
NewSemanticCache creates a SemanticCache with the given maximum entry count. stats may be nil — counters are silently skipped. This is safe for tests that do not set up a Prometheus registry.
func (*SemanticCache) Get ¶
func (sc *SemanticCache) Get(scope [32]byte, queryVec []float32, dest string, threshold float64) (SemanticCacheEntry, bool)
Get performs a semantic cache lookup.
It scans entries in reverse insertion order (newest first) for entries with a matching scope that are fresh (watermark check) and within cosine-similarity threshold of queryVec. The first matching entry is returned.
Returns the cached entry and true on a hit. Returns a zero-value and false on a miss (no matching entry, stale entry, or no entry within threshold).
Hit increments the hit counter; miss (including after scanning all entries without a match) increments the miss counter.
Reference: Tech Spec Section 3.4 — Stage 2.
func (*SemanticCache) InvalidateDest ¶
func (sc *SemanticCache) InvalidateDest(dest string)
InvalidateDest advances the watermark for dest, instantly staling all existing semantic cache entries for that destination. Called by the write path after a payload is delivered.
Reference: Tech Spec Section 3.4 (watermark freshness check).
func (*SemanticCache) Len ¶
func (sc *SemanticCache) Len() int
Len returns the number of entries currently in the cache.
func (*SemanticCache) Put ¶
func (sc *SemanticCache) Put(scope [32]byte, queryVec []float32, dest string, entry SemanticCacheEntry)
Put stores a semantic cache entry. The watermark is snapshotted at Put time; a subsequent write to the destination will make this entry stale.
When the cache is at capacity, the oldest entry is evicted (FIFO).
type SemanticCacheEntry ¶
type SemanticCacheEntry struct {
Records []destination.TranslatedPayload
NextCursor string
HasMore bool
}
SemanticCacheEntry is the value returned on a Stage 2 cache hit.
type SemanticStats ¶
type SemanticStats struct {
// contains filtered or unexported fields
}
SemanticStats holds Prometheus counters for Stage 2 semantic-cache events. Register via NewSemanticStats on the daemon's private registry.
Metric names:
- bubblefish_cache_semantic_hits_total
- bubblefish_cache_semantic_misses_total
Reference: Tech Spec Section 11.3.
func NewSemanticStats ¶
func NewSemanticStats(reg prometheus.Registerer) *SemanticStats
NewSemanticStats creates and registers the two semantic-cache counters on reg. Panics only on programming errors (duplicate names, impossible with a fresh private registry).
func (*SemanticStats) Hit ¶
func (s *SemanticStats) Hit()
Hit increments the semantic cache hit counter. Safe to call on a nil receiver.
func (*SemanticStats) HitCount ¶
func (s *SemanticStats) HitCount() int64
HitCount returns the total number of semantic cache hits since startup. Safe to call on a nil receiver (returns 0).
func (*SemanticStats) Miss ¶
func (s *SemanticStats) Miss()
Miss increments the semantic cache miss counter. Safe to call on a nil receiver.
func (*SemanticStats) MissCount ¶
func (s *SemanticStats) MissCount() int64
MissCount returns the total number of semantic cache misses since startup. Safe to call on a nil receiver (returns 0).
type Stats ¶
type Stats struct {
// contains filtered or unexported fields
}
Stats holds the Prometheus counters for exact-cache hit and miss events. Register counters on the daemon's private registry by passing it to NewStats.
Metric names:
- bubblefish_cache_exact_hits_total
- bubblefish_cache_exact_misses_total
Reference: Tech Spec Section 11.3.
func NewStats ¶
func NewStats(reg prometheus.Registerer) *Stats
NewStats creates and registers the two exact-cache counters on reg. Panics only if reg already contains counters with the same names, which is a programming error that cannot occur with the daemon's private registry.
type WatermarkStore ¶
type WatermarkStore struct {
// contains filtered or unexported fields
}
WatermarkStore maintains a monotonically increasing counter per destination. Cache entries store the watermark at insertion time; an entry is stale when its stored watermark is less than the current destination watermark.
Watermarks are advanced by the write path each time a payload is delivered to a destination. This invalidates all exact-cache entries for that destination without requiring an explicit cache scan.
Reference: Tech Spec Section 3.4 — Stage 1 (watermark freshness check).
func NewWatermarkStore ¶
func NewWatermarkStore() *WatermarkStore
NewWatermarkStore creates an empty WatermarkStore. All destinations start at watermark 0; the first Advance call moves them to 1.
func (*WatermarkStore) Advance ¶
func (w *WatermarkStore) Advance(dest string) uint64
Advance increments the watermark for dest and returns the new value. After Advance returns, any cache entry that recorded the previous watermark is considered stale and will be rejected by ExactCache.Get.
func (*WatermarkStore) Current ¶
func (w *WatermarkStore) Current(dest string) uint64
Current returns the current watermark for dest. Returns 0 for unknown destinations (no writes have been delivered yet).