Skip to content

Commit 1818ae2

Browse files
authored
SOLR-17869: Avoid creating grouping shard requests when timeAllowed is exhausted (#3678)
1 parent de7f11d commit 1818ae2

File tree

3 files changed

+112
-21
lines changed

3 files changed

+112
-21
lines changed

solr/CHANGES.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -280,6 +280,8 @@ Bug Fixes
280280

281281
* 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)
282282

283+
* SOLR-17869: Avoid creating grouping shard requests when timeAllowed has already run out. (Andrzej Bialecki, hossman)
284+
283285
Dependency Upgrades
284286
---------------------
285287
(No changes)

solr/core/src/java/org/apache/solr/search/grouping/distributed/requestfactory/TopGroupsShardRequestFactory.java

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,22 @@ private ShardRequest[] createRequest(ResponseBuilder rb, String[] shards) {
8383
sreq.purpose = ShardRequest.PURPOSE_GET_TOP_IDS;
8484
sreq.params = new ModifiableSolrParams(rb.req.getParams());
8585

86+
// TODO: should eventually all components that send sub-requests be subject to similar
87+
// logic if we are running with timeAllowed?
88+
int origTimeAllowed = sreq.params.getInt(CommonParams.TIME_ALLOWED, -1);
89+
if (origTimeAllowed > 0) {
90+
int remainingTimeAllowed = origTimeAllowed - rb.firstPhaseElapsedTime;
91+
// at least 1 ms to be useful
92+
if (remainingTimeAllowed <= 1) {
93+
// We've already used up our time budget
94+
rb.rsp.setPartialResults(rb.req);
95+
rb.rsp.addPartialResponseDetail(
96+
getClass().getSimpleName() + ": timeAllowed exhausted in first phase");
97+
return new ShardRequest[0];
98+
}
99+
sreq.params.set(CommonParams.TIME_ALLOWED, remainingTimeAllowed);
100+
}
101+
86102
// If group.format=simple group.offset doesn't make sense
87103
Grouping.Format responseFormat = rb.getGroupingSpec().getResponseFormat();
88104
if (responseFormat == Grouping.Format.simple || rb.getGroupingSpec().isMain()) {
@@ -132,12 +148,6 @@ private ShardRequest[] createRequest(ResponseBuilder rb, String[] shards) {
132148
sreq.params.set(CommonParams.FL, schema.getUniqueKeyField().getName());
133149
}
134150

135-
int origTimeAllowed = sreq.params.getInt(CommonParams.TIME_ALLOWED, -1);
136-
if (origTimeAllowed > 0) {
137-
sreq.params.set(
138-
CommonParams.TIME_ALLOWED, Math.max(1, origTimeAllowed - rb.firstPhaseElapsedTime));
139-
}
140-
141151
return new ShardRequest[] {sreq};
142152
}
143153
}

solr/core/src/test/org/apache/solr/TestDistributedGrouping.java

Lines changed: 94 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,13 @@
2828
import org.apache.solr.common.params.ModifiableSolrParams;
2929
import org.apache.solr.common.params.SolrParams;
3030
import org.apache.solr.common.util.NamedList;
31+
import org.apache.solr.handler.component.QueryComponent;
32+
import org.apache.solr.handler.component.ResponseBuilder;
33+
import org.apache.solr.handler.component.ShardRequest;
34+
import org.apache.solr.request.SolrQueryRequest;
35+
import org.apache.solr.response.SolrQueryResponse;
36+
import org.apache.solr.search.grouping.distributed.requestfactory.TopGroupsShardRequestFactory;
37+
import org.junit.BeforeClass;
3138
import org.junit.Test;
3239

3340
/**
@@ -39,6 +46,11 @@
3946
@SuppressPointFields(bugUrl = "https://issues.apache.org/jira/browse/SOLR-10844")
4047
public class TestDistributedGrouping extends BaseDistributedSearchTestCase {
4148

49+
@BeforeClass
50+
public static void beforeClass() throws Exception {
51+
initCore("solrconfig-delaying-component.xml", "schema.xml");
52+
}
53+
4254
public TestDistributedGrouping() {
4355
// SOLR-10844: Even with points suppressed, this test breaks if we (randomize) docvalues="true"
4456
// on trie fields?!?!?!!?
@@ -1251,19 +1263,48 @@ public void test() throws Exception {
12511263
for (String rows : new String[] {"10", "0"}) {
12521264
simpleQuery(
12531265
"q", "*:*", "group", "true", "group.field", i1, "group.ngroups", ngroups, "rows", rows);
1254-
simpleQuery(
1255-
"q",
1256-
"*:*",
1257-
"group",
1258-
"true",
1259-
"group.field",
1260-
i1,
1261-
"group.ngroups",
1262-
ngroups,
1263-
"rows",
1264-
rows,
1265-
"timeAllowed",
1266-
"123456");
1266+
// delaying component introduces a delay longer than timeAllowed
1267+
QueryResponse rsp =
1268+
simpleQuery(
1269+
"q",
1270+
t1 + ":eggs",
1271+
"group",
1272+
"true",
1273+
"group.field",
1274+
i1,
1275+
"group.ngroups",
1276+
ngroups,
1277+
"rows",
1278+
rows,
1279+
"cache",
1280+
"false",
1281+
"timeAllowed",
1282+
"200",
1283+
"sleep",
1284+
"300");
1285+
assertTrue(
1286+
"header: " + rsp.getHeader(), SolrQueryResponse.isPartialResults(rsp.getHeader()));
1287+
//
1288+
rsp =
1289+
simpleQuery(
1290+
"q",
1291+
t1 + ":eggs",
1292+
"group",
1293+
"true",
1294+
"group.field",
1295+
i1,
1296+
"group.ngroups",
1297+
ngroups,
1298+
"rows",
1299+
rows,
1300+
"cache",
1301+
"false",
1302+
"timeAllowed",
1303+
"200",
1304+
"sleep",
1305+
"10");
1306+
assertFalse(
1307+
"header: " + rsp.getHeader(), SolrQueryResponse.isPartialResults(rsp.getHeader()));
12671308
}
12681309
}
12691310

@@ -1650,13 +1691,51 @@ public void test() throws Exception {
16501691
"true");
16511692
}
16521693

1653-
private void simpleQuery(Object... queryParams) throws Exception {
1694+
@Test
1695+
public void testShardRequestFactory() throws Exception {
1696+
SolrQueryRequest req =
1697+
req(
1698+
"q",
1699+
"*:*",
1700+
"rows",
1701+
"100",
1702+
"fl",
1703+
"id," + i1,
1704+
"group",
1705+
"true",
1706+
"group.field",
1707+
i1,
1708+
"group.limit",
1709+
"-1",
1710+
"sort",
1711+
i1 + " asc, id asc",
1712+
"timeAllowed",
1713+
"200");
1714+
try {
1715+
SolrQueryResponse rsp = new SolrQueryResponse();
1716+
ResponseBuilder rb = new ResponseBuilder(req, rsp, List.of());
1717+
new QueryComponent().prepare(rb);
1718+
rb.setNeedDocSet(true);
1719+
1720+
TopGroupsShardRequestFactory f = new TopGroupsShardRequestFactory();
1721+
ShardRequest[] sreq = f.constructRequest(rb);
1722+
assertTrue(sreq.length > 0);
1723+
1724+
rb.firstPhaseElapsedTime = 200; // simulate timeout
1725+
sreq = f.constructRequest(rb);
1726+
assertEquals(0, sreq.length);
1727+
} finally {
1728+
req.close();
1729+
}
1730+
}
1731+
1732+
private QueryResponse simpleQuery(Object... queryParams) throws Exception {
16541733
ModifiableSolrParams params = new ModifiableSolrParams();
16551734
for (int i = 0; i < queryParams.length; i += 2) {
16561735
params.add(queryParams[i].toString(), queryParams[i + 1].toString());
16571736
}
16581737
params.set("shards", shards);
1659-
queryRandomShard(params);
1738+
return queryRandomShard(params);
16601739
}
16611740

16621741
/**

0 commit comments

Comments
 (0)