aboutsummaryrefslogtreecommitdiffstats
path: root/src/remake/mod.rs
diff options
context:
space:
mode:
authortv <tv@krebsco.de>2026-11-01 13:19:04 +0100
committertv <tv@krebsco.de>2026-11-01 13:19:04 +0100
commit7a5a7408179c5fe9943bd2ce60295e86f1afaa40 (patch)
tree166284a6b05f1f3e5d5166c38eda33088ae5461b /src/remake/mod.rs
parentb4aa16f2a3c3f9dc0d4eb6e7399bd7ffe269d669 (diff)
document: reject writes during rejoin
Diffstat (limited to 'src/remake/mod.rs')
-rw-r--r--src/remake/mod.rs18
1 files changed, 13 insertions, 5 deletions
diff --git a/src/remake/mod.rs b/src/remake/mod.rs
index e9d3021..04e9d8a 100644
--- a/src/remake/mod.rs
+++ b/src/remake/mod.rs
@@ -53,7 +53,7 @@ use axum::{
use tokio::sync::broadcast;
use crate::document::replica::Epoch;
-use crate::document::store::ChangeSet;
+use crate::document::store::{ChangeSet, StoreError};
use crate::document::{Document, Transaction};
/// Remakes and their aftermath on this node, in numbers (`/admin/stats`).
@@ -184,12 +184,18 @@ pub(crate) trait Host: Clone + Send + Sync + 'static {
F: FnOnce(&Document) -> T + Send + 'static,
T: Send + 'static;
- /// One committed change (rolled back on error), published and replicated.
+ /// One committed change (rolled back on error), published and replicated. Refused
+ /// (`StoreError::Rejoining`) while the document isn't writable: from a rejoin's
+ /// swap until [`Host::accept_writes`].
fn commit_doc<T, E, F>(&self, f: F) -> impl Future<Output = Result<T, E>> + Send
where
F: FnOnce(&mut Transaction<'_>) -> Result<T, E> + Send + 'static,
T: Send + 'static,
- E: Send + 'static;
+ E: From<StoreError> + Send + 'static;
+
+ /// Lets writes in again, after a rejoin swapped in a document that took none
+ /// ([`Host::switch_epoch`] with `writable` false).
+ fn accept_writes(&self) -> impl Future<Output = ()> + Send;
/// Applies a change downloaded from peers (`fetch_change`), then publishes it like
/// a change received by sync.
@@ -199,11 +205,13 @@ pub(crate) trait Host: Clone + Send + Sync + 'static {
) -> impl Future<Output = Result<(), String>> + Send;
/// Replaces the document and its epoch atomically. Under the write lock, `f` gets
- /// the live document and returns the new one. Afterwards the node resets every
- /// peer's sync state and publishes the change. Returns the old document.
+ /// the live document and returns the new one, which takes writes if `writable`
+ /// (a rejoin's fresh document doesn't). Afterwards the node resets every peer's
+ /// sync state and publishes the change. Returns the old document.
fn switch_epoch<E, F>(
&self,
epoch: Epoch,
+ writable: bool,
f: F,
) -> impl Future<Output = Result<Document, E>> + Send
where