mirror of
https://github.com/rustfs/rustfs.git
synced 2026-08-13 00:26:53 +00:00
fix(site-replication): admit same-generation peer-edit fan-out bodies (#6007)
The peer-edit delivery fence from #5882 treated an equal applied generation as stale. One edit legitimately fans out one delivery per peer record under a single generation (the ILM-expiry edit sends every peer's record), so the receiver applied only the first body, raised its high-water mark, and silently acked-success while dropping the rest — enableILMExpiryReplication never converged on receiving sites and the three-node nightly e2e failed deterministically (issue #5767). Only a strictly newer applied generation is stale now. Equal generation implies the same logical edit and re-applying a delivery is idempotent (update_peer overwrites the peer record; the mark is raised with max), while strictly older deliveries — the cross-node ordering case the fence exists for — stay rejected. Adds a composed unit test driving three same-generation bodies through the receiver's fenced sequence, and widens the replication e2e's two site-replication wait helpers from a 10s polling ceiling to the 30s deadline the file's other waits use.
This commit is contained in:
@@ -2401,15 +2401,20 @@ async fn wait_for_site_replication_info<F>(
|
||||
where
|
||||
F: Fn(&SiteReplicationInfo) -> bool,
|
||||
{
|
||||
for _ in 0..40 {
|
||||
// 30s to match wait_for_replication_state: the three-node site tests run
|
||||
// several full rustfs processes on one runner, so peer-state propagation
|
||||
// can take well over 10s under CI load.
|
||||
let deadline = tokio::time::Instant::now() + Duration::from_secs(30);
|
||||
loop {
|
||||
let info = site_replication_info(env).await?;
|
||||
if predicate(&info) {
|
||||
return Ok(info);
|
||||
}
|
||||
if tokio::time::Instant::now() >= deadline {
|
||||
return Err(format!("site replication info did not reach expected state on {}", env.address).into());
|
||||
}
|
||||
sleep(Duration::from_millis(250)).await;
|
||||
}
|
||||
|
||||
Err(format!("site replication info did not reach expected state on {}", env.address).into())
|
||||
}
|
||||
|
||||
async fn wait_for_site_replication_status<F>(
|
||||
@@ -2420,15 +2425,19 @@ async fn wait_for_site_replication_status<F>(
|
||||
where
|
||||
F: Fn(&SRStatusInfo) -> bool,
|
||||
{
|
||||
for _ in 0..40 {
|
||||
// Same 30s ceiling as wait_for_site_replication_info: the status probes
|
||||
// fan out to every peer, so they see the same multi-process CI load.
|
||||
let deadline = tokio::time::Instant::now() + Duration::from_secs(30);
|
||||
loop {
|
||||
let status = site_replication_status(env, query).await?;
|
||||
if predicate(&status) {
|
||||
return Ok(status);
|
||||
}
|
||||
if tokio::time::Instant::now() >= deadline {
|
||||
return Err(format!("site replication status did not reach expected state on {}", env.address).into());
|
||||
}
|
||||
sleep(Duration::from_millis(250)).await;
|
||||
}
|
||||
|
||||
Err(format!("site replication status did not reach expected state on {}", env.address).into())
|
||||
}
|
||||
|
||||
async fn wait_for_replication_reset_target<F>(
|
||||
|
||||
Reference in New Issue
Block a user