This is an automated email from the ASF dual-hosted git repository.
gerlowskija 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 a15e6f42785 SOLR-17413: ulog replay should copy SolrQueryRequest
(#2765)
a15e6f42785 is described below
commit a15e6f4278523f2a23ad35246fe7e34bf531e12f
Author: Jason Gerlowski <[email protected]>
AuthorDate: Mon Oct 28 11:12:18 2024 -0700
SOLR-17413: ulog replay should copy SolrQueryRequest (#2765)
SolrQueryRequest is a non-threadsafe type, but was being shared across
executor threads during UpdateLog replay. This introduces a number of
issues, not the least being a ConcurrentModificationException if
multiple threads happen to tweak the request 'context' simultaneously.
This commit fixes this issue by giving each executor thread a unique
LocalSolrQueryRequest instance to use.
---
solr/CHANGES.txt | 2 ++
.../src/java/org/apache/solr/update/UpdateLog.java | 19 ++++++++++++++-----
2 files changed, 16 insertions(+), 5 deletions(-)
diff --git a/solr/CHANGES.txt b/solr/CHANGES.txt
index f8dc0b18a98..7adc0afa5c8 100644
--- a/solr/CHANGES.txt
+++ b/solr/CHANGES.txt
@@ -81,6 +81,8 @@ Bug Fixes
* SOLR-17464: Fixed Http2SolrClient bug in that 'requestAsync' triggered NPE
when using a shared Jetty client (Jason Gerlowski, James Dyer)
+* SOLR-17413: Fixed UpdateLog replay bug that shared thread-unsafe
SolrQueryRequest objects across threads (Jason Gerlowski, David Smiley, Houston
Putman)
+
Dependency Upgrades
---------------------
(No changes)
diff --git a/solr/core/src/java/org/apache/solr/update/UpdateLog.java
b/solr/core/src/java/org/apache/solr/update/UpdateLog.java
index 9bc685f276b..d1c430bceee 100644
--- a/solr/core/src/java/org/apache/solr/update/UpdateLog.java
+++ b/solr/core/src/java/org/apache/solr/update/UpdateLog.java
@@ -63,6 +63,7 @@ import org.apache.solr.common.SolrDocumentBase;
import org.apache.solr.common.SolrException;
import org.apache.solr.common.SolrException.ErrorCode;
import org.apache.solr.common.SolrInputDocument;
+import org.apache.solr.common.params.MapSolrParams;
import org.apache.solr.common.params.ModifiableSolrParams;
import org.apache.solr.common.params.SolrParams;
import org.apache.solr.common.util.CollectionUtil;
@@ -1998,6 +1999,14 @@ public class UpdateLog implements PluginInfoInitialized,
SolrMetricProducer {
protected RecoveryInfo recoveryInfo;
class LogReplayer implements Runnable {
+ private final SolrParams BASE_REPLAY_PARAMS =
+ new MapSolrParams(
+ Map.of(
+ DISTRIB_UPDATE_PARAM,
+ FROMLEADER.toString(),
+ DistributedUpdateProcessor.LOG_REPLAY,
+ "true"));
+
private Logger loglog = log; // set to something different?
Deque<TransactionLog> translogs;
@@ -2024,10 +2033,7 @@ public class UpdateLog implements PluginInfoInitialized,
SolrMetricProducer {
@Override
public void run() {
- ModifiableSolrParams params = new ModifiableSolrParams();
- params.set(DISTRIB_UPDATE_PARAM, FROMLEADER.toString());
- params.set(DistributedUpdateProcessor.LOG_REPLAY, "true");
- req = new LocalSolrQueryRequest(uhandler.core, params);
+ req = new LocalSolrQueryRequest(uhandler.core, BASE_REPLAY_PARAMS);
rsp = new SolrQueryResponse();
// setting request info will help logging
SolrRequestInfo.setRequestInfo(new SolrRequestInfo(req, rsp));
@@ -2100,7 +2106,10 @@ public class UpdateLog implements PluginInfoInitialized,
SolrMetricProducer {
ThreadLocal<UpdateRequestProcessor> procThreadLocal =
ThreadLocal.withInitial(
() -> {
- var proc = processorChain.createProcessor(req, rsp);
+ // SolrQueryRequest is not thread-safe, so use a copy when
creating URPs
+ final var localRequest =
+ new LocalSolrQueryRequest(uhandler.core,
BASE_REPLAY_PARAMS);
+ var proc = processorChain.createProcessor(localRequest, rsp);
procPool.add(proc);
return proc;
});