mirror of
https://github.com/rustfs/rustfs.git
synced 2026-10-04 04:21:35 +00:00
fix(heal): detect stale delete-marker metadata (#8102)
This commit is contained in:
@@ -6821,7 +6821,12 @@ pub fn should_heal_object_on_disk(
|
||||
return (false, false, err.clone());
|
||||
}
|
||||
|
||||
if !meta.equals(latest_meta) {
|
||||
// `FileInfo::equals` intentionally compares the erasure payload shape and
|
||||
// modification time, but it does not compare the selected version or the
|
||||
// delete-marker bit. Heal uses this decision for versioned metadata, so a
|
||||
// stale historical version that is still marked latest must be treated as
|
||||
// outdated even when those storage-level fields happen to match.
|
||||
if !meta.equals(latest_meta) || !heal_metadata_identity_matches(meta, latest_meta) {
|
||||
debug!(
|
||||
event = EVENT_SET_DISK_HEAL,
|
||||
component = LOG_COMPONENT_ECSTORE,
|
||||
@@ -6844,6 +6849,11 @@ pub fn should_heal_object_on_disk(
|
||||
(false, false, None)
|
||||
}
|
||||
|
||||
fn heal_metadata_identity_matches(meta: &FileInfo, latest_meta: &FileInfo) -> bool {
|
||||
meta.deleted == latest_meta.deleted
|
||||
&& meta.version_id.filter(|version| !version.is_nil()) == latest_meta.version_id.filter(|version| !version.is_nil())
|
||||
}
|
||||
|
||||
/// Probe every drive of the set at once. Each live probe is bounded by the
|
||||
/// drive `disk_info` timeout, and the admin peer probe budget only covers one
|
||||
/// such timeout; a sequential walk over several stalled drives after a power
|
||||
@@ -11288,6 +11298,29 @@ mod tests {
|
||||
assert_eq!(reason, Some(DiskError::FileCorrupt));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn stale_delete_marker_identity_requires_metadata_heal() {
|
||||
let historical_version = Uuid::new_v4();
|
||||
let marker_version = Uuid::new_v4();
|
||||
let mut stale = FileInfo {
|
||||
version_id: Some(historical_version),
|
||||
..FileInfo::default()
|
||||
};
|
||||
let mut latest = stale.clone();
|
||||
stale.deleted = false;
|
||||
latest.deleted = true;
|
||||
latest.version_id = Some(marker_version);
|
||||
|
||||
// The generic equality helper intentionally considers these records
|
||||
// equal when their erasure shape and mod-time match. Heal must still
|
||||
// repair the version identity and delete-marker state.
|
||||
assert!(stale.equals(&latest));
|
||||
let (should_heal, metadata, reason) = should_heal_object_on_disk(&None, &[], &stale, &latest);
|
||||
assert!(should_heal);
|
||||
assert!(metadata);
|
||||
assert_eq!(reason, Some(DiskError::OutdatedXLMeta));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn metadata_io_failures_never_authorize_heal_overwrite() {
|
||||
let meta = FileInfo::default();
|
||||
|
||||
Reference in New Issue
Block a user