mirror of
https://github.com/rustfs/rustfs.git
synced 2026-07-26 08:18:18 +00:00
fix(filemeta): key round-tripped replication reset state by canonical header (backlog#799 B16) (#4325)
fix(filemeta): key round-tripped replication reset state by canonical header (backlog#799 B19->B16) `get_internal_replication_state` stored the reset status under the bare ARN after stripping the internal prefix, while the write and lookup sides (`get_replication_state` / `ReplicationState::target_state`) use the full `target_reset_header(arn)` key. A `target_state` fallback masked the lookup miss, but the map stayed keyed inconsistently (bare on read, full on write), which can drop reset state across merge/reflatten cycles. Store the canonical `target_reset_header(arn)` key on read so the map is consistent everywhere; the lookup fallback becomes belt-and-suspenders rather than load-bearing. Adds a round-trip regression test. Refs backlog#799 (B16), tracked in rustfs/backlog#863.
This commit is contained in:
@@ -2326,7 +2326,14 @@ fn get_internal_replication_state(metadata: &HashMap<String, String>) -> Option<
|
||||
_ => {
|
||||
if let Some(arn) = sub_key.strip_prefix("replication-reset-") {
|
||||
has = true;
|
||||
rs.reset_statuses_map.insert(arn.to_string(), v.clone());
|
||||
// Store the canonical full-header key so the map matches
|
||||
// the key `target_reset_header()` produces on the
|
||||
// write/lookup side. Storing the bare ARN keyed the map
|
||||
// inconsistently (bare on read, full on write), which
|
||||
// could drop reset state across merge/reflatten cycles
|
||||
// (backlog#799 B16).
|
||||
rs.reset_statuses_map
|
||||
.insert(crate::replication::target_reset_header(arn), v.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3645,4 +3652,29 @@ mod tests {
|
||||
assert_eq!(dm.version_id, Some(vid));
|
||||
assert!(dm.mod_time.is_some());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn get_internal_replication_state_keeps_canonical_reset_key() {
|
||||
// The reset status is stored on disk under the full internal key; parsing
|
||||
// must keep it keyed by `target_reset_header(arn)` (not the bare ARN) so
|
||||
// `ReplicationState::target_state` finds it after a round trip
|
||||
// (backlog#799 B16).
|
||||
let arn = "arn:rustfs:replication:us-east-1:target:bucket";
|
||||
let ts = "2026-06-30T00:00:00Z;reset-1".to_string();
|
||||
let key = crate::replication::target_reset_header(arn);
|
||||
let mut metadata = HashMap::new();
|
||||
metadata.insert(key.clone(), ts.clone());
|
||||
|
||||
let rs = get_internal_replication_state(&metadata).expect("reset state should parse");
|
||||
assert_eq!(
|
||||
rs.reset_statuses_map.get(&key),
|
||||
Some(&ts),
|
||||
"map must be keyed by target_reset_header, not the bare ARN"
|
||||
);
|
||||
assert_eq!(
|
||||
rs.target_state(arn).resync_timestamp,
|
||||
ts,
|
||||
"lookup must find the round-tripped reset status"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user