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

jdyer 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 f7757f96cd8 SOLR-17541: LBSolrClient implementations should agree on 
'getClient()' semantics (#2899)
f7757f96cd8 is described below

commit f7757f96cd8c297f061587cc3c1af521628b732f
Author: jdyer1 <[email protected]>
AuthorDate: Thu Oct 2 16:55:23 2025 -0500

    SOLR-17541: LBSolrClient implementations should agree on 'getClient()' 
semantics (#2899)
---
 solr/CHANGES.txt                                   |  5 +++
 .../apache/solr/core/HttpSolrClientProvider.java   |  3 +-
 .../org/apache/solr/update/UpdateShardHandler.java |  4 +--
 .../solr/client/solrj/impl/Http2SolrClient.java    | 40 +++++++++++++++++-----
 4 files changed, 40 insertions(+), 12 deletions(-)

diff --git a/solr/CHANGES.txt b/solr/CHANGES.txt
index d47d93b2d0a..d1ccfc79adb 100644
--- a/solr/CHANGES.txt
+++ b/solr/CHANGES.txt
@@ -76,6 +76,11 @@ Improvements
   authenticate in browser without a credentials prompt being displayed. The 
MultiAuthPlugin can now
   also be configured with a single plugin.
 
+* SOLR-17541: `LBHttp2SolrClient` now maintains a separate internal/delegate 
client per Solr Base URL.  Both `LBHttp2SolrClient` and `CloudHttp2SolrClient`
+  always create and manage these internal clients.  The ability for callers to 
provide a pre-built client is removed.  Callers may specify the internal client
+  details by providing an instance of either `Http2SolrClient.Builder` or 
`HttpJdkSolrClient.Builder`. (James Dyer)
+
+
 Optimizations
 ---------------------
 * SOLR-17568: The CLI bin/solr export tool now contacts the appropriate nodes 
directly for data instead of proxying through one.
diff --git 
a/solr/core/src/java/org/apache/solr/core/HttpSolrClientProvider.java 
b/solr/core/src/java/org/apache/solr/core/HttpSolrClientProvider.java
index 2bf25a896f6..2e0d348aa0f 100644
--- a/solr/core/src/java/org/apache/solr/core/HttpSolrClientProvider.java
+++ b/solr/core/src/java/org/apache/solr/core/HttpSolrClientProvider.java
@@ -16,7 +16,6 @@
  */
 package org.apache.solr.core;
 
-import java.util.List;
 import java.util.concurrent.TimeUnit;
 import org.apache.solr.client.solrj.impl.Http2SolrClient;
 import org.apache.solr.common.util.IOUtils;
@@ -44,7 +43,7 @@ final class HttpSolrClientProvider implements AutoCloseable {
     initializeMetrics(parentContext);
 
     Http2SolrClient.Builder httpClientBuilder =
-        new 
Http2SolrClient.Builder().withListenerFactory(List.of(trackHttpSolrMetrics));
+        new Http2SolrClient.Builder().addListenerFactory(trackHttpSolrMetrics);
 
     if (cfg != null) {
       httpClientBuilder
diff --git a/solr/core/src/java/org/apache/solr/update/UpdateShardHandler.java 
b/solr/core/src/java/org/apache/solr/update/UpdateShardHandler.java
index e214c0cc3a8..fbe642c7481 100644
--- a/solr/core/src/java/org/apache/solr/update/UpdateShardHandler.java
+++ b/solr/core/src/java/org/apache/solr/update/UpdateShardHandler.java
@@ -104,10 +104,12 @@ public class UpdateShardHandler implements SolrInfoBean {
     Http2SolrClient.Builder recoveryOnlyClientBuilder = new 
Http2SolrClient.Builder();
     if (cfg != null) {
       updateOnlyClientBuilder
+          .addListenerFactory(trackHttpSolrMetrics)
           .withConnectionTimeout(cfg.getDistributedConnectionTimeout(), 
TimeUnit.MILLISECONDS)
           .withIdleTimeout(cfg.getDistributedSocketTimeout(), 
TimeUnit.MILLISECONDS)
           .withMaxConnectionsPerHost(cfg.getMaxUpdateConnectionsPerHost());
       recoveryOnlyClientBuilder
+          .addListenerFactory(trackHttpSolrMetrics)
           .withConnectionTimeout(cfg.getDistributedConnectionTimeout(), 
TimeUnit.MILLISECONDS)
           .withIdleTimeout(cfg.getDistributedSocketTimeout(), 
TimeUnit.MILLISECONDS)
           .withRequestTimeout(Long.MAX_VALUE, TimeUnit.MILLISECONDS)
@@ -116,10 +118,8 @@ public class UpdateShardHandler implements SolrInfoBean {
 
     updateOnlyClientBuilder.withTheseParamNamesInTheUrl(urlParamNames);
     updateOnlyClient = updateOnlyClientBuilder.build();
-    updateOnlyClient.addListenerFactory(trackHttpSolrMetrics);
 
     recoveryOnlyClient = recoveryOnlyClientBuilder.build();
-    recoveryOnlyClient.addListenerFactory(trackHttpSolrMetrics);
 
     ThreadFactory recoveryThreadFactory = new 
SolrNamedThreadFactory("recoveryExecutor");
     if (cfg != null && cfg.getMaxRecoveryThreads() > 0) {
diff --git 
a/solr/solrj/src/java/org/apache/solr/client/solrj/impl/Http2SolrClient.java 
b/solr/solrj/src/java/org/apache/solr/client/solrj/impl/Http2SolrClient.java
index 1fe2b91eb83..d291283123a 100644
--- a/solr/solrj/src/java/org/apache/solr/client/solrj/impl/Http2SolrClient.java
+++ b/solr/solrj/src/java/org/apache/solr/client/solrj/impl/Http2SolrClient.java
@@ -113,7 +113,7 @@ public class Http2SolrClient extends HttpSolrClientBase {
 
   private final long idleTimeoutMillis;
 
-  private List<HttpListenerFactory> listenerFactory = new ArrayList<>();
+  private List<HttpListenerFactory> listenerFactory;
   protected AsyncTracker asyncTracker = new AsyncTracker();
 
   private final boolean closeClient;
@@ -154,9 +154,12 @@ public class Http2SolrClient extends HttpSolrClientBase {
     }
     // note: do not manipulate httpClient below this point; it could be a 
shared instance
 
-    if (builder.listenerFactory != null) {
-      this.listenerFactory.addAll(builder.listenerFactory);
+    if (builder.listenerFactories != null) {
+      this.listenerFactory = builder.listenerFactories;
+    } else {
+      this.listenerFactory = new ArrayList<>(0);
     }
+
     updateDefaultMimeTypeForParser();
     this.idleTimeoutMillis = builder.getIdleTimeoutMillis();
 
@@ -958,7 +961,7 @@ public class Http2SolrClient extends HttpSolrClientBase {
 
     protected Long keyStoreReloadIntervalSecs;
 
-    private List<HttpListenerFactory> listenerFactory;
+    private List<HttpListenerFactory> listenerFactories;
 
     public Builder() {
       super();
@@ -984,8 +987,29 @@ public class Http2SolrClient extends HttpSolrClientBase {
       this.baseSolrUrl = baseSolrUrl;
     }
 
-    public Http2SolrClient.Builder 
withListenerFactory(List<HttpListenerFactory> listenerFactory) {
-      this.listenerFactory = listenerFactory;
+    /**
+     * specify a listener factory, which will be appended to any existing 
values.
+     *
+     * @param listenerFactory a HttpListenerFactory
+     * @return This Builder
+     */
+    public Http2SolrClient.Builder addListenerFactory(HttpListenerFactory 
listenerFactory) {
+      if (this.listenerFactories == null) {
+        this.listenerFactories = new ArrayList<>(1);
+      }
+      this.listenerFactories.add(listenerFactory);
+      return this;
+    }
+
+    /**
+     * Specify listener factories, which will replace any existing values.
+     *
+     * @param listenerFactories a list of HttpListenerFactory instances
+     * @return This Builder
+     */
+    public Http2SolrClient.Builder withListenerFactories(
+        List<HttpListenerFactory> listenerFactories) {
+      this.listenerFactories = listenerFactories;
       return this;
     }
 
@@ -1103,8 +1127,8 @@ public class Http2SolrClient extends HttpSolrClientBase {
       if (this.urlParamNames == null) {
         this.urlParamNames = http2SolrClient.urlParamNames;
       }
-      if (this.listenerFactory == null) {
-        this.listenerFactory = new 
ArrayList<>(http2SolrClient.listenerFactory);
+      if (this.listenerFactories == null) {
+        this.listenerFactories = http2SolrClient.listenerFactory;
       }
       if (this.executor == null) {
         this.executor = http2SolrClient.executor;

Reply via email to