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

xiangfu 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 c141c8de570 [bugfixing] Fix /debug/routingTable always returning same 
replica-group (strictReplicaGroup) (#17403)
c141c8de570 is described below

commit c141c8de570af791d6c58678293a724d788784b2
Author: Xiang Fu <[email protected]>
AuthorDate: Fri Dec 19 14:35:06 2025 -0800

    [bugfixing] Fix /debug/routingTable always returning same replica-group 
(strictReplicaGroup) (#17403)
    
    * gpg signing test
    
    * Fix broker debug routingTable requestId skew
    
    Use a single requestId per /debug/routingTable call and add tests to 
prevent realtime-only strictReplicaGroup skew.
---
 .../broker/api/resources/PinotBrokerDebug.java     |   7 +-
 .../broker/api/resources/PinotBrokerDebugTest.java | 110 +++++++++++++++++++++
 2 files changed, 115 insertions(+), 2 deletions(-)

diff --git 
a/pinot-broker/src/main/java/org/apache/pinot/broker/api/resources/PinotBrokerDebug.java
 
b/pinot-broker/src/main/java/org/apache/pinot/broker/api/resources/PinotBrokerDebug.java
index ba1d2cddf44..1db7133631b 100644
--- 
a/pinot-broker/src/main/java/org/apache/pinot/broker/api/resources/PinotBrokerDebug.java
+++ 
b/pinot-broker/src/main/java/org/apache/pinot/broker/api/resources/PinotBrokerDebug.java
@@ -175,11 +175,14 @@ public class PinotBrokerDebug {
   }
 
   private void getRoutingTable(String tableName, BiConsumer<String, 
RoutingTable> consumer) {
+    // Use a single requestId for both OFFLINE and REALTIME routing so that 
replica-group selection rotates properly
+    // for raw table names (no suffix) and stays consistent for hybrid tables.
+    long requestId = getRequestId();
     TableType tableType = 
TableNameBuilder.getTableTypeFromTableName(tableName);
     if (tableType != TableType.REALTIME) {
       String offlineTableName = 
TableNameBuilder.OFFLINE.tableNameWithType(tableName);
       RoutingTable routingTable = _routingManager.getRoutingTable(
-          CalciteSqlCompiler.compileToBrokerRequest("SELECT * FROM " + 
offlineTableName), getRequestId());
+          CalciteSqlCompiler.compileToBrokerRequest("SELECT * FROM " + 
offlineTableName), requestId);
       if (routingTable != null) {
         consumer.accept(offlineTableName, routingTable);
       }
@@ -187,7 +190,7 @@ public class PinotBrokerDebug {
     if (tableType != TableType.OFFLINE) {
       String realtimeTableName = 
TableNameBuilder.REALTIME.tableNameWithType(tableName);
       RoutingTable routingTable = _routingManager.getRoutingTable(
-          CalciteSqlCompiler.compileToBrokerRequest("SELECT * FROM " + 
realtimeTableName), getRequestId());
+          CalciteSqlCompiler.compileToBrokerRequest("SELECT * FROM " + 
realtimeTableName), requestId);
       if (routingTable != null) {
         consumer.accept(realtimeTableName, routingTable);
       }
diff --git 
a/pinot-broker/src/test/java/org/apache/pinot/broker/api/resources/PinotBrokerDebugTest.java
 
b/pinot-broker/src/test/java/org/apache/pinot/broker/api/resources/PinotBrokerDebugTest.java
new file mode 100644
index 00000000000..550eedd867d
--- /dev/null
+++ 
b/pinot-broker/src/test/java/org/apache/pinot/broker/api/resources/PinotBrokerDebugTest.java
@@ -0,0 +1,110 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.pinot.broker.api.resources;
+
+import java.lang.reflect.Field;
+import java.util.Collections;
+import java.util.List;
+import javax.ws.rs.core.HttpHeaders;
+import org.apache.pinot.broker.routing.BrokerRoutingManager;
+import org.apache.pinot.common.request.BrokerRequest;
+import org.apache.pinot.core.routing.RoutingTable;
+import org.mockito.ArgumentCaptor;
+import org.testng.annotations.Test;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyLong;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertTrue;
+
+
+public class PinotBrokerDebugTest {
+
+  @Test
+  public void testGetRoutingTableUsesSameRequestIdForOfflineAndRealtime()
+      throws Exception {
+    BrokerRoutingManager routingManager = mock(BrokerRoutingManager.class);
+    when(routingManager.getRoutingTable(any(BrokerRequest.class), anyLong()))
+        .thenReturn(new RoutingTable(Collections.emptyMap(), 
Collections.emptyList(), 0));
+
+    PinotBrokerDebug brokerDebug = new PinotBrokerDebug();
+    Field routingManagerField = 
PinotBrokerDebug.class.getDeclaredField("_routingManager");
+    routingManagerField.setAccessible(true);
+    routingManagerField.set(brokerDebug, routingManager);
+
+    brokerDebug.getRoutingTable("testTable", (HttpHeaders) null);
+
+    ArgumentCaptor<Long> requestIdCaptor = ArgumentCaptor.forClass(Long.class);
+    verify(routingManager, times(2)).getRoutingTable(any(BrokerRequest.class), 
requestIdCaptor.capture());
+    List<Long> requestIds = requestIdCaptor.getAllValues();
+    assertEquals(requestIds.size(), 2);
+    assertEquals(requestIds.get(0), requestIds.get(1));
+  }
+
+  @Test
+  public void testGetRoutingTableForRealtimeOnlyRawTableDoesNotSkewRequestId()
+      throws Exception {
+    BrokerRoutingManager routingManager = mock(BrokerRoutingManager.class);
+    when(routingManager.getRoutingTable(any(BrokerRequest.class), 
anyLong())).thenAnswer(invocation -> {
+      BrokerRequest brokerRequest = invocation.getArgument(0);
+      String tableNameWithType = brokerRequest.getQuerySource().getTableName();
+      if (tableNameWithType.endsWith("_REALTIME")) {
+        return new RoutingTable(Collections.emptyMap(), 
Collections.emptyList(), 0);
+      }
+      return null;
+    });
+
+    PinotBrokerDebug brokerDebug = new PinotBrokerDebug();
+    Field routingManagerField = 
PinotBrokerDebug.class.getDeclaredField("_routingManager");
+    routingManagerField.setAccessible(true);
+    routingManagerField.set(brokerDebug, routingManager);
+
+    brokerDebug.getRoutingTable("testTable", (HttpHeaders) null);
+    brokerDebug.getRoutingTable("testTable", (HttpHeaders) null);
+
+    ArgumentCaptor<BrokerRequest> brokerRequestCaptor = 
ArgumentCaptor.forClass(BrokerRequest.class);
+    ArgumentCaptor<Long> requestIdCaptor = ArgumentCaptor.forClass(Long.class);
+    verify(routingManager, 
times(4)).getRoutingTable(brokerRequestCaptor.capture(), 
requestIdCaptor.capture());
+    List<BrokerRequest> brokerRequests = brokerRequestCaptor.getAllValues();
+    List<Long> requestIds = requestIdCaptor.getAllValues();
+
+    assertEquals(brokerRequests.size(), 4);
+    assertEquals(requestIds.size(), 4);
+
+    Long firstRealtimeRequestId = null;
+    Long secondRealtimeRequestId = null;
+    for (int i = 0; i < brokerRequests.size(); i++) {
+      if 
(brokerRequests.get(i).getQuerySource().getTableName().endsWith("_REALTIME")) {
+        if (firstRealtimeRequestId == null) {
+          firstRealtimeRequestId = requestIds.get(i);
+        } else {
+          secondRealtimeRequestId = requestIds.get(i);
+        }
+      }
+    }
+
+    assertTrue(firstRealtimeRequestId != null);
+    assertTrue(secondRealtimeRequestId != null);
+    assertEquals((long) secondRealtimeRequestId, firstRealtimeRequestId + 1);
+  }
+}


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

Reply via email to