Optionaloptions: MultiLevelCachingStoreOptionsPrivatel1Privatel2PrivateprefetcherPrivatesourcePrivatel2PrivateenabledPrivatenoPrivatedebugPrivateshouldPrivateclearPrivate Static ReadonlyDEFAULT_Private Static ReadonlyDEFAULT_PrivatevalidationPrivatedisposedPrivate ReadonlydataPrivate Readonlyl2Privatel2PrivatependingPrivateinvalidationPrivatenetworkPrivatenetworkPrivatetotalPrivatetotalPrivatel1Privatel2PrivatedemandPrivate Static ReadonlyBANDWIDTH_PrivatebandwidthRegister a callback to be invoked when caches are invalidated (e.g., clearAll, validateCache). Used by L0 DecompressedChunkCache to clear itself when L1/L2 are invalidated.
Attach a prefetcher to receive access notifications.
Get the attached prefetcher (if any).
Initialize the two-level cache and validate against remote dataset.
Performs complete cache setup including OPFS initialization and content hash validation. This MUST be called before any get() operations.
Initialization steps:
Cache validation is CRITICAL: fetches .zattrs directly from HTTP (bypassing cache) to detect dataset changes. If content_hash differs, clears L2 completely and re-initializes. This prevents stale data.
Promise that resolves when cache is fully initialized and validated. If caching is disabled (?noCache), resolves immediately without setup.
const store = new MultiLevelCachingStore(url, {
l1MaxSize: 100 * 1024 * 1024, // 100MB
l2MaxSize: 2 * 1024 * 1024 * 1024 // 2GB
});
await store.init();
console.log('Cache ready');
// Now safe to call get()
// Handle initialization errors gracefully
try {
await store.init();
} catch (error) {
console.error('Cache init failed:', error);
// Fall back to direct HTTP (no caching) by reloading with ?noCache
// (caching is controlled via URL parameters, not constructor options)
}
Get a Zarr chunk with three-level cascade: L1 memory → L2 OPFS → L3 HTTP.
Implements zarrita's AsyncReadable interface for seamless Zarr integration. This is the primary data access method called by zarrita for ALL chunk reads.
Cache cascade behavior:
On successful fetch:
Performance characteristics:
Zarr chunk key relative to store root. Examples: - Array chunk: 'positions/0.1.2' - Metadata: '.zarray', '.zmetadata', '.zattrs' - Nested: 'group1/subgroup/array/0.0'
Optionaloptions: { signal?: AbortSignal }
Zarrita read options. A supplied abort signal cancels the underlying source read for this caller.
Promise resolving to chunk data as Uint8Array, or undefined when the key does not exist (404) or the store is being disposed with its owning scene.
AbortError when a live demand read is cancelled by
its caller or cache invalidation. Rejecting is required because zarrita treats
undefined as a missing chunk and substitutes fill values.
When a source/network failure exhausts retries or the container is unreadable, so the loader can record the failure.
// Get a chunk (called by zarrita internally)
const chunk = await store.get('positions/0.1.2');
if (chunk) {
console.log(`Loaded ${chunk.byteLength} bytes`);
// Process chunk data...
} else {
console.log('Chunk not found');
}
// Load metadata (also goes through cache)
const zattrs = await store.get('.zattrs');
if (zattrs) {
const attrs = JSON.parse(new TextDecoder().decode(zattrs));
console.log('Dataset metadata:', attrs);
}
// Cache cascade demonstration
// First access: L3 fetch (~100ms)
console.time('first');
await store.get('positions/0.0.0');
console.timeEnd('first'); // ~100ms
// Second access: L1 hit (~1μs)
console.time('second');
await store.get('positions/0.0.0');
console.timeEnd('second'); // ~0.001ms
Performance: Typical access pattern: - First load: 90% L3 fetches (cold cache) - Subsequent loads: 95% L1 hits, 4% L2 hits, 1% L3 fetches - Memory usage: L1 ~100MB, L2 ~2GB (configurable)
Get a chunk and report the failure mode structurally.
Same L1 → L2 → L3 cascade as get, but distinguishes:
ok(data) — present in some tier or fetched successfully.err({ kind: 'Missing' }) — server returned 404. Caller may treat as
"not yet stored" without alarm.err({ kind: 'NetworkError', cause }) — a non-missing HTTP failure or
transient network/DNS error after retries exhausted. Caller may back off.err({ kind: 'Aborted' }) — caller signal, cache invalidation, or
store disposal aborted the read.err({ kind: 'Fatal', cause }) — the whole container is unreadable, not
just this key. MultiLevelCachingStore.get rethrows cause rather
than reporting a miss, so the failure reaches the user instead of
rendering an empty scene.Optionaloptions: { signal?: AbortSignal; suppressPrefetch?: boolean }PrivatewaitOptionalsignal: AbortSignalPrivatefetchRun the L2 → network cascade for a single key. Called at most once per key per concurrent-getter wave by getResult's pendingGets coalescer. Increments aggregate network counters once; per-caller demand counters are incremented in getResult after this resolves.
OptionalsharedSignal: AbortSignalPrivatevalidateValidate cache using content hash. Clears cache if content changed.
Validation is serialized per dataset via a static queue keyed on
datasetId, which is SHA-256(source.identity) (see hashUrl). All
MultiLevelCachingStore instances pointing at the same URL share the
same id and therefore the same queue, so rapid same-URL switches
cannot let an older validation finish after a newer one and restore
stale metadata. Each entry registers an AbortController so a
subsequent dispose() on this instance can cancel both the
in-flight HTTP fetch and any waiting follow-up validation that
captured this.
PrivatedoPrivateabortCRIT-5: cancel every in-flight coalesced get and forget them, so a fetch
that started before an invalidation cannot resurrect stale bytes by writing
back into the just-cleared L1/L2 after it resolves. Each pending entry's
controller signal is composed into fetchKeyChain, so abort() trips the
post-arrayBuffer populate guard. Shared by the content-hash-mismatch and
TTL-expiry clear paths so the two stay in lockstep.
PrivateinvalidateDrop every cache tier for an invalidation (content-hash mismatch, TTL
expiry, or a user-triggered clearAll). Ordering is load-bearing:
abortPendingGets() runs FIRST so no in-flight coalesced fetch can pass
fetchKeyChain's populate guard and repopulate a tier DURING the async
clearL2() wipe — the residual window a clear-then-abort order leaves open.
L2's epoch is bumped inside clearL2(); L0 is dropped via the invalidation
callbacks. Shared by all three invalidation paths so they stay in lockstep.
List all cached datasets in OPFS. Thin wrapper around OPFSStore.listAll — kept on the orchestrator so external callers keep importing through the package's public API.
Get cache statistics. Returns the aggregated multi-tier snapshot
(MultiLevelCacheStats) consumed by the data-loading monitor,
debug overlay, and cache E2E suite.
Check if caching is enabled. Used by CacheStatsProvider interface.
Clear L1 memory cache only.
Clear L2 OPFS cache only.
Bumps l2Epoch and drops queued background writes FIRST (synchronously),
so a write enqueued before this clear can never land after it and resurrect
stale bytes: not-yet-started tasks are dropped here, and an already-running
task self-drops on its epoch re-check (with the OPFS generation counter as
a final backstop). This is the single chokepoint for every L2-clearing path
(clearAll, content-hash mismatch, TTL expiry, ?clearCache).
Clear all caches (L1 + L2). Reachable mid-session from the monitor /
settings "clear caches" controls and __luxarDebug, so it aborts in-flight
gets FIRST (see invalidateAllTiers) to prevent stale repopulation.
Dispose the cache store. Flushes pending writes, aborts this instance's own in-flight cache-validation entry (identity-scoped — it does NOT remove the entry from the static queue; the entry leaves the map only when its validation settles and it is still the head, so a newer same-URL store's head is left intact), and clears L1.
The validation cancellation matters because two stores against the same
URL share the static queue; without it, a closure that captured this
could run setContentHash() against a disposed l2Store.
PrivatelogConditional logging based on debug mode. Errors always emit; info/warn
only when debug is on. All output is routed through the shared
log utility so it shows up consistently in the debug-console overlay.
Multi-level caching store that implements zarrita's AsyncReadable interface. Orchestrates three tiers — L0 (decompressed in-memory chunk cache, owned by the zarrita layer), L1 (memory, in-process), L2 (OPFS, cross-tab) — over a ChunkSource that supplies the bytes.