This is an automated email from the ASF dual-hosted git repository.

Jackie-Jiang pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/pinot.git


The following commit(s) were added to refs/heads/master by this push:
     new 4f7023a564a Wait for external view convergence before the single 
validation run in pauseless ingestion tests (#19354)
4f7023a564a is described below

commit 4f7023a564ab8363645497a4df7297f54f472283
Author: Xiaotian (Jackie) Jiang <[email protected]>
AuthorDate: Mon Aug 24 17:19:58 2026 -0700

    Wait for external view convergence before the single validation run in 
pauseless ingestion tests (#19354)
---
 .../tests/BasePauselessRealtimeIngestionTest.java  |  6 ++++++
 .../realtime/utils/PauselessRealtimeTestUtils.java | 25 ++++++++++++++++++++++
 2 files changed, 31 insertions(+)

diff --git 
a/pinot-integration-tests/src/test/java/org/apache/pinot/integration/tests/BasePauselessRealtimeIngestionTest.java
 
b/pinot-integration-tests/src/test/java/org/apache/pinot/integration/tests/BasePauselessRealtimeIngestionTest.java
index be447d786f9..fa5c5c01528 100644
--- 
a/pinot-integration-tests/src/test/java/org/apache/pinot/integration/tests/BasePauselessRealtimeIngestionTest.java
+++ 
b/pinot-integration-tests/src/test/java/org/apache/pinot/integration/tests/BasePauselessRealtimeIngestionTest.java
@@ -202,6 +202,12 @@ public abstract class BasePauselessRealtimeIngestionTest 
extends BaseClusterInte
 
     disableFailure();
 
+    // The repair performed by the validation run below discovers the server 
hosting each stranded segment through
+    // the external view, so wait for the external view to catch up with the 
ideal state first. E.g. when commit-end
+    // fails, the stranded segments are already ONLINE in the ideal state, but 
on a loaded host the server may not
+    // have processed the CONSUMING -> ONLINE transitions yet, and the 
one-shot repair would permanently miss them.
+    
PauselessRealtimeTestUtils.waitForExternalViewToConverge(_helixResourceManager, 
tableNameWithType, 100_000L);
+
     // Force-expire the segments stranded by the injected failure instead of 
waiting out the max segment completion
     // time: they become immediately eligible for repair, and their in-flight 
commit attempts keep getting rejected,
     // so the single validation run below stays the only recovery path under 
test. Segments created afterwards keep
diff --git 
a/pinot-integration-tests/src/test/java/org/apache/pinot/integration/tests/realtime/utils/PauselessRealtimeTestUtils.java
 
b/pinot-integration-tests/src/test/java/org/apache/pinot/integration/tests/realtime/utils/PauselessRealtimeTestUtils.java
index 16b3cf5e776..4b117234f01 100644
--- 
a/pinot-integration-tests/src/test/java/org/apache/pinot/integration/tests/realtime/utils/PauselessRealtimeTestUtils.java
+++ 
b/pinot-integration-tests/src/test/java/org/apache/pinot/integration/tests/realtime/utils/PauselessRealtimeTestUtils.java
@@ -23,6 +23,7 @@ import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import org.apache.helix.HelixManager;
+import org.apache.helix.model.ExternalView;
 import org.apache.helix.model.IdealState;
 import org.apache.pinot.common.metadata.segment.SegmentZKMetadata;
 import org.apache.pinot.common.utils.LLCSegmentName;
@@ -30,6 +31,7 @@ import org.apache.pinot.common.utils.helix.HelixHelper;
 import org.apache.pinot.controller.helix.core.PinotHelixResourceManager;
 import 
org.apache.pinot.controller.helix.core.realtime.PinotLLCRealtimeSegmentManager;
 import org.apache.pinot.spi.utils.CommonConstants;
+import org.apache.pinot.util.TestUtils;
 
 import static org.testng.Assert.assertEquals;
 
@@ -45,6 +47,29 @@ public class PauselessRealtimeTestUtils {
     assertEquals(segmentAssignment.size(), numSegmentsExpected);
   }
 
+  /// Waits until the external view of the given table converges to its ideal 
state, i.e. every instance of every
+  /// segment in the ideal state reaches the prescribed state in the external 
view.
+  ///
+  /// The segment repair performed by the validation task discovers segment 
replicas through the external view, so a
+  /// test that relies on a single validation run must wait for convergence 
before triggering it: a still-pending
+  /// `CONSUMING -> ONLINE` transition would make the one-shot repair 
permanently miss the segment.
+  public static void waitForExternalViewToConverge(PinotHelixResourceManager 
helixResourceManager,
+      String tableNameWithType, long timeoutMs) {
+    TestUtils.waitForCondition(aVoid -> {
+      IdealState idealState = 
helixResourceManager.getTableIdealState(tableNameWithType);
+      ExternalView externalView = 
helixResourceManager.getTableExternalView(tableNameWithType);
+      if (idealState == null || externalView == null) {
+        return false;
+      }
+      for (Map.Entry<String, Map<String, String>> entry : 
idealState.getRecord().getMapFields().entrySet()) {
+        if 
(!entry.getValue().equals(externalView.getStateMap(entry.getKey()))) {
+          return false;
+        }
+      }
+      return true;
+    }, 1000, timeoutMs, "External view failed to converge to ideal state for 
table: " + tableNameWithType);
+  }
+
   /// Marks all current segments of the given table as exceeding the max 
segment completion time, making them
   /// immediately eligible for repair by the next validation run while keeping 
their in-flight commit attempts
   /// rejected. Segments created after this call are not affected. No-op when 
the cluster is not started with a


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to