From 66e63d20dde39c62b15448e7b0b1389eb1a4dae1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=94=90=E5=B0=8F=E9=B8=AD?= Date: Fri, 21 Aug 2026 19:33:59 +0800 Subject: [PATCH] fix(replication): surface skipped multipart LWW comparison at warn level MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When the complete-multipart LWW gate cannot read the destination version (quorum error), the inbound metadata is applied without comparison — the exact overwrite rustfs/backlog#1953 exists to prevent. Keep the fail-open semantics (failing the complete would loop through MRF) but log the degraded path at warn so operators can see it; the version-absent first replication keeps riding the same branch. --- crates/ecstore/src/set_disk/ops/multipart.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/crates/ecstore/src/set_disk/ops/multipart.rs b/crates/ecstore/src/set_disk/ops/multipart.rs index 0d3ead977..8a176640a 100644 --- a/crates/ecstore/src/set_disk/ops/multipart.rs +++ b/crates/ecstore/src/set_disk/ops/multipart.rs @@ -2254,7 +2254,10 @@ impl crate::storage_api_contracts::multipart::MultipartOperations for SetDisks { crate::set_disk::ops::object::merge_replication_metadata_lww(&mut fi.metadata, &stored, opts); } Err(err) => { - debug!( + // Degraded path: without the stored state the inbound + // metadata is applied unchanged — exactly the overwrite + // LWW exists to prevent — so this must be operator-visible. + warn!( component = LOG_COMPONENT_ECSTORE, subsystem = LOG_SUBSYSTEM_SET_DISK, bucket, @@ -2262,7 +2265,7 @@ impl crate::storage_api_contracts::multipart::MultipartOperations for SetDisks { version_id = %version_id, error = %err, state = "replication_lww_read_unavailable", - "SetDisk multipart replication LWW read skipped" + "SetDisk multipart replication LWW read skipped; inbound metadata applied without comparison" ); } }