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 .hibernated snapshot

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:

  1. Check for existing .hibernated file
  2. Validate snapshot integrity
  3. Rehydrate directly from cache if valid
  4. 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_hibernated in crates/logic/lib.rs identifies when cells can suspend
  • Cache format: .hibernated files containing SQLite state plus WAL data
  • Fast restore: crates/celld/main.rs dispatch logic rehydrates from cache when valid
  • Resource limits: logic::cache enforces automatic eviction by total size
  • Safety: ltx/src/db.rs validates 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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →