This is an automated email from the ASF dual-hosted git repository.
sigram 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 a3ec45894b7 SOLR-18591: Don't double-count shard cpuTime on tolerant
partial failure (#5239)
a3ec45894b7 is described below
commit a3ec45894b72bacb8a5f35e2b7f96013503e51ab
Author: sarkaramrit1993 <[email protected]>
AuthorDate: Wed Oct 28 04:36:26 2026 -0700
SOLR-18591: Don't double-count shard cpuTime on tolerant partial failure
(#5239)
---
changelog/unreleased/SOLR-18591.yml | 7 ++
.../solr/handler/component/SearchHandler.java | 5 -
.../component/TolerantShardCpuTimeTest.java | 123 +++++++++++++++++++++
3 files changed, 130 insertions(+), 5 deletions(-)
diff --git a/changelog/unreleased/SOLR-18591.yml
b/changelog/unreleased/SOLR-18591.yml
new file mode 100644
index 00000000000..1be2c2fc1ba
--- /dev/null
+++ b/changelog/unreleased/SOLR-18591.yml
@@ -0,0 +1,7 @@
+title: "Distributed search with shards.tolerant no longer double-counts shard
cpuTime when a shard fails."
+type: fixed
+authors:
+ - name: Amrit Sarkar
+links:
+ - name: SOLR-18591
+ url: https://issues.apache.org/jira/browse/SOLR-18591
diff --git
a/solr/core/src/java/org/apache/solr/handler/component/SearchHandler.java
b/solr/core/src/java/org/apache/solr/handler/component/SearchHandler.java
index 76f62bd7ca9..0d768ef4517 100644
--- a/solr/core/src/java/org/apache/solr/handler/component/SearchHandler.java
+++ b/solr/core/src/java/org/apache/solr/handler/component/SearchHandler.java
@@ -667,11 +667,6 @@ public class SearchHandler extends RequestHandlerBase
throwSolrException(shardException.get());
} else {
rsp.setPartialResults(rb.req);
- if (publishCpuTime) {
- totalShardCpuTime +=
computeShardCpuTime(srsp.getShardRequest().responses);
- rsp.getResponseHeader().add(ThreadCpuTimer.CPU_TIME,
totalShardCpuTime);
- rsp.addToLog(ThreadCpuTimer.CPU_TIME, totalShardCpuTime);
- }
}
}
}
diff --git
a/solr/core/src/test/org/apache/solr/handler/component/TolerantShardCpuTimeTest.java
b/solr/core/src/test/org/apache/solr/handler/component/TolerantShardCpuTimeTest.java
new file mode 100644
index 00000000000..e8ff51645dc
--- /dev/null
+++
b/solr/core/src/test/org/apache/solr/handler/component/TolerantShardCpuTimeTest.java
@@ -0,0 +1,123 @@
+/*
+ * 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.solr.handler.component;
+
+import java.util.List;
+import org.apache.solr.client.solrj.request.CollectionAdminRequest;
+import org.apache.solr.client.solrj.request.SolrQuery;
+import org.apache.solr.client.solrj.request.UpdateRequest;
+import org.apache.solr.client.solrj.response.QueryResponse;
+import org.apache.solr.cloud.ConfigRequest;
+import org.apache.solr.cloud.SolrCloudTestCase;
+import org.apache.solr.common.SolrException;
+import org.apache.solr.common.cloud.DocCollection;
+import org.apache.solr.common.cloud.Slice;
+import org.apache.solr.common.params.ShardParams;
+import org.apache.solr.util.ThreadCpuTimer;
+import org.junit.BeforeClass;
+
+/** CPU time reported by a tolerant distributed search when one shard fails. */
+public class TolerantShardCpuTimeTest extends SolrCloudTestCase {
+
+ private static final String COLLECTION = "tolerant-cpu";
+ private static final String HANDLER = "/fixedcpu";
+ private static final String FAIL_SHARD_PARAM = "failShard";
+ private static final String DOC_ID = "1";
+ private static final long SHARD_CPU_MS = 1000L;
+
+ /** Reports a fixed shard cpuTime, or fails on the shard named by {@link
#FAIL_SHARD_PARAM}. */
+ public static class FixedCpuComponent extends SearchComponent {
+ @Override
+ public void prepare(ResponseBuilder rb) {}
+
+ @Override
+ public void process(ResponseBuilder rb) {
+ String shard =
rb.req.getCore().getCoreDescriptor().getCloudDescriptor().getShardId();
+ if (shard.equals(rb.req.getParams().get(FAIL_SHARD_PARAM))) {
+ throw new SolrException(SolrException.ErrorCode.SERVER_ERROR, "failing
" + shard);
+ }
+ rb.rsp.getResponseHeader().add(ThreadCpuTimer.CPU_TIME, SHARD_CPU_MS);
+ }
+
+ @Override
+ public String getDescription() {
+ return "fixed cpuTime";
+ }
+ }
+
+ @BeforeClass
+ public static void setupCluster() throws Exception {
+ System.setProperty(ThreadCpuTimer.ENABLE_CPU_TIME, "true");
+ configureCluster(2).addConfig("conf",
configset("cloud-dynamic")).configure();
+ CollectionAdminRequest.createCollection(COLLECTION, "conf", 2, 1)
+ .process(cluster.getSolrClient());
+ waitForState("collection", COLLECTION, clusterShape(2, 2));
+
+ cluster
+ .getSolrClient()
+ .request(
+ new ConfigRequest(
+ "{'add-searchcomponent': {'name': 'fixedcpu', 'class': '"
+ + FixedCpuComponent.class.getName()
+ + "'}}"),
+ COLLECTION);
+ cluster
+ .getSolrClient()
+ .request(
+ new ConfigRequest(
+ "{'add-requesthandler': {'name': '"
+ + HANDLER
+ + "', 'class': '"
+ + SearchHandler.class.getName()
+ + "', 'last-components': ['fixedcpu']}}"),
+ COLLECTION);
+
+ new UpdateRequest().add(sdoc("id",
DOC_ID)).commit(cluster.getSolrClient(), COLLECTION);
+ }
+
+ public void testSinglePass() throws Exception {
+ assertCpuTime(true, SHARD_CPU_MS);
+ }
+
+ public void testTwoPhase() throws Exception {
+ // the live shard gets a GET_TOP_IDS and a GET_FIELDS request
+ assertCpuTime(false, 2 * SHARD_CPU_MS);
+ }
+
+ private void assertCpuTime(boolean singlePass, long expected) throws
Exception {
+ DocCollection coll = getCollectionState(COLLECTION);
+ String liveShard = coll.getRouter().getTargetSlice(DOC_ID, null, null,
null, coll).getName();
+ String failShard =
+ coll.getSlices().stream()
+ .map(Slice::getName)
+ .filter(s -> !s.equals(liveShard))
+ .findFirst()
+ .orElseThrow();
+
+ SolrQuery query = new SolrQuery("*:*");
+ query.setRequestHandler(HANDLER);
+ query.set(ShardParams.SHARDS_TOLERANT, true);
+ query.set(ShardParams.DISTRIB_SINGLE_PASS, singlePass);
+ query.set(FAIL_SHARD_PARAM, failShard);
+
+ QueryResponse rsp = cluster.getSolrClient().query(COLLECTION, query);
+
+ assertEquals(1, rsp.getResults().getNumFound());
+ assertEquals(Boolean.TRUE, rsp.getHeader().get("partialResults"));
+ assertEquals(List.of(expected),
rsp.getHeader().getAll(ThreadCpuTimer.CPU_TIME));
+ }
+}