This is an automated email from the ASF dual-hosted git repository. jdyer pushed a commit to branch feature/SOLR-17516-c in repository https://gitbox.apache.org/repos/asf/solr.git
commit 898977a183c08db3ca241a54dd3ca925f0e10448 Author: jdyer1 <[email protected]> AuthorDate: Thu Oct 31 08:29:24 2024 -0500 Make LBHttp2SolrClient Generic --- .../solr/handler/component/HttpShardHandler.java | 3 +- .../handler/component/HttpShardHandlerFactory.java | 4 +- .../client/solrj/impl/CloudHttp2SolrClient.java | 6 +- .../solr/client/solrj/impl/Http2SolrClient.java | 4 - .../solr/client/solrj/impl/HttpSolrClientBase.java | 4 + .../solr/client/solrj/impl/LBHttp2SolrClient.java | 172 +++++++++++---------- .../impl/LBHttp2SolrClientIntegrationTest.java | 53 +++---- .../client/solrj/impl/LBHttp2SolrClientTest.java | 12 +- 8 files changed, 132 insertions(+), 126 deletions(-) diff --git a/solr/core/src/java/org/apache/solr/handler/component/HttpShardHandler.java b/solr/core/src/java/org/apache/solr/handler/component/HttpShardHandler.java index 219197d8cd8..7592eed86fc 100644 --- a/solr/core/src/java/org/apache/solr/handler/component/HttpShardHandler.java +++ b/solr/core/src/java/org/apache/solr/handler/component/HttpShardHandler.java @@ -31,6 +31,7 @@ import java.util.function.BiConsumer; import net.jcip.annotations.NotThreadSafe; import org.apache.solr.client.solrj.SolrRequest; import org.apache.solr.client.solrj.SolrResponse; +import org.apache.solr.client.solrj.impl.Http2SolrClient; import org.apache.solr.client.solrj.impl.LBHttp2SolrClient; import org.apache.solr.client.solrj.impl.LBSolrClient; import org.apache.solr.client.solrj.request.QueryRequest; @@ -113,7 +114,7 @@ public class HttpShardHandler extends ShardHandler { protected AtomicInteger pending; private final Map<String, List<String>> shardToURLs; - protected LBHttp2SolrClient lbClient; + protected LBHttp2SolrClient<Http2SolrClient> lbClient; public HttpShardHandler(HttpShardHandlerFactory httpShardHandlerFactory) { this.httpShardHandlerFactory = httpShardHandlerFactory; diff --git a/solr/core/src/java/org/apache/solr/handler/component/HttpShardHandlerFactory.java b/solr/core/src/java/org/apache/solr/handler/component/HttpShardHandlerFactory.java index 2bfc4cb236a..ac7dc0cf8e0 100644 --- a/solr/core/src/java/org/apache/solr/handler/component/HttpShardHandlerFactory.java +++ b/solr/core/src/java/org/apache/solr/handler/component/HttpShardHandlerFactory.java @@ -84,7 +84,7 @@ public class HttpShardHandlerFactory extends ShardHandlerFactory protected volatile Http2SolrClient defaultClient; protected InstrumentedHttpListenerFactory httpListenerFactory; - protected LBHttp2SolrClient loadbalancer; + protected LBHttp2SolrClient<Http2SolrClient> loadbalancer; int corePoolSize = 0; int maximumPoolSize = Integer.MAX_VALUE; @@ -314,7 +314,7 @@ public class HttpShardHandlerFactory extends ShardHandlerFactory .withMaxConnectionsPerHost(maxConnectionsPerHost) .build(); this.defaultClient.addListenerFactory(this.httpListenerFactory); - this.loadbalancer = new LBHttp2SolrClient.Builder(defaultClient).build(); + this.loadbalancer = new LBHttp2SolrClient.Builder<Http2SolrClient>(defaultClient).build(); initReplicaListTransformers(getParameter(args, "replicaRouting", null, sb)); diff --git a/solr/solrj/src/java/org/apache/solr/client/solrj/impl/CloudHttp2SolrClient.java b/solr/solrj/src/java/org/apache/solr/client/solrj/impl/CloudHttp2SolrClient.java index f45945ae045..ec66c1f636f 100644 --- a/solr/solrj/src/java/org/apache/solr/client/solrj/impl/CloudHttp2SolrClient.java +++ b/solr/solrj/src/java/org/apache/solr/client/solrj/impl/CloudHttp2SolrClient.java @@ -40,7 +40,7 @@ import org.apache.solr.common.SolrException; public class CloudHttp2SolrClient extends CloudSolrClient { private final ClusterStateProvider stateProvider; - private final LBHttp2SolrClient lbClient; + private final LBHttp2SolrClient<Http2SolrClient> lbClient; private final Http2SolrClient myClient; private final boolean clientIsInternal; @@ -76,7 +76,7 @@ public class CloudHttp2SolrClient extends CloudSolrClient { // locks. this.locks = objectList(builder.parallelCacheRefreshesLocks); - this.lbClient = new LBHttp2SolrClient.Builder(myClient).build(); + this.lbClient = new LBHttp2SolrClient.Builder<Http2SolrClient>(myClient).build(); } private Http2SolrClient createOrGetHttpClientFromBuilder(Builder builder) { @@ -142,7 +142,7 @@ public class CloudHttp2SolrClient extends CloudSolrClient { } @Override - public LBHttp2SolrClient getLbClient() { + public LBHttp2SolrClient<Http2SolrClient> getLbClient() { return lbClient; } 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 c35e11cf491..00e91c514bd 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 @@ -821,10 +821,6 @@ public class Http2SolrClient extends HttpSolrClientBase { .collect(Collectors.joining(", ")); } - protected RequestWriter getRequestWriter() { - return requestWriter; - } - /** * An Http2SolrClient that doesn't close or cleanup any resources * diff --git a/solr/solrj/src/java/org/apache/solr/client/solrj/impl/HttpSolrClientBase.java b/solr/solrj/src/java/org/apache/solr/client/solrj/impl/HttpSolrClientBase.java index 244fcb4c7b9..a2618c53649 100644 --- a/solr/solrj/src/java/org/apache/solr/client/solrj/impl/HttpSolrClientBase.java +++ b/solr/solrj/src/java/org/apache/solr/client/solrj/impl/HttpSolrClientBase.java @@ -120,6 +120,10 @@ public abstract class HttpSolrClientBase extends SolrClient { return solrRequest.getResponseParser() == null ? this.parser : solrRequest.getResponseParser(); } + protected RequestWriter getRequestWriter() { + return requestWriter; + } + // TODO: Remove this for 10.0, there is a typo in the method name @Deprecated(since = "9.8", forRemoval = true) protected ModifiableSolrParams initalizeSolrParams( diff --git a/solr/solrj/src/java/org/apache/solr/client/solrj/impl/LBHttp2SolrClient.java b/solr/solrj/src/java/org/apache/solr/client/solrj/impl/LBHttp2SolrClient.java index e6633aff4d5..12db741d231 100644 --- a/solr/solrj/src/java/org/apache/solr/client/solrj/impl/LBHttp2SolrClient.java +++ b/solr/solrj/src/java/org/apache/solr/client/solrj/impl/LBHttp2SolrClient.java @@ -95,12 +95,14 @@ import org.slf4j.MDC; * * @since solr 8.0 */ -public class LBHttp2SolrClient extends LBSolrClient { - private final Http2SolrClient solrClient; +public class LBHttp2SolrClient<C extends HttpSolrClientBase> extends LBSolrClient { - private LBHttp2SolrClient(Builder builder) { + protected final C solrClient; + + @SuppressWarnings("unchecked") + protected LBHttp2SolrClient(Builder<?> builder) { super(Arrays.asList(builder.solrEndpoints)); - this.solrClient = builder.http2SolrClient; + this.solrClient = (C) builder.solrClient; this.aliveCheckIntervalMillis = builder.aliveCheckIntervalMillis; this.defaultCollection = builder.defaultCollection; } @@ -138,59 +140,59 @@ public class LBHttp2SolrClient extends LBSolrClient { CompletableFuture<Rsp> apiFuture = new CompletableFuture<>(); Rsp rsp = new Rsp(); boolean isNonRetryable = - req.request instanceof IsUpdateRequest || ADMIN_PATHS.contains(req.request.getPath()); + req.request instanceof IsUpdateRequest || ADMIN_PATHS.contains(req.request.getPath()); EndpointIterator it = new EndpointIterator(req, zombieServers); AtomicReference<CompletableFuture<NamedList<Object>>> currentFuture = new AtomicReference<>(); RetryListener retryListener = - new RetryListener() { - - @Override - public void onSuccess(Rsp rsp) { - apiFuture.complete(rsp); - } + new RetryListener() { - @Override - public void onFailure(Exception e, boolean retryReq) { - if (retryReq) { - Endpoint url; - try { - url = it.nextOrError(e); - } catch (SolrServerException ex) { - apiFuture.completeExceptionally(e); - return; + @Override + public void onSuccess(Rsp rsp) { + apiFuture.complete(rsp); } - MDC.put("LBSolrClient.url", url.toString()); - if (!apiFuture.isCancelled()) { - CompletableFuture<NamedList<Object>> future = - doAsyncRequest(url, req, rsp, isNonRetryable, it.isServingZombieServer(), this); - currentFuture.set(future); + + @Override + public void onFailure(Exception e, boolean retryReq) { + if (retryReq) { + Endpoint url; + try { + url = it.nextOrError(e); + } catch (SolrServerException ex) { + apiFuture.completeExceptionally(e); + return; + } + MDC.put("LBSolrClient.url", url.toString()); + if (!apiFuture.isCancelled()) { + CompletableFuture<NamedList<Object>> future = + doAsyncRequest(url, req, rsp, isNonRetryable, it.isServingZombieServer(), this); + currentFuture.set(future); + } + } else { + apiFuture.completeExceptionally(e); + } } - } else { - apiFuture.completeExceptionally(e); - } - } - }; + }; try { CompletableFuture<NamedList<Object>> future = - doAsyncRequest( - it.nextOrError(), - req, - rsp, - isNonRetryable, - it.isServingZombieServer(), - retryListener); + doAsyncRequest( + it.nextOrError(), + req, + rsp, + isNonRetryable, + it.isServingZombieServer(), + retryListener); currentFuture.set(future); } catch (SolrServerException e) { apiFuture.completeExceptionally(e); return apiFuture; } apiFuture.exceptionally( - (error) -> { - if (apiFuture.isCancelled()) { - currentFuture.get().cancel(true); - } - return null; - }); + (error) -> { + if (apiFuture.isCancelled()) { + currentFuture.get().cancel(true); + } + return null; + }); return apiFuture; } @@ -201,34 +203,34 @@ public class LBHttp2SolrClient extends LBSolrClient { } private CompletableFuture<NamedList<Object>> doAsyncRequest( - Endpoint endpoint, - Req req, - Rsp rsp, - boolean isNonRetryable, - boolean isZombie, - RetryListener listener) { + Endpoint endpoint, + Req req, + Rsp rsp, + boolean isNonRetryable, + boolean isZombie, + RetryListener listener) { String baseUrl = endpoint.toString(); rsp.server = baseUrl; req.getRequest().setBasePath(baseUrl); CompletableFuture<NamedList<Object>> future = - ((Http2SolrClient) getClient(endpoint)).requestAsync(req.getRequest()); + ((HttpSolrClientBase) getClient(endpoint)).requestAsync(req.getRequest()); future.whenComplete( - (result, throwable) -> { - if (!future.isCompletedExceptionally()) { - onSuccessfulRequest(result, endpoint, rsp, isZombie, listener); - } else if (!future.isCancelled()) { - onFailedRequest(throwable, endpoint, isNonRetryable, isZombie, listener); - } - }); + (result, throwable) -> { + if (!future.isCompletedExceptionally()) { + onSuccessfulRequest(result, endpoint, rsp, isZombie, listener); + } else if (!future.isCancelled()) { + onFailedRequest(throwable, endpoint, isNonRetryable, isZombie, listener); + } + }); return future; } private void onSuccessfulRequest( - NamedList<Object> result, - Endpoint endpoint, - Rsp rsp, - boolean isZombie, - RetryListener listener) { + NamedList<Object> result, + Endpoint endpoint, + Rsp rsp, + boolean isZombie, + RetryListener listener) { rsp.rsp = result; if (isZombie) { zombieServers.remove(endpoint.toString()); @@ -237,11 +239,11 @@ public class LBHttp2SolrClient extends LBSolrClient { } private void onFailedRequest( - Throwable oe, - Endpoint endpoint, - boolean isNonRetryable, - boolean isZombie, - RetryListener listener) { + Throwable oe, + Endpoint endpoint, + boolean isNonRetryable, + boolean isZombie, + RetryListener listener) { try { throw (Exception) oe; } catch (BaseHttpSolrClient.RemoteExecutionException e) { @@ -283,17 +285,19 @@ public class LBHttp2SolrClient extends LBSolrClient { listener.onFailure(new SolrServerException(e), false); } } - - public static class Builder { - - private final Http2SolrClient http2SolrClient; - private final Endpoint[] solrEndpoints; - private long aliveCheckIntervalMillis = - TimeUnit.MILLISECONDS.convert(60, TimeUnit.SECONDS); // 1 minute between checks + public static class Builder<C extends HttpSolrClientBase> { + final C solrClient; + protected final LBSolrClient.Endpoint[] solrEndpoints; + long aliveCheckIntervalMillis = + TimeUnit.MILLISECONDS.convert(60, TimeUnit.SECONDS); // 1 minute between checks protected String defaultCollection; - public Builder(Http2SolrClient http2Client, Endpoint... endpoints) { - this.http2SolrClient = http2Client; + public LBHttp2SolrClient<C> build() { + return new LBHttp2SolrClient<C>(this); + } + + public Builder(C http2Client, LBSolrClient.Endpoint... endpoints) { + this.solrClient = http2Client; this.solrEndpoints = endpoints; } @@ -303,23 +307,23 @@ public class LBHttp2SolrClient extends LBSolrClient { * * @param aliveCheckInterval how often to ping for aliveness */ - public LBHttp2SolrClient.Builder setAliveCheckInterval(int aliveCheckInterval, TimeUnit unit) { + @SuppressWarnings("unchecked") + public Builder<C> setAliveCheckInterval(int aliveCheckInterval, TimeUnit unit) { if (aliveCheckInterval <= 0) { throw new IllegalArgumentException( - "Alive check interval must be " + "positive, specified value = " + aliveCheckInterval); + "Alive check interval must be " + "positive, specified value = " + aliveCheckInterval); } this.aliveCheckIntervalMillis = TimeUnit.MILLISECONDS.convert(aliveCheckInterval, unit); return this; } - /** Sets a default for core or collection based requests. */ - public LBHttp2SolrClient.Builder withDefaultCollection(String defaultCoreOrCollection) { + /** + * Sets a default for core or collection based requests. + */ + @SuppressWarnings("unchecked") + public Builder<C> withDefaultCollection(String defaultCoreOrCollection) { this.defaultCollection = defaultCoreOrCollection; return this; } - - public LBHttp2SolrClient build() { - return new LBHttp2SolrClient(this); - } } } diff --git a/solr/solrj/src/test/org/apache/solr/client/solrj/impl/LBHttp2SolrClientIntegrationTest.java b/solr/solrj/src/test/org/apache/solr/client/solrj/impl/LBHttp2SolrClientIntegrationTest.java index b13882d53b4..58ad81ac956 100644 --- a/solr/solrj/src/test/org/apache/solr/client/solrj/impl/LBHttp2SolrClientIntegrationTest.java +++ b/solr/solrj/src/test/org/apache/solr/client/solrj/impl/LBHttp2SolrClientIntegrationTest.java @@ -16,32 +16,11 @@ */ package org.apache.solr.client.solrj.impl; -import java.io.File; -import java.io.IOException; -import java.io.UncheckedIOException; -import java.lang.invoke.MethodHandles; -import java.net.Socket; -import java.nio.file.Files; -import java.nio.file.Path; -import java.security.cert.CertificateException; -import java.security.cert.X509Certificate; -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; -import java.util.Properties; -import java.util.Set; -import java.util.concurrent.TimeUnit; -import javax.net.ssl.SSLEngine; -import javax.net.ssl.TrustManager; -import javax.net.ssl.X509ExtendedTrustManager; import org.apache.lucene.util.IOUtils; import org.apache.solr.SolrTestCaseJ4; import org.apache.solr.client.solrj.SolrClient; import org.apache.solr.client.solrj.SolrQuery; import org.apache.solr.client.solrj.SolrServerException; -import org.apache.solr.client.solrj.impl.Http2SolrClient; -import org.apache.solr.client.solrj.impl.LBHttp2SolrClient; -import org.apache.solr.client.solrj.impl.LBSolrClient; import org.apache.solr.client.solrj.response.QueryResponse; import org.apache.solr.client.solrj.response.SolrResponseBase; import org.apache.solr.common.SolrInputDocument; @@ -54,6 +33,25 @@ import org.junit.BeforeClass; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import javax.net.ssl.SSLEngine; +import javax.net.ssl.TrustManager; +import javax.net.ssl.X509ExtendedTrustManager; +import java.io.File; +import java.io.IOException; +import java.io.UncheckedIOException; +import java.lang.invoke.MethodHandles; +import java.net.Socket; +import java.nio.file.Files; +import java.nio.file.Path; +import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Properties; +import java.util.Set; +import java.util.concurrent.TimeUnit; + /** * Test for LBHttp2SolrClient * @@ -131,7 +129,8 @@ public class LBHttp2SolrClientIntegrationTest extends SolrTestCaseJ4 { .withConnectionTimeout(1000, TimeUnit.MILLISECONDS) .withIdleTimeout(2000, TimeUnit.MILLISECONDS) .build(); - var lbClient = new LBHttp2SolrClient.Builder(delegateClient, baseSolrEndpoints) + var lbClient = + new LBHttp2SolrClient.Builder<>(delegateClient, baseSolrEndpoints) .withDefaultCollection(solr[0].getDefaultCollection()) .setAliveCheckInterval(500, TimeUnit.MILLISECONDS) .build(); @@ -142,7 +141,8 @@ public class LBHttp2SolrClientIntegrationTest extends SolrTestCaseJ4 { .withIdleTimeout(2000, TimeUnit.MILLISECONDS) .withSSLContext(MockTrustManager.ALL_TRUSTING_SSL_CONTEXT) .build(); - var lbClient = new LBHttpJdkSolrClient.Builder(delegateClient, baseSolrEndpoints) + var lbClient = + new LBHttp2SolrClient.Builder<>(delegateClient, baseSolrEndpoints) .withDefaultCollection(solr[0].getDefaultCollection()) .setAliveCheckInterval(500, TimeUnit.MILLISECONDS) .build(); @@ -240,7 +240,8 @@ public class LBHttp2SolrClientIntegrationTest extends SolrTestCaseJ4 { // wait maximum ms for serverName to come back up private void waitForServer( - int maxSeconds, LBHttpSolrClientBase<?> client, int nServers, String serverName) throws Exception { + int maxSeconds, LBHttp2SolrClient<?> client, int nServers, String serverName) + throws Exception { final TimeOut timeout = new TimeOut(maxSeconds, TimeUnit.SECONDS, TimeSource.NANO_TIME); while (!timeout.hasTimedOut()) { QueryResponse resp; @@ -360,10 +361,10 @@ public class LBHttp2SolrClientIntegrationTest extends SolrTestCaseJ4 { private static class LBClientHolder implements AutoCloseable { - final LBHttpSolrClientBase<?> lbClient; + final LBHttp2SolrClient<?> lbClient; final HttpSolrClientBase delegate; - LBClientHolder(LBHttpSolrClientBase<?> lbClient, HttpSolrClientBase delegate) { + LBClientHolder(LBHttp2SolrClient<?> lbClient, HttpSolrClientBase delegate) { this.lbClient = lbClient; this.delegate = delegate; } diff --git a/solr/solrj/src/test/org/apache/solr/client/solrj/impl/LBHttp2SolrClientTest.java b/solr/solrj/src/test/org/apache/solr/client/solrj/impl/LBHttp2SolrClientTest.java index 63ccd04b814..790c17af8bf 100644 --- a/solr/solrj/src/test/org/apache/solr/client/solrj/impl/LBHttp2SolrClientTest.java +++ b/solr/solrj/src/test/org/apache/solr/client/solrj/impl/LBHttp2SolrClientTest.java @@ -52,8 +52,8 @@ public class LBHttp2SolrClientTest extends SolrTestCase { try (Http2SolrClient http2SolrClient = new Http2SolrClient.Builder(url).withTheseParamNamesInTheUrl(urlParamNames).build(); - LBHttp2SolrClient testClient = - new LBHttp2SolrClient.Builder(http2SolrClient, new LBSolrClient.Endpoint(url)) + LBHttp2SolrClient<Http2SolrClient> testClient = + new LBHttp2SolrClient.Builder<>(http2SolrClient, new LBSolrClient.Endpoint(url)) .build()) { assertArrayEquals( @@ -77,7 +77,7 @@ public class LBHttp2SolrClientTest extends SolrTestCase { new Http2SolrClient.Builder("http://base.url").withConnectionTimeout(10, TimeUnit.SECONDS); ; try (MockHttpSolrClient client = new MockHttpSolrClient("http://base.url", b); - LBHttp2SolrClient testClient = new LBHttp2SolrClient.Builder(client, ep1, ep2).build()) { + LBHttp2SolrClient<MockHttpSolrClient> testClient = new LBHttp2SolrClient.Builder<>(client, ep1, ep2).build()) { String lastEndpoint = null; for (int i = 0; i < 10; i++) { @@ -105,7 +105,7 @@ public class LBHttp2SolrClientTest extends SolrTestCase { new Http2SolrClient.Builder("http://base.url").withConnectionTimeout(10, TimeUnit.SECONDS); ; try (MockHttpSolrClient client = new MockHttpSolrClient("http://base.url", b); - LBHttp2SolrClient testClient = new LBHttp2SolrClient.Builder(client, ep1, ep2).build()) { + LBHttp2SolrClient<MockHttpSolrClient> testClient = new LBHttp2SolrClient.Builder<>(client, ep1, ep2).build()) { client.basePathToFail = ep1.getBaseUrl(); String basePathToSucceed = ep2.getBaseUrl(); @@ -163,7 +163,7 @@ public class LBHttp2SolrClientTest extends SolrTestCase { new Http2SolrClient.Builder("http://base.url").withConnectionTimeout(10, TimeUnit.SECONDS); ; try (MockHttpSolrClient client = new MockHttpSolrClient("http://base.url", b); - LBHttp2SolrClient testClient = new LBHttp2SolrClient.Builder(client, ep1, ep2).build()) { + LBHttp2SolrClient<MockHttpSolrClient> testClient = new LBHttp2SolrClient.Builder<>(client, ep1, ep2).build()) { for (int j = 0; j < 2; j++) { // first time Endpoint One will return error code 500. @@ -226,7 +226,7 @@ public class LBHttp2SolrClientTest extends SolrTestCase { Http2SolrClient.Builder b = new Http2SolrClient.Builder("http://base.url").withConnectionTimeout(10, TimeUnit.SECONDS); try (MockHttpSolrClient client = new MockHttpSolrClient("http://base.url", b); - LBHttp2SolrClient testClient = new LBHttp2SolrClient.Builder(client, ep1, ep2).build()) { + LBHttp2SolrClient<MockHttpSolrClient> testClient = new LBHttp2SolrClient.Builder<>(client, ep1, ep2).build()) { int limit = 10; // For simplicity use an even limit List<CompletableFuture<LBSolrClient.Rsp>> responses = new ArrayList<>();
