This is an automated email from the ASF dual-hosted git repository.
hossman pushed a commit to branch branch_9x
in repository https://gitbox.apache.org/repos/asf/solr.git
The following commit(s) were added to refs/heads/branch_9x by this push:
new 0897e7ed0bf SOLR-5386: Fix various methods of invoking "local" solr
requests to re-use the same searcher as the original request.
0897e7ed0bf is described below
commit 0897e7ed0bf8fb5504a7066527980d32c57c644a
Author: Chris Hostetter <[email protected]>
AuthorDate: Thu Apr 10 12:57:28 2025 -0700
SOLR-5386: Fix various methods of invoking "local" solr requests to re-use
the same searcher as the original request.
This notably fixes the use of spellcheck.maxCollationTries in firstSearcher
warming queries to prevent deadlock
(cherry picked from commit 17510244b214036ad9365019c5053c1711140da8)
---
solr/CHANGES.txt | 3 ++
.../org/apache/solr/core/QuerySenderListener.java | 12 +----
.../java/org/apache/solr/handler/BlobHandler.java | 3 +-
.../org/apache/solr/handler/SolrConfigHandler.java | 3 +-
.../org/apache/solr/request/SolrQueryRequest.java | 51 ++++++++++++++++++++++
.../org/apache/solr/request/SolrRequestInfo.java | 7 ++-
.../solr/search/CollapsingQParserPlugin.java | 3 +-
.../org/apache/solr/search/SolrIndexSearcher.java | 13 +-----
.../apache/solr/spelling/SpellCheckCollator.java | 3 +-
.../conf/solrconfig-spellcheckcomponent.xml | 21 +++++++--
.../handler/component/SpellCheckComponentTest.java | 12 +++++
11 files changed, 92 insertions(+), 39 deletions(-)
diff --git a/solr/CHANGES.txt b/solr/CHANGES.txt
index a010d2a4972..16eebdd079e 100644
--- a/solr/CHANGES.txt
+++ b/solr/CHANGES.txt
@@ -75,6 +75,9 @@ Bug Fixes
* SOLR-17692: Core unload/deletion now preempts all forms of ongoing
"recovery", rather than inadvertently waiting for
completion in some cases. (Jason Gerlowski)
+* SOLR-5386: Fix various methods of invoking "local" solr requests to re-use
the same searcher as the original request.
+ This notably fixes the use of spellcheck.maxCollationTries in firstSearcher
warming queries to prevent deadlock (hossman)
+
Dependency Upgrades
---------------------
* SOLR-17471: Upgrade Lucene to 9.12.1. (Pierre Salagnac, Christine Poerschke)
diff --git a/solr/core/src/java/org/apache/solr/core/QuerySenderListener.java
b/solr/core/src/java/org/apache/solr/core/QuerySenderListener.java
index a612b27809a..4857cadf101 100644
--- a/solr/core/src/java/org/apache/solr/core/QuerySenderListener.java
+++ b/solr/core/src/java/org/apache/solr/core/QuerySenderListener.java
@@ -23,7 +23,6 @@ import java.util.ArrayList;
import java.util.List;
import org.apache.solr.common.params.CommonParams;
import org.apache.solr.common.util.NamedList;
-import org.apache.solr.request.LocalSolrQueryRequest;
import org.apache.solr.request.SolrQueryRequest;
import org.apache.solr.request.SolrRequestInfo;
import org.apache.solr.response.ResultContext;
@@ -59,16 +58,7 @@ public class QuerySenderListener extends
AbstractSolrEventListener {
if (params.get(DISTRIB) == null) {
params.add(DISTRIB, false);
}
- SolrQueryRequest req =
- new LocalSolrQueryRequest(getCore(), params) {
- @Override
- public SolrIndexSearcher getSearcher() {
- return searcher;
- }
-
- @Override
- public void close() {}
- };
+ SolrQueryRequest req = SolrQueryRequest.wrapSearcher(searcher,
params.toSolrParams());
SolrQueryResponse rsp = new SolrQueryResponse();
SolrRequestInfo.setRequestInfo(new SolrRequestInfo(req, rsp));
try {
diff --git a/solr/core/src/java/org/apache/solr/handler/BlobHandler.java
b/solr/core/src/java/org/apache/solr/handler/BlobHandler.java
index 1db714553a4..37dffbeaceb 100644
--- a/solr/core/src/java/org/apache/solr/handler/BlobHandler.java
+++ b/solr/core/src/java/org/apache/solr/handler/BlobHandler.java
@@ -58,7 +58,6 @@ import org.apache.solr.core.SolrCore;
import org.apache.solr.handler.admin.api.GetBlobInfoAPI;
import org.apache.solr.handler.admin.api.ReplicationAPIBase;
import org.apache.solr.handler.admin.api.UploadBlobAPI;
-import org.apache.solr.request.LocalSolrQueryRequest;
import org.apache.solr.request.SolrQueryRequest;
import org.apache.solr.request.SolrRequestHandler;
import org.apache.solr.request.SolrRequestInfo;
@@ -330,7 +329,7 @@ public class BlobHandler extends RequestHandlerBase
// works OK for real-time get (which is all that BlobHandler uses it for).
private static void forward(
SolrQueryRequest req, String handler, SolrParams params,
SolrQueryResponse rsp) {
- LocalSolrQueryRequest r = new LocalSolrQueryRequest(req.getCore(), params);
+ SolrQueryRequest r = req.subRequest(params);
SolrRequestInfo.getRequestInfo().addCloseHook(r); // Close as late as
possible...
req.getCore().getRequestHandler(handler).handleRequest(r, rsp);
}
diff --git a/solr/core/src/java/org/apache/solr/handler/SolrConfigHandler.java
b/solr/core/src/java/org/apache/solr/handler/SolrConfigHandler.java
index 8a8a0da4425..2e82dd375f9 100644
--- a/solr/core/src/java/org/apache/solr/handler/SolrConfigHandler.java
+++ b/solr/core/src/java/org/apache/solr/handler/SolrConfigHandler.java
@@ -89,7 +89,6 @@ import
org.apache.solr.handler.admin.api.ModifyConfigComponentAPI;
import org.apache.solr.handler.admin.api.ModifyParamSetAPI;
import org.apache.solr.pkg.PackageAPI;
import org.apache.solr.pkg.PackageListeners;
-import org.apache.solr.request.LocalSolrQueryRequest;
import org.apache.solr.request.SolrQueryRequest;
import org.apache.solr.request.SolrRequestHandler;
import org.apache.solr.response.SolrQueryResponse;
@@ -372,7 +371,7 @@ public class SolrConfigHandler extends RequestHandlerBase
}
}
- LocalSolrQueryRequest r = new LocalSolrQueryRequest(req.getCore(),
req.getOriginalParams());
+ SolrQueryRequest r = req.subRequest(req.getOriginalParams());
r.getContext().put(USEPARAM, useParams);
NamedList<?> nl = new PluginInfo(SolrRequestHandler.TYPE,
pluginInfo).initArgs;
SolrPluginUtils.setDefaults(
diff --git a/solr/core/src/java/org/apache/solr/request/SolrQueryRequest.java
b/solr/core/src/java/org/apache/solr/request/SolrQueryRequest.java
index 4dfce550bc0..bf571619e3e 100644
--- a/solr/core/src/java/org/apache/solr/request/SolrQueryRequest.java
+++ b/solr/core/src/java/org/apache/solr/request/SolrQueryRequest.java
@@ -214,4 +214,55 @@ public interface SolrQueryRequest extends AutoCloseable {
wt, SolrCore.DEFAULT_RESPONSE_WRITERS.get("standard"));
}
}
+
+ /**
+ * Returns a new "Sub Request" of the current request.
+ *
+ * <p>This is useful in situations where some code handling an existing
request wishes to invoke a
+ * new request -- as if it came from the same user. The request returned
uses the same {@link
+ * #getSearcher} and {@link #getUserPrincipal} as the current request, and
is initialized using
+ * the same {@link #getSchema()} (but {@link #updateSchemaToLatest} is
handled independently for
+ * the two requests)
+ *
+ * <p>The behavior of a sub-request is undefined if the original request is
closed.
+ */
+ default SolrQueryRequest subRequest(final SolrParams params) {
+ final SolrQueryRequest outerRequest = this;
+ // NOTE: we explicitly do not use DelegatingSolrQueryRequest because we do
not want
+ // any existing (or future) "setter" methods to delegate to the
outerRequest
+ return new SolrQueryRequestBase(outerRequest.getCore(), params) {
+ { // super() implicitly uses core.getLatestSchema(), but we want
+ // whatever outerRequest is currently using
+ this.schema = outerRequest.getSchema();
+ }
+
+ @Override
+ public SolrIndexSearcher getSearcher() {
+ // We do not use/set this.searcherHolder, so that super.close() doesn't
+ // double close
+ return outerRequest.getSearcher();
+ }
+
+ @Override
+ public Principal getUserPrincipal() {
+ return outerRequest.getUserPrincipal();
+ }
+ };
+ }
+
+ /**
+ * Returns a request that explicitly uses the specified
<code>SolrIndexSearcher</code> (even if it
+ * is not registered or fully initialized) in conjunction with the
<code>SolrCore</code>
+ * identified via {@link SolrIndexSearcher#getCore}
+ */
+ static SolrQueryRequest wrapSearcher(final SolrIndexSearcher searcher, final
SolrParams params) {
+ return new SolrQueryRequestBase(searcher.getCore(), params) {
+ @Override
+ public SolrIndexSearcher getSearcher() {
+ // We do not use/set this.searcherHolder, so that super.close() doesn't
+ // double close
+ return searcher;
+ }
+ };
+ }
}
diff --git a/solr/core/src/java/org/apache/solr/request/SolrRequestInfo.java
b/solr/core/src/java/org/apache/solr/request/SolrRequestInfo.java
index 444867b430b..c30d6f2c29e 100644
--- a/solr/core/src/java/org/apache/solr/request/SolrRequestInfo.java
+++ b/solr/core/src/java/org/apache/solr/request/SolrRequestInfo.java
@@ -16,7 +16,6 @@
*/
package org.apache.solr.request;
-import java.io.Closeable;
import java.lang.invoke.MethodHandles;
import java.security.Principal;
import java.util.ArrayDeque;
@@ -55,7 +54,7 @@ public class SolrRequestInfo {
public HttpServletRequest httpRequest;
private TimeZone tz;
private ResponseBuilder rb;
- private List<Closeable> closeHooks;
+ private List<AutoCloseable> closeHooks;
private SolrDispatchFilter.Action action;
private boolean useServerToken = false;
@@ -138,7 +137,7 @@ public class SolrRequestInfo {
}
if (closeHooks != null) {
- for (Closeable hook : closeHooks) {
+ for (AutoCloseable hook : closeHooks) {
try {
hook.close();
} catch (Exception e) {
@@ -218,7 +217,7 @@ public class SolrRequestInfo {
this.rb = rb;
}
- public void addCloseHook(Closeable hook) {
+ public void addCloseHook(AutoCloseable hook) {
// is this better here, or on SolrQueryRequest?
synchronized (this) {
if (isClosed()) {
diff --git
a/solr/core/src/java/org/apache/solr/search/CollapsingQParserPlugin.java
b/solr/core/src/java/org/apache/solr/search/CollapsingQParserPlugin.java
index 221f2c8b06b..d4abe2d0d57 100644
--- a/solr/core/src/java/org/apache/solr/search/CollapsingQParserPlugin.java
+++ b/solr/core/src/java/org/apache/solr/search/CollapsingQParserPlugin.java
@@ -74,7 +74,6 @@ import org.apache.solr.common.params.SolrParams;
import org.apache.solr.common.util.StrUtils;
import org.apache.solr.handler.component.QueryElevationComponent;
import org.apache.solr.handler.component.ResponseBuilder;
-import org.apache.solr.request.LocalSolrQueryRequest;
import org.apache.solr.request.SolrQueryRequest;
import org.apache.solr.request.SolrRequestInfo;
import org.apache.solr.schema.FieldType;
@@ -2131,7 +2130,7 @@ public class CollapsingQParserPlugin extends
QParserPlugin {
minMaxFieldType = searcher.getSchema().getField(text).getType();
} else {
SolrParams params = new ModifiableSolrParams();
- try (SolrQueryRequest request = new
LocalSolrQueryRequest(searcher.getCore(), params)) {
+ try (SolrQueryRequest request =
SolrQueryRequest.wrapSearcher(searcher, params)) {
FunctionQParser functionQParser = new FunctionQParser(text, null,
null, request);
funcQuery = (FunctionQuery) functionQParser.parse();
} catch (SyntaxError e) {
diff --git a/solr/core/src/java/org/apache/solr/search/SolrIndexSearcher.java
b/solr/core/src/java/org/apache/solr/search/SolrIndexSearcher.java
index ec270103a1b..cd33360d221 100644
--- a/solr/core/src/java/org/apache/solr/search/SolrIndexSearcher.java
+++ b/solr/core/src/java/org/apache/solr/search/SolrIndexSearcher.java
@@ -109,7 +109,6 @@ import org.apache.solr.index.SlowCompositeReaderWrapper;
import org.apache.solr.metrics.MetricsMap;
import org.apache.solr.metrics.SolrMetricManager;
import org.apache.solr.metrics.SolrMetricsContext;
-import org.apache.solr.request.LocalSolrQueryRequest;
import org.apache.solr.request.SolrQueryRequest;
import org.apache.solr.request.SolrRequestInfo;
import org.apache.solr.response.SolrQueryResponse;
@@ -2539,17 +2538,7 @@ public class SolrIndexSearcher extends IndexSearcher
implements Closeable, SolrI
log.debug("autowarming [{}] from [{}]\n\t{}", this, old,
old.cacheList[i]);
}
- final SolrQueryRequest req =
- new LocalSolrQueryRequest(core, params) {
- @Override
- public SolrIndexSearcher getSearcher() {
- return SolrIndexSearcher.this;
- }
-
- @Override
- public void close() {}
- };
-
+ final SolrQueryRequest req =
SolrQueryRequest.wrapSearcher(SolrIndexSearcher.this, params);
final SolrQueryResponse rsp = new SolrQueryResponse();
SolrRequestInfo.setRequestInfo(new SolrRequestInfo(req, rsp));
try {
diff --git
a/solr/core/src/java/org/apache/solr/spelling/SpellCheckCollator.java
b/solr/core/src/java/org/apache/solr/spelling/SpellCheckCollator.java
index b65e7d115b2..fd5f465d098 100644
--- a/solr/core/src/java/org/apache/solr/spelling/SpellCheckCollator.java
+++ b/solr/core/src/java/org/apache/solr/spelling/SpellCheckCollator.java
@@ -36,7 +36,6 @@ import org.apache.solr.common.util.SimpleOrderedMap;
import org.apache.solr.handler.component.QueryComponent;
import org.apache.solr.handler.component.ResponseBuilder;
import org.apache.solr.handler.component.SearchComponent;
-import org.apache.solr.request.LocalSolrQueryRequest;
import org.apache.solr.response.SolrQueryResponse;
import org.apache.solr.search.QueryLimits;
import org.slf4j.Logger;
@@ -150,7 +149,7 @@ public class SpellCheckCollator {
// creating a request here... make sure to close it!
ResponseBuilder checkResponse =
new ResponseBuilder(
- new LocalSolrQueryRequest(ultimateResponse.req.getCore(),
params),
+ ultimateResponse.req.subRequest(params),
new SolrQueryResponse(),
Arrays.asList(queryComponent));
checkResponse.setQparser(ultimateResponse.getQparser());
diff --git
a/solr/core/src/test-files/solr/collection1/conf/solrconfig-spellcheckcomponent.xml
b/solr/core/src/test-files/solr/collection1/conf/solrconfig-spellcheckcomponent.xml
index 0253d91b804..0a92e46115b 100644
---
a/solr/core/src/test-files/solr/collection1/conf/solrconfig-spellcheckcomponent.xml
+++
b/solr/core/src/test-files/solr/collection1/conf/solrconfig-spellcheckcomponent.xml
@@ -28,11 +28,24 @@
<writeLockTimeout>1000</writeLockTimeout>
<commitLockTimeout>10000</commitLockTimeout>
<lockType>${solr.tests.lockType:single}</lockType>
- <query>
- <useColdSearcher>false</useColdSearcher>
- <maxWarmingSearchers>1</maxWarmingSearchers>
- </query>
</indexConfig>
+ <query>
+ <useColdSearcher>false</useColdSearcher>
+ <maxWarmingSearchers>1</maxWarmingSearchers>
+ <listener event="firstSearcher" class="solr.QuerySenderListener">
+ <arr name="queries">
+ <lst>
+ <str name="qt">/spellCheckCompRH</str>
+ <str name="q">documemtsss broens</str>
+ <str name="spellcheck">true</str>
+ <str name="spellcheck.dictionary">direct_lowerfilt</str>
+ <str name="spellcheck.collate">true</str>
+ <str name="spellcheck.maxCollations">10</str>
+ <str name="spellcheck.maxCollationTries">10</str>
+ </lst>
+ </arr>
+ </listener>
+ </query>
<requestHandler name="/select"
class="solr.SearchHandler"></requestHandler>
diff --git
a/solr/core/src/test/org/apache/solr/handler/component/SpellCheckComponentTest.java
b/solr/core/src/test/org/apache/solr/handler/component/SpellCheckComponentTest.java
index 4a0eda8e506..f3e64e6e7f1 100644
---
a/solr/core/src/test/org/apache/solr/handler/component/SpellCheckComponentTest.java
+++
b/solr/core/src/test/org/apache/solr/handler/component/SpellCheckComponentTest.java
@@ -643,4 +643,16 @@ public class SpellCheckComponentTest extends
SolrTestCaseJ4 {
assertNull(suggestions.get("suggestion"));
assertFalse((Boolean) spellCheck.get("correctlySpelled"));
}
+
+ @Test
+ public void testFirstSearcherWarming() throws Exception {
+
+ final long preRestart = h.getCore().withSearcher(s -> s.getOpenNanoTime());
+
+ h.reload();
+
+ try (SolrCore current = h.getCoreInc()) {
+ assertNotEquals(preRestart, (long) current.withSearcher(s ->
s.getOpenNanoTime()));
+ }
+ }
}