fix(replication): propagate metadata changes (#5635)

Preserve metadata replication operations in the durable MRF and route tagging, retention, and legal-hold updates through the existing full-object replication transport. Keep ACL propagation outside the contract because the current object model has no durable object ACL state.

Refs #1616
This commit is contained in:
cxymds
2026-08-02 21:50:24 +08:00
committed by GitHub
parent 2cc7443067
commit 779b5a49ea
8 changed files with 294 additions and 156 deletions
+24 -2
View File
@@ -550,6 +550,8 @@ pub enum MrfOpKind {
#[default]
#[serde(rename = "object")]
Object,
#[serde(rename = "metadata")]
Metadata,
#[serde(rename = "delete")]
Delete,
}
@@ -831,7 +833,11 @@ impl ReplicationWorkerOperation for ReplicateObjectInfo {
version_id: self.version_id,
retry_count: retry_count_to_mrf(self.retry_count),
size: self.size,
op: MrfOpKind::Object,
op: if self.op_type == ReplicationType::Metadata {
MrfOpKind::Metadata
} else {
MrfOpKind::Object
},
delete_marker_version_id: None,
delete_marker: false,
delete_marker_mtime: None,
@@ -886,7 +892,11 @@ impl ReplicateObjectInfo {
version_id: self.version_id,
retry_count: retry_count_to_mrf(self.retry_count),
size: self.size,
op: MrfOpKind::Object,
op: if self.op_type == ReplicationType::Metadata {
MrfOpKind::Metadata
} else {
MrfOpKind::Object
},
delete_marker_version_id: None,
delete_marker: false,
delete_marker_mtime: None,
@@ -1114,6 +1124,18 @@ mod tests {
assert_eq!(asynchronous.replicate_target_arns(), vec!["arn:async".to_string()]);
}
#[test]
fn metadata_replication_mrf_entry_preserves_operation_kind() {
let info = ReplicateObjectInfo {
bucket: "bucket".to_string(),
name: "object".to_string(),
op_type: ReplicationType::Metadata,
..Default::default()
};
assert_eq!(info.to_mrf_entry().op, MrfOpKind::Metadata);
}
#[test]
fn target_state_reads_resync_timestamp_from_target_reset_header_key() {
let arn = "arn:rustfs:replication:us-east-1:target:bucket";