summaryrefslogtreecommitdiffstats
path: root/src/remake/quarantine.rs
diff options
context:
space:
mode:
authortv <tv@krebsco.de>2026-10-21 04:08:26 +0200
committertv <tv@krebsco.de>2026-10-21 04:08:26 +0200
commit2ba02bbcff076224e03eaa8414fe388853977a85 (patch)
tree15e26fc2076196daad0e9c5795dc0782bd965c56 /src/remake/quarantine.rs
parenta6543d818badac822273b53c2d9f367696922ba5 (diff)
turn compaction into a kind of remake
Diffstat (limited to 'src/remake/quarantine.rs')
-rw-r--r--src/remake/quarantine.rs46
1 files changed, 44 insertions, 2 deletions
diff --git a/src/remake/quarantine.rs b/src/remake/quarantine.rs
index 32f28da..1090e2c 100644
--- a/src/remake/quarantine.rs
+++ b/src/remake/quarantine.rs
@@ -14,6 +14,7 @@
use std::convert::Infallible;
+use automerge::AutoCommit;
use axum::{
Json,
extract::{Path, State},
@@ -22,12 +23,16 @@ use axum::{
};
use serde::Serialize;
use serde_json::{Value as JsonValue, json};
-use tracing::info;
+use tracing::{info, warn};
+use uuid::Uuid;
use super::Host;
use super::api::error_response;
use super::delta;
+use super::kind::Translator;
use super::local::Quarantined;
+use super::records::unix_millis;
+use crate::document::replica::Epoch;
use crate::document::store;
#[derive(Debug, Serialize)]
@@ -58,6 +63,41 @@ fn not_found() -> Response {
error_response(StatusCode::NOT_FOUND, "no such quarantine entry", None)
}
+/// Puts writes a remake had no place for into quarantine, with `document` (the old
+/// epoch's) to read them from. Returns the entry's ID, or None if there is nothing.
+pub(super) fn add<H: Host>(
+ host: &H,
+ epoch: Epoch,
+ target: Epoch,
+ document: &AutoCommit,
+ quarantined: Vec<(Vec<String>, String)>,
+) -> Option<String> {
+ if quarantined.is_empty() {
+ return None;
+ }
+ let mut reasons: Vec<&str> = quarantined
+ .iter()
+ .map(|(_, reason)| reason.as_str())
+ .collect();
+ reasons.sort_unstable();
+ reasons.dedup();
+ let reason = reasons.join("; ");
+ let paths: Vec<Vec<String>> = quarantined.into_iter().map(|(path, _)| path).collect();
+
+ let id = Uuid::new_v4().to_string();
+ warn!(quarantine = %id, epoch = %epoch, paths = paths.len(), reason = %reason, "Quarantined writes the remake has no place for");
+ host.remake().add_quarantine(Quarantined {
+ id: id.clone(),
+ epoch,
+ target,
+ created_at: unix_millis(),
+ reason,
+ paths,
+ document: document.clone(),
+ });
+ Some(id)
+}
+
pub(crate) async fn list<H: Host>(State(host): State<H>) -> Response {
Json(host.remake().list_quarantine(summary)).into_response()
}
@@ -129,7 +169,9 @@ pub(crate) async fn replay<H: Host>(State(host): State<H>, Path(id): Path<String
let (stats, entry) = host
.commit_doc(move |doc| {
- let stats = delta::replay_paths(&entry.document, doc, &entry.paths);
+ // As they are: the operator decided they belong at their old paths.
+ let stats =
+ delta::replay_paths(&entry.document, doc, &entry.paths, &Translator::default());
Ok::<_, Infallible>((stats, entry))
})
.await