You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@iggy.apache.org by gk...@apache.org on 2026/10/23 16:28:02 UTC
(iggy) branch fix_partition_replica_commit updated: fix CI v3
This is an automated email from the ASF dual-hosted git repository.
numinnex pushed a commit to branch fix_partition_replica_commit
in repository https://gitbox.apache.org/repos/asf/iggy.git
The following commit(s) were added to refs/heads/fix_partition_replica_commit by this push:
new 0e177ec1f fix CI v3
0e177ec1f is described below
commit 0e177ec1f897ac0de28975391587d8280278b08b
Author: Grzegorz Koszyk <g....@gmail.com>
AuthorDate: Fri Oct 23 18:27:56 2026 +0200
fix CI v3
---
core/integration/tests/cluster/crash_durability.rs | 33 +++++++++++++++++++++-
1 file changed, 32 insertions(+), 1 deletion(-)
diff --git a/core/integration/tests/cluster/crash_durability.rs b/core/integration/tests/cluster/crash_durability.rs
index 5dc857d66..1ed2a2b13 100644
--- a/core/integration/tests/cluster/crash_durability.rs
+++ b/core/integration/tests/cluster/crash_durability.rs
@@ -251,6 +251,34 @@ async fn wait_until_cluster_serves(
}
}
+/// Poll until `node`'s partition superblock records the highest view any other
+/// node persisted as its log view, so `node` adopted it instead of still probing.
+async fn wait_until_partition_rejoined(harness: &TestHarness, node: usize, budget: Duration) {
+ let deadline = tokio::time::Instant::now() + budget;
+ loop {
+ let view = (0..harness.cluster_size())
+ .filter(|other| *other != node)
+ .filter_map(|other| {
+ disk::read_partition_superblock_state(&harness.node(other).data_path())
+ })
+ .map(|state| state.view)
+ .max();
+ let own = disk::read_partition_superblock_state(&harness.node(node).data_path())
+ .map(|state| (state.view, state.log_view));
+ if let (Some(view), Some((_, log_view))) = (view, own)
+ && log_view >= view
+ {
+ return;
+ }
+ assert!(
+ tokio::time::Instant::now() < deadline,
+ "node {node} did not rejoin the partition's view within {budget:?}: \
+ others at view {view:?}, node {node} at (view, log_view) {own:?}"
+ );
+ sleep(POLL_INTERVAL).await;
+ }
+}
+
/// Poll until every node's segment files hold all of `payloads`, so a
/// follow-up SIGKILL provably erases nothing that was flushed. Replaces a
/// settle sleep: the ack proves quorum COMMIT, but each replica flushes on
@@ -648,7 +676,9 @@ async fn given_persisted_topic_when_backup_misses_writes_should_repair_before_du
/// missing more ops than one repair chunk. A restarted replica holds back entries
/// above its recovered commit point until the view's log proves them, so repair has to walk that
/// window chunk by chunk before the replica can ack again, and the next kill
-/// leaves it as half of the quorum.
+/// leaves it as half of the quorum. The next kill waits for it to rejoin the
+/// partition's view: until then it votes as a log that may lack acked ops, and
+/// with one survivor left no trusted quorum can elect.
#[iggy_harness(cluster_nodes = 3, server(cluster.repair_chunk_max = 4))]
async fn given_persisted_topic_when_every_replica_is_killed_in_turn_should_preserve_acked_messages(
harness: &mut TestHarness,
@@ -694,6 +724,7 @@ async fn given_persisted_topic_when_every_replica_is_killed_in_turn_should_prese
.await
.unwrap_or_else(|_| panic!("writes stalled after node {node} restarted")),
);
+ wait_until_partition_rejoined(harness, node, CONVERGE_TIMEOUT).await;
}
let client = wait_until_cluster_serves(harness, &nodes, CONVERGE_TIMEOUT).await;
wait_for_acked_readable(&client, &acked, CONVERGE_TIMEOUT)