WeaveDocs
Strand

Storage Backends

Pluggable storage backends for Strand: in-memory, on-disk, and custom drivers behind a single trait, with WAL and integrity checks.

Purpose

Append-only log with Merkle proofs, bitfields, storage backends, policies, and replication streams.

This page follows the real source shape for Strand and explains the workflow a developer is likely to use first.

Storage contract

Document persistence format, integrity checks, read/write ordering, idempotency, compaction or repair behavior, and how callers recover from partial failures. This section should answer what data is durable and what can be reconstructed.

Warning

MemoryStorage is for tests only. Data is lost on process exit. Production deployments must use FileStorage (or a custom durable backend) — there is no warning at runtime if you accidentally use the memory backend in production.

Primary types to know

  • AllowAllPolicy — models/strand/src/policy.rs
  • Bitfield — models/strand/src/bitfield.rs
  • BitfieldIterator — models/strand/src/bitfield.rs
  • FileStorage — models/strand/src/storage.rs
  • Header — models/strand/src/lib.rs
  • Info — models/strand/src/storage.rs
  • MemoryStorage — models/strand/src/storage.rs
  • MerkleTree — models/strand/src/merkle_tree.rs
  • Node — models/strand/src/merkle_tree.rs
  • Proof — models/strand/src/merkle_tree.rs
  • RangeHandle — models/strand/src/replication_api.rs
  • RangeSpec — models/strand/src/replication_api.rs

Example shape

use strand::{FileStorage, MemoryStorage, Strand, StrandConfig};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // FileStorage owns 8 flat files (data.bin / data.idx / headers.bin / headers.idx
    // and their counterparts). `new` is idempotent — re-opening reuses existing files.
    let durable_dir = tempfile::tempdir()?;
    let _file_backend = FileStorage::new(durable_dir.path())?;

    // The Strand builder picks FileStorage when you supply a path via `with_storage`.
    let cfg = StrandConfig::new().with_storage(durable_dir.path());
    let mut durable = Strand::new(cfg).await?;
    durable.append(b"durable-block").await?;

    // MemoryStorage is a drop-in `Storage` impl for tests and ephemeral peers.
    // Strand chooses it automatically when no path is configured.
    let mut ephemeral = Strand::new(StrandConfig::new()).await?;
    let _ = MemoryStorage::new(); // referenced to document the explicit constructor
    ephemeral.append(b"in-memory-block").await?;

    println!(
        "durable_path={} durable_len={} ephemeral_len={}",
        durable_dir.path().display(),
        durable.len(),
        ephemeral.len(),
    );
    Ok(())
}