Celld Local Cache Mechanism for Hibernated Cells: How On-Disk Snapshots Enable Fast Rehydration
Celld stores hibernated cell state as .hibernated snapshot files on local disk, allowing cells to rehydrate without re-executing their constructors.
The local cache mechanism for hibernated cells in Celld (denoland/celld) minimizes cold-start latency by persisting a cell's SQLite database state to disk when its only remaining live resources are hibernatable WebSocket streams. This design lets the runtime restore cells instantly rather than rebuilding them from scratch.
How Hibernation Triggers Cache Creation
A cell enters the hibernated state when Core::is_hibernated determines that all active resources can be safely suspended. In crates/logic/lib.rs, this check examines whether remaining WebSocket streams are marked hibernatable:
// crates/logic/lib.rs – pub fn is_hibernated(&self, id: &str) -> bool
pub fn is_hibernated(&self, id: &str) -> bool {
// Returns true when only hibernatable resources remain,
// signaling the cell can be cached rather than destroyed
}
When is_hibernated returns true, the cell transitions to hibernated status while its SQLite record persists on disk.
The .hibernated Snapshot File Format
The state store—the cell's SQLite database—contains all durable data. Upon hibernation, Celld writes a snapshot cache file with the .hibernated extension.
In crates/celld/ltx_repl.rs (lines 406-416), the runtime:
- Copies the SQLite database file
- Flushes and includes any pending WAL (Write-Ahead Log) data
- Packages this into the atomic
.hibernatedsnapshot
This ensures the snapshot represents a consistent, recoverable state.
Cache Lookup and Cell Rehydration
When a new event arrives for a hibernated cell, the dispatch logic in crates/celld/main.rs (lines 2770-3305) performs a local cache lookup:
- Check for existing
.hibernatedfile - Validate snapshot integrity
- Rehydrate directly from cache if valid
- Fall back to fresh construction if validation fails
// Simplified representation of the dispatch decision flow
fn dispatch_event(cell_id: &str, event: Event) {
if core.is_hibernated(cell_id) {
// Attempt cache-based restore
if let Some(snapshot) = load_hibernated_snapshot(cell_id) {
restore_from_snapshot(cell_id, snapshot);
return;
}
}
// Fresh start path
spawn_new_isolate(cell_id, event);
}
Cache Eviction and Size Management
The local cache mechanism is not permanent. The logic::cache module enforces size-based eviction policies to prevent disk exhaustion:
// Rust: manual cache eviction (normally triggered internally)
core.evict_cache_until_size(50 * 1024 * 1024); // enforce 50 MiB limit
In crates/logic/cache.rs (lines 11-30), the eviction algorithm prunes oldest snapshots first when cache size exceeds configured thresholds.
Safety Checks and Invalidation
Before using a cached snapshot, Celld validates consistency with current replication state. The invalidate_pos_cache logic in crates/ltx/src/db.rs (lines 495-511) verifies:
- Snapshot matches current replication position
- No unsafe writes occurred since hibernation
- Database checksums align with expected values
If validation fails, the cache is discarded and the cell rebuilds from scratch—a slower but safe fallback.
JavaScript API for Hibernatable Detection
Cell authors can check hibernatability status via the celld:js/websocket module:
// JavaScript: check if a cell can hibernate (indicating cache may exist)
import { ws_hibernatable } from "celld:js/websocket";
const cellId = 42;
const canHibernate = ws_hibernatable(cellId).unwrapOr(false);
console.log(`Cell ${cellId} hibernatable?`, canHibernate);
This API surfaces the same hibernatability check used internally by the runtime to trigger .hibernated snapshot creation.
Key Source Files
| File | Responsibility |
|---|---|
crates/logic/lib.rs |
Core hibernation detection (is_hibernated) |
crates/celld/ltx_repl.rs |
.hibernated snapshot read/write operations |
crates/celld/main.rs |
Event dispatch and cache-vs-fresh restore decisions |
crates/logic/cache.rs |
Size-based eviction for snapshot cache |
crates/ltx/src/db.rs |
Position validation and cache invalidation |
crates/celld/js/websocket.rs |
JavaScript hibernatable WebSocket API |
Summary
- Hibernation trigger:
Core::is_hibernatedincrates/logic/lib.rsidentifies when cells can suspend - Cache format:
.hibernatedfiles containing SQLite state plus WAL data - Fast restore:
crates/celld/main.rsdispatch logic rehydrates from cache when valid - Resource limits:
logic::cacheenforces automatic eviction by total size - Safety:
ltx/src/db.rsvalidates snapshots against replication state before use
Frequently Asked Questions
What distinguishes a hibernated cell from a destroyed cell?
A destroyed cell has no persisted state and must re-execute its constructor on next access. A hibernated cell maintains its .hibernated snapshot on local disk, enabling sub-second reactivation without constructor re-execution. The key difference is the presence of a valid cache file that passed all safety checks.
How does Celld prevent cache corruption from replication lag?
Before rehydration, invalidate_pos_cache in crates/ltx/src/db.rs compares the snapshot's replication position against the current cluster state. If the cell processed transactions that the snapshot doesn't include, or vice versa, the cache is invalidated and the cell rebuilds from durable SQLite storage instead.
Can I configure the local cache size limit?
The eviction threshold is controlled through core.evict_cache_until_size(), typically invoked internally by the runtime based on node configuration. Direct manipulation requires Rust-level access to the Core struct; there is presently no JavaScript API for cache sizing.
What happens to WebSocket connections during hibernation?
Hibernatable WebSocket connections, configured via ws_hibernatable() in crates/celld/js/websocket.rs, are the prerequisite for hibernation itself. These connections enter a suspended state tracked separately; when the cell rehydrates, Celld attempts to resume them transparently if the underlying transport remains valid.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →