summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authortv <tv@krebsco.de>2026-10-26 20:47:15 +0100
committertv <tv@krebsco.de>2026-10-26 20:47:15 +0100
commit53baaff5d7c1c9fd62cf0e94bcb86120edd699b6 (patch)
treef2904948a02fdaf1e473f686fadda135a8b7b74c /src
parent88417aa0660b0766f3c75bf5846361528537e0b9 (diff)
permit at most one document export at a time
Diffstat (limited to 'src')
-rw-r--r--src/api/document.rs23
1 files changed, 23 insertions, 0 deletions
diff --git a/src/api/document.rs b/src/api/document.rs
index 6c10c38..20bbc7b 100644
--- a/src/api/document.rs
+++ b/src/api/document.rs
@@ -5,6 +5,8 @@
//! it came from is in headers: `X-Continuum-Swarm`, `X-Continuum-Epoch`
//! (`<generation>:<id hex>`) and `X-Continuum-Heads` (hex, comma-separated).
+use std::sync::atomic::{AtomicBool, Ordering};
+
use axum::{
extract::State,
http::{HeaderName, HeaderValue, StatusCode, header},
@@ -15,10 +17,31 @@ use tracing::{info, warn};
use crate::state::AppState;
+/// An export in progress: each holds a copy of the whole document and its saved bytes,
+/// so one at a time.
+static EXPORTING: AtomicBool = AtomicBool::new(false);
+
+/// Clears `EXPORTING` when the export ends, however it ends.
+struct Exporting;
+
+impl Drop for Exporting {
+ fn drop(&mut self) {
+ EXPORTING.store(false, Ordering::Release);
+ }
+}
+
pub(crate) async fn get_document(State(state): State<AppState>) -> Response {
if !state.is_ready().await {
return (StatusCode::SERVICE_UNAVAILABLE, "node is not ready\n").into_response();
}
+ if EXPORTING.swap(true, Ordering::AcqRel) {
+ return (
+ StatusCode::TOO_MANY_REQUESTS,
+ "another export is in progress; try again when it is done\n",
+ )
+ .into_response();
+ }
+ let _exporting = Exporting;
let swarm_id = state.swarm_id().await.unwrap_or_default();
let start = Instant::now();