aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authortv <tv@krebsco.de>2026-11-01 13:34:26 +0100
committertv <tv@krebsco.de>2026-11-01 13:34:26 +0100
commit1202c0ba9bf49e7e31492c90b37af3e6c91b98b7 (patch)
tree72263c64c60c1d99e6e7b4381c032e8d6a4ec990 /src
parentda76a3fd1eeb01b67cf7e281180bd4b677476d48 (diff)
state: drop epoch_tx
The stamp is the only lock-free epoch label.
Diffstat (limited to 'src')
-rw-r--r--src/node.rs2
-rw-r--r--src/state/host.rs6
-rw-r--r--src/state/mod.rs9
-rw-r--r--src/swarm/peer/epoch.rs3
4 files changed, 9 insertions, 11 deletions
diff --git a/src/node.rs b/src/node.rs
index 8224c7a..f6bdbb3 100644
--- a/src/node.rs
+++ b/src/node.rs
@@ -69,7 +69,6 @@ impl Node {
let (sync_tx, sync_rx) = mpsc::unbounded_channel();
let (change_tx, _) = watch::channel(0_u64);
let (change_events, _) = broadcast::channel(256);
- let (epoch_tx, _) = watch::channel(config.initial_epoch);
let firewall = Arc::new(Firewall::default());
let traffic = Arc::new(Traffic::default());
let initial_actor = crate::document::actor(&config.initial_doc);
@@ -88,7 +87,6 @@ impl Node {
let stamp = replica.stamps();
let state = AppState {
doc: Arc::new(crate::document::lock::DocumentLock::new(replica)),
- epoch_tx,
stamp,
lifecycle: Arc::new(RwLock::new(NodeLifecycle::Joining {
discovered_swarm_id: None,
diff --git a/src/state/host.rs b/src/state/host.rs
index 6bb9d3b..7c3e165 100644
--- a/src/state/host.rs
+++ b/src/state/host.rs
@@ -283,10 +283,10 @@ impl Host for AppState {
replica.epoch = epoch;
replica.epoch_seq += 1;
replica.writable = writable;
+ // Publishes the epoch with the heads (`Replica::stamps`), under the
+ // same lock, so it never disagrees with the document for anyone
+ // holding the lock.
replica.refresh_heads();
- // Updated under the same lock, so the cached epoch never disagrees
- // with the document for anyone holding the lock.
- state.epoch_tx.send_replace(epoch);
// Reset every peer's sync state before the lock is released, so no
// message is generated from or applied to a state that describes the
// old document. (Lock order doc -> peer, as in sync generation.)
diff --git a/src/state/mod.rs b/src/state/mod.rs
index 9ee08b7..5e4a4d3 100644
--- a/src/state/mod.rs
+++ b/src/state/mod.rs
@@ -59,10 +59,9 @@ pub(crate) struct AppState {
/// The document and its epoch. Derefs to `Document`.
pub(crate) doc: Arc<DocumentLock>,
- /// Copy of `doc.epoch` for cheap, lock-free reads (handshakes, keepalives, /peers).
- /// Only ever changed while holding `doc`'s write lock, together with `doc.epoch`.
- pub(crate) epoch_tx: watch::Sender<Epoch>,
- /// `doc`'s epoch label and heads, readable without its lock (`Replica::stamps`).
+ /// `doc`'s epoch label and heads, readable without its lock (`Replica::stamps`):
+ /// for cheap reads (handshakes, keepalives, /peers). Only ever changed while holding
+ /// `doc`'s write lock, together with `doc.epoch`.
pub(crate) stamp: watch::Receiver<Stamp>,
pub(crate) lifecycle: Arc<RwLock<NodeLifecycle>>,
@@ -231,7 +230,7 @@ impl AppState {
/// The local epoch. Code that labels or applies sync messages must use the epoch
/// of the locked `Replica` instead, so label and document can't disagree.
pub(crate) fn local_epoch(&self) -> Epoch {
- *self.epoch_tx.borrow()
+ self.stamp.borrow().epoch
}
/// The local epoch and `Replica::epoch_seq`, read together, without waiting for the
diff --git a/src/swarm/peer/epoch.rs b/src/swarm/peer/epoch.rs
index d97db0f..d00a903 100644
--- a/src/swarm/peer/epoch.rs
+++ b/src/swarm/peer/epoch.rs
@@ -13,7 +13,8 @@ use crate::transport;
///
/// `seq` is the peer's `epoch_seq` with it. A message with a lower one than we have was
/// sent before the peer's last epoch change and delivered late: its epoch isn't
-/// recorded, so it can't flip our view of the peer back. The count starts over when the
+/// recorded, so it can't flip our view of the peer back. The message itself still
+/// counts: if its epoch is ours, its sync is applied (it is data of our epoch). The count starts over when the
/// peer restarts, which its HELLO or HELLO_REPLY tells by a new run (`run`).
pub(super) async fn observe_peer_epoch(
state: &AppState,