WeaveDocs
Strand

Replication

Replication streams for Strand: live tail follows, range backfills, and bitfield-driven repair between peers.

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.

Network contract

Document peer identity, topic selection, message framing, session lifetime, retry behavior, metrics, and what must be stable between releases. Any change here can strand peers, so examples should be exercised with at least two real processes.

Warning

Replication wire format is part of the public contract between peers. Changing message framing or session lifetime is a breaking change that strands older peers until they upgrade. Treat it like an on-the-wire protocol revision and version accordingly.

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::{RangeSpec, ReplicationOptions, Strand, StrandConfig};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Seed a local strand with three blocks; replication pulls a range against this state.
    let dir = tempfile::tempdir()?;
    let mut strand = Strand::new(StrandConfig::new().with_storage(dir.path())).await?;
    for payload in [b"a".as_slice(), b"b", b"c"] {
        strand.append(payload).await?;
    }

    // Open a replication handle. Linear=true schedules sequential block fetches;
    // flip it off for interleaved striding (useful when peers are partially populated).
    let opts = ReplicationOptions { is_initiator: true, linear: true };
    let handle = strand.replication(opts).await;

    // Request a bounded range; RangeHandle.cancel_async() stops the scheduler cleanly.
    let range = RangeSpec { start: 0, end: Some(strand.len()), linear: true };
    let range_handle = handle.download(range).await?;
    handle.poll_once().await?;
    range_handle.cancel_async().await?;

    println!("replicated up to seq={}", strand.len() - 1);
    Ok(())
}