aboutsummaryrefslogtreecommitdiffstats
path: root/src/state/read.rs
diff options
context:
space:
mode:
authortv <tv@krebsco.de>2026-11-01 19:35:20 +0100
committertv <tv@krebsco.de>2026-11-01 19:35:20 +0100
commit1f3be9d059876f7f3994056b1ac8ce307628a52a (patch)
tree8f1ca7e7d4b5c1b317d6191b44f0c580aa90acbc /src/state/read.rs
parenta9838a756fa7730e887598592a2f1b5b294e68a7 (diff)
document: allow writes during rejoin
Diffstat (limited to 'src/state/read.rs')
-rw-r--r--src/state/read.rs27
1 files changed, 21 insertions, 6 deletions
diff --git a/src/state/read.rs b/src/state/read.rs
index a9b3116..e325e61 100644
--- a/src/state/read.rs
+++ b/src/state/read.rs
@@ -1,4 +1,5 @@
-//! Serving reads: from the live document, or from the pre-rejoin copy while rejoining.
+//! Serving reads: from the live document, or from the pre-rejoin document while
+//! rejoining.
use std::sync::Arc;
@@ -7,10 +8,13 @@ use crate::document::replica::Epoch;
use crate::document::{ChangeHash, Document};
use crate::locks::RwLockExt;
-/// A read-only view of the document the node served before it started rejoining.
+/// The document the node served before it started rejoining, of the epoch it left:
+/// reads are answered from it (marked stale), and writes go into it
+/// (`AppState::mutate_doc`), until the rejoin replays them into the new epoch or
+/// restores this document (`Host::finish_rejoin`, `Host::abandon_rejoin`).
pub(crate) struct StaleView {
pub(crate) epoch: Epoch,
- pub(crate) doc: Arc<Document>,
+ pub(crate) doc: Arc<std::sync::RwLock<Document>>,
}
/// Where a read was served from.
@@ -57,9 +61,12 @@ impl AppState {
return Err(axum::http::StatusCode::SERVICE_UNAVAILABLE);
};
- let rendered = tokio::task::spawn_blocking(move || finish(read(&doc)))
- .await
- .expect("document read task panicked");
+ let rendered = tokio::task::spawn_blocking(move || {
+ let data = read(&doc.read_or_recover());
+ finish(data)
+ })
+ .await
+ .expect("document read task panicked");
Ok((rendered, ReadSource::Stale(epoch), None))
}
@@ -93,4 +100,12 @@ impl AppState {
pub(super) fn set_stale(&self, view: Option<StaleView>) {
*self.stale.write_or_recover() = view;
}
+
+ /// The stale view's document and epoch, if there is one.
+ pub(crate) fn stale_document(&self) -> Option<(Epoch, Arc<std::sync::RwLock<Document>>)> {
+ self.stale
+ .read_or_recover()
+ .as_ref()
+ .map(|view| (view.epoch, Arc::clone(&view.doc)))
+ }
}