Expand description
§Sync Protocol
The sync protocol is based on this paper: https://arxiv.org/abs/2012.00472, it assumes a reliable in-order stream between two peers who are synchronizing a document.
Each peer maintains a State
for each peer they are synchronizing with.
This state tracks things like what the heads of the other peer are and
whether there are in-flight messages. Anything which implements SyncDoc
can take part in the sync protocol. The flow goes something like this:
- The initiating peer creates an empty
State
and then callsSyncDoc::generate_sync_message()
to generate new sync message and sends it to the receiving peer. - The receiving peer receives a message from the initiator, creates a new
State
, and callsSyncDoc::receive_sync_message()
on it’s view of the document - The receiving peer then calls
SyncDoc::generate_sync_message()
to generate a new sync message and send it back to the initiator - From this point on each peer operates in a loop, receiving a sync message from the other peer and then generating a new message to send back.
§Example
use automerge::{transaction::Transactable, sync::{self, SyncDoc}, ReadDoc};
// Create a document on peer1
let mut peer1 = automerge::AutoCommit::new();
peer1.put(automerge::ROOT, "key", "value")?;
// Create a state to track our sync with peer2
let mut peer1_state = sync::State::new();
// Generate the initial message to send to peer2, unwrap for brevity
let message1to2 = peer1.sync().generate_sync_message(&mut peer1_state).unwrap();
// We receive the message on peer2. We don't have a document at all yet
// so we create one
let mut peer2 = automerge::AutoCommit::new();
// We don't have a state for peer1 (it's a new connection), so we create one
let mut peer2_state = sync::State::new();
// Now receive the message from peer 1
peer2.sync().receive_sync_message(&mut peer2_state, message1to2)?;
// Now we loop, sending messages from one to two and two to one until
// neither has anything new to send
loop {
let two_to_one = peer2.sync().generate_sync_message(&mut peer2_state);
if let Some(message) = two_to_one.as_ref() {
println!("two to one");
peer1.sync().receive_sync_message(&mut peer1_state, message.clone())?;
}
let one_to_two = peer1.sync().generate_sync_message(&mut peer1_state);
if let Some(message) = one_to_two.as_ref() {
println!("one to two");
peer2.sync().receive_sync_message(&mut peer2_state, message.clone())?;
}
if two_to_one.is_none() && one_to_two.is_none() {
break;
}
}
assert_eq!(peer2.get(automerge::ROOT, "key")?.unwrap().0.to_str(), Some("value"));
Structs§
- Bloom
Filter - Chunk
List - An array of changes, each of which should be passed to
Automerge::load_incremental()
- Decode
Bloom Error - Have
- A summary of the changes that the sender of the message already has. This is implicitly a request to the recipient to send all changes that the sender does not already have.
- Message
- The sync message to be sent.
- State
- The state of synchronisation with a peer.
Enums§
Traits§
- SyncDoc
- A document which can take part in the sync protocol