Overview

Many application views are assembled from multiple cache keys: a product page combines product details, pricing, inventory, and reviews. Traditionally, the application issues N separate GET commands and stitches the results together. Cache Fusion moves this composition into the cache layer. You declare which fragments make up a composite key, and Cachee returns the assembled result in a single GET_FUSED call.

The FusionEngine maintains a forward index (composite → fragments) and a reverse index (fragment → composites). When a fragment is updated via SET, all composites that include that fragment are marked dirty and will be recomposed on the next read.

When to Use

Use Cache Fusion when your read path assembles data from 2–10 independently-cached fragments. Common patterns: API response aggregation, dashboard panels, product detail pages, user profile views composed of preferences + permissions + history.

Data Structure

Rust struct FusionEngine { // Forward: composite key → ordered list of fragment keys composites: DashMap<String, Vec<String>>, // Reverse: fragment key → set of composite keys that use it reverse: DashMap<String, HashSet<String>>, // Dirty set: composites that need recomposition dirty: DashSet<String>, // Reference to the main cache engine for reading fragments cache: Arc<CacheEngine>, }

The reverse index is the key to efficient dirty tracking. When a SET writes to a fragment key, the engine checks the reverse index in O(1). If the fragment belongs to any composites, those composites are added to the dirty set. This avoids scanning all composites on every write.

FUSE Command

Register a composite key by declaring its fragment list. Fragment order is preserved — the composed result concatenates fragments in the declared order.

RESP # Register a composite from 4 fragments FUSE "page:product:42" "product:42:details" "product:42:price" "product:42:inventory" "product:42:reviews" # → OK (4 fragments registered) # Update the fragment ordering or add/remove fragments FUSE "page:product:42" "product:42:details" "product:42:price" "product:42:reviews" # → OK (3 fragments, inventory removed)

Re-issuing FUSE for an existing composite replaces the fragment list entirely. The reverse index is updated atomically — old fragment → composite mappings are removed, new ones are added.

Compose & GET_FUSED

The compose() function reads each fragment from the CacheEngine via standard GET, concatenates them into a JSON array (preserving fragment order), and caches the assembled result under the composite key.

RESP # Read the composed result GET_FUSED "page:product:42" # → { "fragments": [ # {"key": "product:42:details", "value": "{...}"}, # {"key": "product:42:price", "value": "29.99"}, # {"key": "product:42:reviews", "value": "[...]"} # ], "complete": true }

Dirty Tracking

When a GET_FUSED request arrives for a composite in the dirty set, the engine recomposes the value before returning. The recomposition reads fresh fragment values, rebuilds the assembled result, writes it back to the cache, and removes the composite from the dirty set. Subsequent reads of the same composite (until a fragment changes again) return the cached assembled value directly.

Partial Results

If one or more fragments are missing from the cache (expired, evicted, or never set), GET_FUSED returns a partial result with the missing_keys field listing which fragments were unavailable.

Partial Response # Fragment "product:42:inventory" was evicted GET_FUSED "page:product:42" # → { "fragments": [ # {"key": "product:42:details", "value": "{...}"}, # {"key": "product:42:price", "value": "29.99"} # ], # "missing_keys": ["product:42:inventory"], # "complete": false }
Partial vs. Error

By default, GET_FUSED returns partial results. Set fusion.require_complete true to return an error when any fragment is missing. This is useful for views where partial data is worse than no data (e.g., financial summaries).

Configuration

Parameter Default Description
fusion.enabled false Enable the Cache Fusion subsystem
fusion.max_fragments 32 Maximum number of fragments per composite key
fusion.require_complete false When true, GET_FUSED returns error if any fragment is missing
fusion.max_composites 100000 Maximum number of registered composite keys
fusion.cache_composed true Cache the assembled result under the composite key (vs. always recompose on read)

Performance

Operation Complexity Typical Latency
FUSE (register composite) O(F) where F = fragment count <2 µs
GET_FUSED (cached, clean) O(1) ~0.15 µs
GET_FUSED (dirty, recompose) O(F) reads + compose ~1–5 µs (4 fragments)
SET (fragment, dirty marking) O(C) where C = composites using fragment <0.5 µs overhead
Reverse index lookup O(1) DashMap ~0.08 µs

Compared to N separate GET calls from the application, GET_FUSED eliminates N-1 round-trips (or N-1 function calls in the in-process case). For a 4-fragment composite, this saves ~0.45 µs in-process or ~200 µs over TCP.

Memory Overhead

When fusion.cache_composed is enabled (default), the assembled result is stored as a separate cache entry. This duplicates the data — fragments exist individually AND as the composed result. Disable caching if memory is constrained and recomposition latency (~1–5µs) is acceptable.