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.
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.rsBitfield— models/strand/src/bitfield.rsBitfieldIterator— models/strand/src/bitfield.rsFileStorage— models/strand/src/storage.rsHeader— models/strand/src/lib.rsInfo— models/strand/src/storage.rsMemoryStorage— models/strand/src/storage.rsMerkleTree— models/strand/src/merkle_tree.rsNode— models/strand/src/merkle_tree.rsProof— models/strand/src/merkle_tree.rsRangeHandle— models/strand/src/replication_api.rsRangeSpec— 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(())
}