From 53baaff5d7c1c9fd62cf0e94bcb86120edd699b6 Mon Sep 17 00:00:00 2001 From: tv Date: Mon, 26 Oct 2026 20:47:15 +0100 Subject: permit at most one document export at a time --- src/api/document.rs | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) (limited to 'src/api') 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` //! (`:`) 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) -> 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(); -- cgit v1.3.1