# How Celld Manages Concurrent Access to the Same Cell

> Celld ensures single-writer semantics for cells using epoch-based fencing and atomic leases. Learn how it manages concurrent access and prevents conflicts.

- Repository: [Deno/celld](https://github.com/denoland/celld)
- Tags: internals
- Published: 2026-08-09

---

**Celld guarantees single-writer semantics for each cell through epoch-based fencing and atomic per-cell leases, ensuring that only one replica can write to a given cell at any moment while rejecting concurrent attempts via conditional compare-and-swap operations.**

Celld is an open-source distributed cell storage system developed by Deno Land Inc. that provides strongly consistent access to individual cells across distributed replicas. When multiple writers attempt to access the same cell simultaneously, the system must prevent race conditions while maintaining high availability. According to the denoland/celld source code, the project achieves this through a sophisticated coordination mechanism combining logical epochs, lease tokens, and atomic storage operations.

## Epoch-Based Fencing and Per-Cell Leases

Celld employs a two-layer coordination strategy that separates the right to write (epoch fencing) from the mechanism of writing (lease tokens).

### Epoch Fencing and Writer Rights

When a replica initializes, it **seeds the cell’s position** and records an *epoch* representing a logical generation of that cell’s state. As implemented in [`crates/ltx/src/replica.rs`](https://github.com/denoland/celld/blob/main/crates/ltx/src/replica.rs) at lines 188–191, the system fences exactly one writer per epoch, ensuring that any subsequent write in the same epoch must first hold the valid lease.

The epoch mechanism provides fault tolerance for transient failures. If a write fails with a transient store error, the replica **retains the epoch** and its cached position, avoiding expensive re-listing operations. Only errors indicating state divergence—such as checksum mismatches—trigger an epoch clear, forcing the replica to re-derive its position from storage. This distinction optimizes for network hiccups while strictly enforcing consistency on data corruption.

### Per-Cell Lease Acquisition

The **leaser** module ([`crates/ltx/src/leaser.rs`](https://github.com/denoland/celld/blob/main/crates/ltx/src/leaser.rs)) manages the lifecycle of write permissions through lease tokens. Before writing, a replica must acquire a lease for the specific `cell_id` from the leaser, which tracks expiration times and ensures only one valid lease exists per cell at any time.

The lease state is stored in the backing object store, making it visible across all replicas. When a lease expires or is explicitly released, the token becomes invalid, and subsequent write attempts must acquire a fresh lease before proceeding.

## Atomic Conditional Writes for Isolation

Once a replica holds a valid lease, it must still contend with the storage layer’s consistency guarantees. Celld uses **conditional-put (CAS)** operations to ensure atomic updates.

In [`crates/celld/bucket.rs`](https://github.com/denoland/celld/blob/main/crates/celld/bucket.rs) at lines 48–53, the system performs conditional writes with **retries disabled** to prevent false rejections. The CAS operation checks an ETag or version precondition; if the cell has been modified since the lease was acquired, the write returns `Ok(None)` or an error, signaling a concurrent modification. This atomic check guarantees that even if two replicas hold leases (due to clock skew or delayed expiration), only the first successful CAS operation commits.

```rust
// Conditional writes only, built with retries OFF to avoid false-rejections
// (bucket.rs, lines 48-53)
// https://github.com/denoland/celld/blob/main/crates/celld/bucket.rs#L48-L53

```

## Connection Pooling and Write Sequencing

Beyond fencing and leases, Celld isolates traffic and orders operations to prevent subtle race conditions.

### Isolated Store Instances per Cell

Each cell receives its own dedicated connection pool to eliminate cross-cell interference. As noted in [`crates/ltx/src/client/object_store.rs`](https://github.com/denoland/celld/blob/main/crates/ltx/src/client/object_store.rs) at line 255, the system maintains **one connection pool for every cell on a node** using `OnceCell`-wrapped store instances. This isolation ensures that heavy write traffic on one cell cannot exhaust connection limits or cause latency spikes for other cells.

```rust
// "one connection pool for every cell on a node"
// (object_store.rs, line 255)
// https://github.com/denoland/celld/blob/main/crates/ltx/src/client/object_store.rs#L255

```

### Sequencing Writes After Settled Operations

Celld strictly orders destructive operations through the wake-tracking system in [`crates/logic/wake.rs`](https://github.com/denoland/celld/blob/main/crates/logic/wake.rs) (lines 236–239). Before finalizing a PUT request, the system verifies that any prior DELETE or update has fully settled using a `flushed` map that records each cell’s state (verified, deleting, etc.).

If a delete operation is in-flight, new writes block until the previous operation completes and the cell state transitions to a safe value. This **write sequencing** prevents the "lost update" problem where a new write could overwrite a deletion that hasn't propagated through the storage backend.

```rust
// PUT must be sequenced after it settles; store gives a "may have committed" result
// (wake.rs, lines 236-239)
// https://github.com/denoland/celld/blob/main/crates/logic/wake.rs#L236-L239

```

## Implementation Example: Coordinated Cell Write

The following Rust example demonstrates the complete flow of acquiring a lease and performing a conditional write:

```rust
use celld::leaser::Leaser;
use celld::bucket::Bucket;
use object_store::path::Path;
use object_store::PutOptions;

async fn write_to_cell(
    leaser: &Leaser,
    bucket: &Bucket,
    cell_id: &str,
    body: bytes::Bytes
) -> Result<(), Box<dyn std::error::Error>> {
    // Acquire a lease for a cell before writing
    let lease = leaser.acquire(cell_id).await?;
    
    // Attempt a conditional write (CAS); only succeeds if lease is still valid
    // and no other writer has modified the cell since we last read it
    let result = bucket.cas_store.put_opts(
        &Path::from(format!("cells/{cell_id}")),
        body.into(),
        PutOptions {
            // ETagMatch ensures the write only succeeds if the object hasn't changed
            ..Default::default()
        },
    ).await;

    // `result` is Ok(()) on success, Err(_) if the lease was lost or another writer beat us
    match result {
        Ok(_) => {
            log::info!("Write succeeded for cell {}", cell_id);
            Ok(())
        }
        Err(e) => {
            // Lease was likely taken by another writer – retry after re-acquiring
            log::warn!("Concurrent write detected for {}: {}", cell_id, e);
            Err(e.into())
        }
    }
}

```

The replica sync loop respects fencing by preserving epochs across transient failures:

```rust
// The replica sync loop respects fencing – it clears its cached position only
// on unrecoverable errors, preserving the epoch for idempotent re-uploads.
match replica.sync().await {
    Ok(_) => log::info!("Sync succeeded"),
    Err(e) if pos_untrustworthy(&e) => {
        // Divergent state – drop epoch and recompute position
        replica.pos = Pos::ZERO;
        replica.pos_known = false;
    }
    Err(e) => log::error!("Sync failed but epoch retained: {}", e),
}

```

## Summary

- **Epoch fencing** in [`replica.rs`](https://github.com/denoland/celld/blob/main/replica.rs) binds writer rights to logical generations, clearing cached positions only on divergent errors while retaining them during transient failures.
- **Per-cell leases** managed by [`leaser.rs`](https://github.com/denoland/celld/blob/main/leaser.rs) provide time-bounded write permissions stored in the backing object store.
- **Conditional-put operations** in [`bucket.rs`](https://github.com/denoland/celld/blob/main/bucket.rs) enforce atomic updates with retries disabled, ensuring only the lease holder can successfully write.
- **Connection pooling** in [`object_store.rs`](https://github.com/denoland/celld/blob/main/object_store.rs) isolates each cell’s network traffic to prevent cross-cell interference.
- **Write sequencing** in [`wake.rs`](https://github.com/denoland/celld/blob/main/wake.rs) blocks new operations until prior deletes settle, eliminating lost updates during state transitions.

## Frequently Asked Questions

### What happens when two replicas try to write to the same cell simultaneously?

The first replica to successfully execute a conditional-put (CAS) operation commits the write, while the second receives a rejection (`Ok(None)` or error) because the cell’s version has changed. The rejected replica must re-acquire a fresh lease and retry, ensuring **serialised access** without data corruption.

### How does Celld handle transient storage errors during writes?

Celld distinguishes between transient errors (network timeouts, temporary unavailability) and divergent state errors (checksum mismatches). As implemented in [`replica.rs`](https://github.com/denoland/celld/blob/main/replica.rs), transient failures **retain the current epoch**, allowing the replica to retry using its cached position. Only divergent errors clear the epoch and force a full position re-derivation.

### Why does Celld disable retries for conditional write operations?

Retries are disabled in [`bucket.rs`](https://github.com/denoland/celld/blob/main/bucket.rs) (lines 48–53) for conditional writes to **avoid false rejections**. If the initial CAS fails due to concurrent modification, a retry would likely fail again because the underlying condition (ETag match) remains invalid. Disabling retries forces the caller to re-evaluate the lease and cell state before attempting another write.

### How does write sequencing prevent data loss during cell deletion?

The [`wake.rs`](https://github.com/denoland/celld/blob/main/wake.rs) module tracks cell states in a `flushed` map, ensuring that **PUT operations block** until any in-flight DELETE fully settles in the storage backend. This prevents scenarios where a new write could commit to a cell that is mid-deletion, which would otherwise create an inconsistent state where the delete appears to succeed but the data remains accessible.