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

ab pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/solr.git


The following commit(s) were added to refs/heads/main by this push:
     new 1818ae278f1 SOLR-17869: Avoid creating grouping shard requests when 
timeAllowed is exhausted (#3678)
1818ae278f1 is described below

commit 1818ae278f1195567b95c91aa54acea8614330a1
Author: Andrzej BiaƂecki <[email protected]>
AuthorDate: Thu Sep 25 16:06:34 2025 +0200

    SOLR-17869: Avoid creating grouping shard requests when timeAllowed is 
exhausted (#3678)
---
 solr/CHANGES.txt                                   |   2 +
 .../TopGroupsShardRequestFactory.java              |  22 +++--
 .../org/apache/solr/TestDistributedGrouping.java   | 109 ++++++++++++++++++---
 3 files changed, 112 insertions(+), 21 deletions(-)

diff --git a/solr/CHANGES.txt b/solr/CHANGES.txt
index 60a2db6c5f1..fb829a39fb9 100644
--- a/solr/CHANGES.txt
+++ b/solr/CHANGES.txt
@@ -280,6 +280,8 @@ Bug Fixes
 
 * SOLR-17837: PULL replica nodes could be marked as "preferredLeader" by 
BALANCESHARDUNIQUE despite never being able to be elected leader (Kevin Liang 
via Houston Putman)
 
+* SOLR-17869: Avoid creating grouping shard requests when timeAllowed has 
already run out. (Andrzej Bialecki, hossman)
+
 Dependency Upgrades
 ---------------------
 (No changes)
diff --git 
a/solr/core/src/java/org/apache/solr/search/grouping/distributed/requestfactory/TopGroupsShardRequestFactory.java
 
b/solr/core/src/java/org/apache/solr/search/grouping/distributed/requestfactory/TopGroupsShardRequestFactory.java
index 22127f76dfc..fb795d21d62 100644
--- 
a/solr/core/src/java/org/apache/solr/search/grouping/distributed/requestfactory/TopGroupsShardRequestFactory.java
+++ 
b/solr/core/src/java/org/apache/solr/search/grouping/distributed/requestfactory/TopGroupsShardRequestFactory.java
@@ -83,6 +83,22 @@ public class TopGroupsShardRequestFactory implements 
ShardRequestFactory {
     sreq.purpose = ShardRequest.PURPOSE_GET_TOP_IDS;
     sreq.params = new ModifiableSolrParams(rb.req.getParams());
 
+    // TODO: should eventually all components that send sub-requests be 
subject to similar
+    //  logic if we are running with timeAllowed?
+    int origTimeAllowed = sreq.params.getInt(CommonParams.TIME_ALLOWED, -1);
+    if (origTimeAllowed > 0) {
+      int remainingTimeAllowed = origTimeAllowed - rb.firstPhaseElapsedTime;
+      // at least 1 ms to be useful
+      if (remainingTimeAllowed <= 1) {
+        // We've already used up our time budget
+        rb.rsp.setPartialResults(rb.req);
+        rb.rsp.addPartialResponseDetail(
+            getClass().getSimpleName() + ": timeAllowed exhausted in first 
phase");
+        return new ShardRequest[0];
+      }
+      sreq.params.set(CommonParams.TIME_ALLOWED, remainingTimeAllowed);
+    }
+
     // If group.format=simple group.offset doesn't make sense
     Grouping.Format responseFormat = rb.getGroupingSpec().getResponseFormat();
     if (responseFormat == Grouping.Format.simple || 
rb.getGroupingSpec().isMain()) {
@@ -132,12 +148,6 @@ public class TopGroupsShardRequestFactory implements 
ShardRequestFactory {
       sreq.params.set(CommonParams.FL, schema.getUniqueKeyField().getName());
     }
 
-    int origTimeAllowed = sreq.params.getInt(CommonParams.TIME_ALLOWED, -1);
-    if (origTimeAllowed > 0) {
-      sreq.params.set(
-          CommonParams.TIME_ALLOWED, Math.max(1, origTimeAllowed - 
rb.firstPhaseElapsedTime));
-    }
-
     return new ShardRequest[] {sreq};
   }
 }
diff --git a/solr/core/src/test/org/apache/solr/TestDistributedGrouping.java 
b/solr/core/src/test/org/apache/solr/TestDistributedGrouping.java
index a2bbcadb37d..132b21784e0 100644
--- a/solr/core/src/test/org/apache/solr/TestDistributedGrouping.java
+++ b/solr/core/src/test/org/apache/solr/TestDistributedGrouping.java
@@ -28,6 +28,13 @@ import org.apache.solr.common.params.CommonParams;
 import org.apache.solr.common.params.ModifiableSolrParams;
 import org.apache.solr.common.params.SolrParams;
 import org.apache.solr.common.util.NamedList;
+import org.apache.solr.handler.component.QueryComponent;
+import org.apache.solr.handler.component.ResponseBuilder;
+import org.apache.solr.handler.component.ShardRequest;
+import org.apache.solr.request.SolrQueryRequest;
+import org.apache.solr.response.SolrQueryResponse;
+import 
org.apache.solr.search.grouping.distributed.requestfactory.TopGroupsShardRequestFactory;
+import org.junit.BeforeClass;
 import org.junit.Test;
 
 /**
@@ -39,6 +46,11 @@ import org.junit.Test;
 @SuppressPointFields(bugUrl = 
"https://issues.apache.org/jira/browse/SOLR-10844";)
 public class TestDistributedGrouping extends BaseDistributedSearchTestCase {
 
+  @BeforeClass
+  public static void beforeClass() throws Exception {
+    initCore("solrconfig-delaying-component.xml", "schema.xml");
+  }
+
   public TestDistributedGrouping() {
     // SOLR-10844: Even with points suppressed, this test breaks if we 
(randomize) docvalues="true"
     // on trie fields?!?!?!!?
@@ -1251,19 +1263,48 @@ public class TestDistributedGrouping extends 
BaseDistributedSearchTestCase {
       for (String rows : new String[] {"10", "0"}) {
         simpleQuery(
             "q", "*:*", "group", "true", "group.field", i1, "group.ngroups", 
ngroups, "rows", rows);
-        simpleQuery(
-            "q",
-            "*:*",
-            "group",
-            "true",
-            "group.field",
-            i1,
-            "group.ngroups",
-            ngroups,
-            "rows",
-            rows,
-            "timeAllowed",
-            "123456");
+        // delaying component introduces a delay longer than timeAllowed
+        QueryResponse rsp =
+            simpleQuery(
+                "q",
+                t1 + ":eggs",
+                "group",
+                "true",
+                "group.field",
+                i1,
+                "group.ngroups",
+                ngroups,
+                "rows",
+                rows,
+                "cache",
+                "false",
+                "timeAllowed",
+                "200",
+                "sleep",
+                "300");
+        assertTrue(
+            "header: " + rsp.getHeader(), 
SolrQueryResponse.isPartialResults(rsp.getHeader()));
+        //
+        rsp =
+            simpleQuery(
+                "q",
+                t1 + ":eggs",
+                "group",
+                "true",
+                "group.field",
+                i1,
+                "group.ngroups",
+                ngroups,
+                "rows",
+                rows,
+                "cache",
+                "false",
+                "timeAllowed",
+                "200",
+                "sleep",
+                "10");
+        assertFalse(
+            "header: " + rsp.getHeader(), 
SolrQueryResponse.isPartialResults(rsp.getHeader()));
       }
     }
 
@@ -1650,13 +1691,51 @@ public class TestDistributedGrouping extends 
BaseDistributedSearchTestCase {
         "true");
   }
 
-  private void simpleQuery(Object... queryParams) throws Exception {
+  @Test
+  public void testShardRequestFactory() throws Exception {
+    SolrQueryRequest req =
+        req(
+            "q",
+            "*:*",
+            "rows",
+            "100",
+            "fl",
+            "id," + i1,
+            "group",
+            "true",
+            "group.field",
+            i1,
+            "group.limit",
+            "-1",
+            "sort",
+            i1 + " asc, id asc",
+            "timeAllowed",
+            "200");
+    try {
+      SolrQueryResponse rsp = new SolrQueryResponse();
+      ResponseBuilder rb = new ResponseBuilder(req, rsp, List.of());
+      new QueryComponent().prepare(rb);
+      rb.setNeedDocSet(true);
+
+      TopGroupsShardRequestFactory f = new TopGroupsShardRequestFactory();
+      ShardRequest[] sreq = f.constructRequest(rb);
+      assertTrue(sreq.length > 0);
+
+      rb.firstPhaseElapsedTime = 200; // simulate timeout
+      sreq = f.constructRequest(rb);
+      assertEquals(0, sreq.length);
+    } finally {
+      req.close();
+    }
+  }
+
+  private QueryResponse simpleQuery(Object... queryParams) throws Exception {
     ModifiableSolrParams params = new ModifiableSolrParams();
     for (int i = 0; i < queryParams.length; i += 2) {
       params.add(queryParams[i].toString(), queryParams[i + 1].toString());
     }
     params.set("shards", shards);
-    queryRandomShard(params);
+    return queryRandomShard(params);
   }
 
   /**

Reply via email to