From 1f3be9d059876f7f3994056b1ac8ce307628a52a Mon Sep 17 00:00:00 2001 From: tv Date: Sun, 1 Nov 2026 19:35:20 +0100 Subject: document: allow writes during rejoin --- src/state/mod.rs | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) (limited to 'src/state/mod.rs') diff --git a/src/state/mod.rs b/src/state/mod.rs index 6e6e48c..7c1299f 100644 --- a/src/state/mod.rs +++ b/src/state/mod.rs @@ -40,7 +40,7 @@ use crate::document::lock::DocumentLock; use crate::document::replica::{Epoch, Stamp}; use crate::document::store::{ChangeSet, StoreError}; use crate::document::{Document, Transaction}; -use crate::locks::MutexExt; +use crate::locks::{MutexExt, RwLockExt}; use crate::remake::{Host, RemakeState}; use crate::swarm::sync::SyncEvent; use crate::swarm::throughput::ThroughputTable; @@ -394,8 +394,10 @@ impl AppState { /// Mutates the document on the blocking pool as one change, then /// publishes it. Write and notification run in the same blocking task, so a - /// cancelled request can't leave a committed write unannounced. Refused - /// (`StoreError::Rejoining`, `f` not called) while the document isn't writable. + /// cancelled request can't leave a committed write unannounced. While a rejoin runs, + /// the write goes into the document before it (`StaleView`), replayed when the + /// rejoin ends; on a node that keeps none, it is refused (`StoreError::Rejoining`, + /// `f` not called). pub(crate) async fn mutate_doc( &self, f: impl FnOnce(&mut Transaction<'_>) -> Result + Send + 'static, @@ -412,7 +414,18 @@ impl AppState { // Checked here, under the lock: the caller's readiness check (if any) // was before a rejoin could swap in a fresh document. if !replica.writable { - return Err(E::from(StoreError::Rejoining)); + // Rejoining: into the document before the rejoin, which the rejoin + // replays when it ends (`StaleView`); refused by a node that keeps + // none (it wasn't ready). + let Some((_, stale)) = state.stale_document() else { + return Err(E::from(StoreError::Rejoining)); + }; + let mut doc = stale.write_or_recover(); + return crate::document::replica::transact( + &mut doc, + state.clock.now_millis(), + f, + ); } // One API write = one change; on error, its partial writes (e.g. the old // value deleted, the new one not written) are dropped. -- cgit v1.3.1