aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/document/changes.rs7
-rw-r--r--src/simtest/bench.rs4
-rw-r--r--src/swarm/stats.rs9
-rw-r--r--src/swarm/sync.rs9
4 files changed, 27 insertions, 2 deletions
diff --git a/src/document/changes.rs b/src/document/changes.rs
index 1091261..9a07fc0 100644
--- a/src/document/changes.rs
+++ b/src/document/changes.rs
@@ -8,6 +8,13 @@ use anyhow::{Context, Result, anyhow, bail};
use super::{Change, ChangeHash, Document, ReadDoc};
+/// Whether `doc` has every change of `heads`.
+pub(crate) fn holds_all(doc: &Document, heads: &[ChangeHash]) -> bool {
+ heads
+ .iter()
+ .all(|head| doc.get_change_by_hash(head).is_some())
+}
+
/// Whether the history of `theirs` (of them, those `doc` has) holds all of `ours`
/// (heads of `doc`): a peer at `theirs` has every change we have.
pub(crate) fn covers(doc: &Document, theirs: &[ChangeHash], ours: &[ChangeHash]) -> bool {
diff --git a/src/simtest/bench.rs b/src/simtest/bench.rs
index 39e054e..aec54dc 100644
--- a/src/simtest/bench.rs
+++ b/src/simtest/bench.rs
@@ -350,6 +350,7 @@ impl Totals {
relay.asked_known_later += stats.relay.asked_known_later;
relay.nothing_new_change_bytes += stats.relay.nothing_new_change_bytes;
relay.nothing_new_bloom_bytes += stats.relay.nothing_new_bloom_bytes;
+ relay.waiting += stats.relay.waiting;
relay.off_tree += stats.relay.off_tree;
relay.off_tree_ms += stats.relay.off_tree_ms;
for (_, peer_state) in node.peers_snapshot().await {
@@ -717,13 +718,14 @@ fn report(
);
let _ = writeln!(
out,
- " sync per write: {:.1} taken as delivered ({:.0} bytes each), {:.1} with only changes the receiver had ({:.0} bytes each; {:.1} along trees, {:.1} taken as delivered)",
+ " sync per write: {:.1} taken as delivered ({:.0} bytes each), {:.1} with only changes the receiver had ({:.0} bytes each; {:.1} along trees, {:.1} taken as delivered), {:.1} with changes waiting for predecessors",
delivered.0,
delivered.1,
nothing_new.0,
nothing_new.1,
(r1.nothing_new_along_trees - r0.nothing_new_along_trees) as f64 / writes,
(r1.nothing_new_delivered - r0.nothing_new_delivered) as f64 / writes,
+ (r1.waiting - r0.waiting) as f64 / writes,
);
let each = |bytes: u64, count: u64| {
if count > 0 {
diff --git a/src/swarm/stats.rs b/src/swarm/stats.rs
index 31b6a3b..ba75d68 100644
--- a/src/swarm/stats.rs
+++ b/src/swarm/stats.rs
@@ -157,6 +157,10 @@ pub(crate) struct Relay {
pub(crate) carrying_bloom_bytes: u64,
pub(crate) nothing_new_change_bytes: u64,
pub(crate) nothing_new_bloom_bytes: u64,
+ /// Sync messages received that carried changes, none of them applied yet: they wait
+ /// for predecessors that didn't come (Automerge holds them back). Not counted with
+ /// `nothing_new`, which they aren't.
+ pub(crate) waiting: u64,
/// The changes new to us that sync messages brought (beside what they carried that
/// we had): with `carrying` less `nothing_new`, how many a message with news brings.
pub(crate) new_changes: u64,
@@ -314,6 +318,11 @@ impl NodeStats {
inner.relay.nothing_new_bloom_bytes += sizes.1 as u64;
}
+ /// A sync message carried changes that wait for predecessors (`Relay::waiting`).
+ pub(crate) fn waiting(&self) {
+ self.lock().relay.waiting += 1;
+ }
+
/// Changes from elsewhere were applied, `delays_ms` after they were committed, that
/// came not along a writer's tree.
pub(crate) fn off_tree(&self, delays_ms: &[i64]) {
diff --git a/src/swarm/sync.rs b/src/swarm/sync.rs
index 0edc277..5511ea2 100644
--- a/src/swarm/sync.rs
+++ b/src/swarm/sync.rs
@@ -574,6 +574,7 @@ pub(crate) async fn handle_sync(
peer_state.last_heads =
Some((epoch, transport::HeadsSummary::of(message.heads().to_vec())));
let heads_before = replica.heads().to_vec();
+ let said = message.heads().to_vec();
let sync = &mut peer_state.sync;
replica
@@ -617,7 +618,13 @@ pub(crate) async fn handle_sync(
stats.new_changes(new);
}
if carried && !changed {
- stats.nothing_new(payload_len, writer.is_some(), delivered, sizes);
+ // Its heads not ours yet: what it brought waits for predecessors, which
+ // isn't having come twice.
+ if !crate::document::changes::holds_all(&replica.doc, &said) {
+ stats.waiting();
+ } else {
+ stats.nothing_new(payload_len, writer.is_some(), delivered, sizes);
+ }
}
// Whose they are, to pass them on along their writers' trees, however they
// came (along a tree, with an answer, pulled).