From 3f3a75e8a1983bc754307337916d6e9f9fcf6316 Mon Sep 17 00:00:00 2001 From: Sanjay Dutt Date: Mon, 2 Sep 2024 22:00:54 +0530 Subject: [PATCH 01/26] introducing new home for Default solr client --- .../org/apache/solr/core/CoreContainer.java | 6 +- .../solr/core/ServerSolrClientCache.java | 68 +++++++++++++++++++ .../security/PKIAuthenticationPlugin.java | 42 +++++++----- .../solr/client/solrj/io/SolrClientCache.java | 12 ++-- 4 files changed, 106 insertions(+), 22 deletions(-) create mode 100644 solr/core/src/java/org/apache/solr/core/ServerSolrClientCache.java diff --git a/solr/core/src/java/org/apache/solr/core/CoreContainer.java b/solr/core/src/java/org/apache/solr/core/CoreContainer.java index 57370af1f18..d8573a83ff4 100644 --- a/solr/core/src/java/org/apache/solr/core/CoreContainer.java +++ b/solr/core/src/java/org/apache/solr/core/CoreContainer.java @@ -652,6 +652,10 @@ public Lookup getAuthSchemeRegistry() { pkiAuthenticationSecurityBuilder.getHttpClientBuilder(HttpClientUtil.getHttpClientBuilder()); shardHandlerFactory.setSecurityBuilder(pkiAuthenticationSecurityBuilder); updateShardHandler.setSecurityBuilder(pkiAuthenticationSecurityBuilder); + if (solrClientCache instanceof ServerSolrClientCache) { + ServerSolrClientCache serverSolrClientCache = (ServerSolrClientCache) solrClientCache; + serverSolrClientCache.setSecurityBuilder(pkiAuthenticationSecurityBuilder); + } } } @@ -837,7 +841,7 @@ private void loadInternal() { updateShardHandler = new UpdateShardHandler(cfg.getUpdateShardHandlerConfig()); updateShardHandler.initializeMetrics(solrMetricsContext, "updateShardHandler"); - solrClientCache = new SolrClientCache(updateShardHandler.getDefaultHttpClient()); + solrClientCache = new ServerSolrClientCache(updateShardHandler.getDefaultHttpClient()); Map cachesConfig = cfg.getCachesConfig(); if (cachesConfig.isEmpty()) { diff --git a/solr/core/src/java/org/apache/solr/core/ServerSolrClientCache.java b/solr/core/src/java/org/apache/solr/core/ServerSolrClientCache.java new file mode 100644 index 00000000000..be113a892ce --- /dev/null +++ b/solr/core/src/java/org/apache/solr/core/ServerSolrClientCache.java @@ -0,0 +1,68 @@ +/* + * 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.core; + +import java.util.List; +import java.util.concurrent.TimeUnit; +import org.apache.http.client.HttpClient; +import org.apache.solr.client.solrj.SolrClient; +import org.apache.solr.client.solrj.impl.Http2SolrClient; +import org.apache.solr.client.solrj.io.SolrClientCache; +import org.apache.solr.common.util.IOUtils; +import org.apache.solr.security.HttpClientBuilderPlugin; +import org.apache.solr.update.UpdateShardHandlerConfig; +import org.apache.solr.util.stats.InstrumentedHttpListenerFactory; + +/** New home for default http client. */ +public class ServerSolrClientCache extends SolrClientCache { + + public ServerSolrClientCache(HttpClient solrClient) { + super(solrClient); + Http2SolrClient.Builder http2SolrClientBuilder = new Http2SolrClient.Builder(); + InstrumentedHttpListenerFactory trackHttpSolrMetrics = + new InstrumentedHttpListenerFactory( + InstrumentedHttpListenerFactory.KNOWN_METRIC_NAME_STRATEGIES.get( + UpdateShardHandlerConfig.DEFAULT_METRICNAMESTRATEGY)); + long idleTimeout = minSocketTimeout; + if (http2SolrClientBuilder.getIdleTimeoutMillis() != null) { + idleTimeout = Math.max(idleTimeout, http2SolrClientBuilder.getIdleTimeoutMillis()); + } + http2SolrClientBuilder.withIdleTimeout(idleTimeout, TimeUnit.MILLISECONDS); + long connTimeout = minConnTimeout; + if (http2SolrClientBuilder.getConnectionTimeout() != null) { + connTimeout = Math.max(idleTimeout, http2SolrClientBuilder.getConnectionTimeout()); + } + http2SolrClientBuilder.withConnectionTimeout(connTimeout, TimeUnit.MILLISECONDS); + http2SolrClientBuilder.withListenerFactory(List.of(trackHttpSolrMetrics)); + + http2SolrClient = http2SolrClientBuilder.build(); + } + + public SolrClient getHttpSolrClient() { + return http2SolrClient; + } + + @Override + public synchronized void close() { + super.close(); + IOUtils.closeQuietly(http2SolrClient); + } + + public void setSecurityBuilder(HttpClientBuilderPlugin builder) { + builder.setup(http2SolrClient); + } +} diff --git a/solr/core/src/java/org/apache/solr/security/PKIAuthenticationPlugin.java b/solr/core/src/java/org/apache/solr/security/PKIAuthenticationPlugin.java index b1f6e6b6eed..d7b52c9a487 100644 --- a/solr/core/src/java/org/apache/solr/security/PKIAuthenticationPlugin.java +++ b/solr/core/src/java/org/apache/solr/security/PKIAuthenticationPlugin.java @@ -41,16 +41,18 @@ import org.apache.http.HttpHeaders; import org.apache.http.HttpRequest; import org.apache.http.HttpRequestInterceptor; -import org.apache.http.HttpResponse; import org.apache.http.auth.BasicUserPrincipal; -import org.apache.http.client.methods.HttpGet; import org.apache.http.protocol.HttpContext; -import org.apache.http.util.EntityUtils; +import org.apache.solr.client.solrj.SolrRequest; +import org.apache.solr.client.solrj.SolrServerException; import org.apache.solr.client.solrj.impl.Http2SolrClient; import org.apache.solr.client.solrj.impl.HttpClientUtil; import org.apache.solr.client.solrj.impl.HttpListenerFactory; import org.apache.solr.client.solrj.impl.SolrHttpClientBuilder; +import org.apache.solr.client.solrj.request.GenericSolrRequest; +import org.apache.solr.common.params.ModifiableSolrParams; import org.apache.solr.common.util.ExecutorUtil; +import org.apache.solr.common.util.NamedList; import org.apache.solr.common.util.StrUtils; import org.apache.solr.common.util.SuppressForbidden; import org.apache.solr.common.util.Utils; @@ -347,22 +349,28 @@ PublicKey fetchPublicKeyFromRemote(String nodename) { HttpEntity entity = null; try { String uri = url + PublicKeyHandler.PATH + "?wt=json&omitHeader=true"; + ModifiableSolrParams solrParams = new ModifiableSolrParams(); + solrParams.add("wt", "json"); + solrParams.add("omitHeader", "true"); + + GenericSolrRequest request = + new GenericSolrRequest(SolrRequest.METHOD.GET, PublicKeyHandler.PATH, solrParams); + log.debug("Fetching fresh public key from: {}", uri); - HttpResponse rsp = - cores - .getUpdateShardHandler() - .getDefaultHttpClient() - .execute(new HttpGet(uri), HttpClientUtil.createNewHttpClientRequestContext()); - entity = rsp.getEntity(); - byte[] bytes = EntityUtils.toByteArray(entity); - Map m = (Map) Utils.fromJSON(bytes); - String key = (String) m.get("key"); - if (key == null) { - log.error("No key available from {}{}", url, PublicKeyHandler.PATH); - return null; - } else { - log.info("New key obtained from node={}, key={}", nodename, key); + + String key; + try (Http2SolrClient solrClient = new Http2SolrClient.Builder(url).build()) { + NamedList resp = + solrClient.request(request, null); + key = (String) resp.get("key"); + if (key == null) { + log.error("No key available from {}{}", url, PublicKeyHandler.PATH); + return null; + } else { + log.info("New key obtained from node={}, key={}", nodename, key); + } } + PublicKey pubKey = CryptoKeys.deserializeX509PublicKey(key); keyCache.put(nodename, pubKey); return pubKey; diff --git a/solr/solrj-streaming/src/java/org/apache/solr/client/solrj/io/SolrClientCache.java b/solr/solrj-streaming/src/java/org/apache/solr/client/solrj/io/SolrClientCache.java index 45ce93c30c4..b4f1d875ef5 100644 --- a/solr/solrj-streaming/src/java/org/apache/solr/client/solrj/io/SolrClientCache.java +++ b/solr/solrj-streaming/src/java/org/apache/solr/client/solrj/io/SolrClientCache.java @@ -48,16 +48,16 @@ public class SolrClientCache implements Closeable { // Set the floor for timeouts to 60 seconds. // Timeouts can be increased by setting the system properties defined below. - private static final int MIN_TIMEOUT = 60000; - private static final int minConnTimeout = + protected static final int MIN_TIMEOUT = 60000; + protected static final int minConnTimeout = Math.max( Integer.getInteger(HttpClientUtil.PROP_CONNECTION_TIMEOUT, MIN_TIMEOUT), MIN_TIMEOUT); - private static final int minSocketTimeout = + protected static final int minSocketTimeout = Math.max(Integer.getInteger(HttpClientUtil.PROP_SO_TIMEOUT, MIN_TIMEOUT), MIN_TIMEOUT); private final Map solrClients = new HashMap<>(); private final HttpClient apacheHttpClient; - private final Http2SolrClient http2SolrClient; + protected Http2SolrClient http2SolrClient; private final AtomicBoolean isClosed = new AtomicBoolean(false); private final AtomicReference defaultZkHost = new AtomicReference<>(); @@ -169,6 +169,10 @@ public synchronized SolrClient getHttpSolrClient(String baseUrl) { return client; } + public SolrClient getHttp2SolrClient() { + return http2SolrClient; + } + @Deprecated private static SolrClient newHttpSolrClient(String url, HttpClient httpClient) { final var builder = From a4615d12eecdcd05e11577feb2a049e0c4ea1d52 Mon Sep 17 00:00:00 2001 From: Sanjay Dutt Date: Mon, 2 Sep 2024 22:16:47 +0530 Subject: [PATCH 02/26] format code --- .../org/apache/solr/security/PKIAuthenticationPlugin.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/solr/core/src/java/org/apache/solr/security/PKIAuthenticationPlugin.java b/solr/core/src/java/org/apache/solr/security/PKIAuthenticationPlugin.java index d7b52c9a487..1b01e4f8a7a 100644 --- a/solr/core/src/java/org/apache/solr/security/PKIAuthenticationPlugin.java +++ b/solr/core/src/java/org/apache/solr/security/PKIAuthenticationPlugin.java @@ -44,7 +44,6 @@ import org.apache.http.auth.BasicUserPrincipal; import org.apache.http.protocol.HttpContext; import org.apache.solr.client.solrj.SolrRequest; -import org.apache.solr.client.solrj.SolrServerException; import org.apache.solr.client.solrj.impl.Http2SolrClient; import org.apache.solr.client.solrj.impl.HttpClientUtil; import org.apache.solr.client.solrj.impl.HttpListenerFactory; @@ -360,8 +359,7 @@ PublicKey fetchPublicKeyFromRemote(String nodename) { String key; try (Http2SolrClient solrClient = new Http2SolrClient.Builder(url).build()) { - NamedList resp = - solrClient.request(request, null); + NamedList resp = solrClient.request(request, null); key = (String) resp.get("key"); if (key == null) { log.error("No key available from {}{}", url, PublicKeyHandler.PATH); From 8062a1e73109de3fb0c199da24e1fd06088055c8 Mon Sep 17 00:00:00 2001 From: Sanjay Dutt Date: Wed, 4 Sep 2024 22:10:10 +0530 Subject: [PATCH 03/26] HttpSolrClientProvider for default http client --- .../api/collections/ReindexCollectionCmd.java | 282 +++++++++--------- .../org/apache/solr/core/CoreContainer.java | 20 +- .../solr/core/HttpSolrClientProvider.java | 151 ++++++++++ .../security/PKIAuthenticationPlugin.java | 24 +- 4 files changed, 316 insertions(+), 161 deletions(-) create mode 100644 solr/core/src/java/org/apache/solr/core/HttpSolrClientProvider.java diff --git a/solr/core/src/java/org/apache/solr/cloud/api/collections/ReindexCollectionCmd.java b/solr/core/src/java/org/apache/solr/cloud/api/collections/ReindexCollectionCmd.java index 91299b3c259..8bc7f85c215 100644 --- a/solr/core/src/java/org/apache/solr/cloud/api/collections/ReindexCollectionCmd.java +++ b/solr/core/src/java/org/apache/solr/cloud/api/collections/ReindexCollectionCmd.java @@ -31,12 +31,9 @@ import java.util.function.Function; import java.util.stream.Collectors; import java.util.stream.Stream; -import org.apache.http.client.HttpClient; -import org.apache.solr.client.solrj.SolrClient; import org.apache.solr.client.solrj.SolrResponse; import org.apache.solr.client.solrj.cloud.DistribStateManager; import org.apache.solr.client.solrj.impl.CloudSolrClient; -import org.apache.solr.client.solrj.impl.HttpSolrClient; import org.apache.solr.client.solrj.request.CollectionAdminRequest; import org.apache.solr.client.solrj.request.QueryRequest; import org.apache.solr.client.solrj.response.QueryResponse; @@ -729,62 +726,59 @@ private void waitForDaemon( String targetCollection, Map reindexingState) throws Exception { - HttpClient client = ccc.getCoreContainer().getUpdateShardHandler().getDefaultHttpClient(); - try (SolrClient solrClient = - new HttpSolrClient.Builder() - .withHttpClient(client) - .withBaseSolrUrl(daemonReplica.getBaseUrl()) - .build()) { - ModifiableSolrParams q = new ModifiableSolrParams(); - q.set(CommonParams.QT, "/stream"); - q.set("action", "list"); - q.set(CommonParams.DISTRIB, false); - QueryRequest req = new QueryRequest(q); - boolean isRunning; - int statusCheck = 0; - do { - isRunning = false; - statusCheck++; - try { - NamedList rsp = solrClient.request(req, daemonReplica.getCoreName()); - Map rs = (Map) rsp.get("result-set"); - if (rs == null || rs.isEmpty()) { - throw new SolrException( - SolrException.ErrorCode.SERVER_ERROR, - "Can't find daemon list: missing result-set: " + Utils.toJSONString(rsp)); - } - List list = (List) rs.get("docs"); - if (list == null) { - throw new SolrException( - SolrException.ErrorCode.SERVER_ERROR, - "Can't find daemon list: missing result-set: " + Utils.toJSONString(rsp)); - } - if (list.isEmpty()) { // finished? - break; - } - for (Object o : list) { - Map map = (Map) o; - String id = (String) map.get("id"); - if (daemonName.equals(id)) { - isRunning = true; - // fail here - TestInjection.injectReindexFailure(); - break; - } - } - } catch (Exception e) { + var solrClient = ccc.getCoreContainer().getDefaultHttpClient(); + + ModifiableSolrParams q = new ModifiableSolrParams(); + q.set(CommonParams.QT, "/stream"); + q.set("action", "list"); + q.set(CommonParams.DISTRIB, false); + QueryRequest req = new QueryRequest(q); + req.setBasePath(daemonReplica.getBaseUrl()); + + boolean isRunning; + int statusCheck = 0; + do { + isRunning = false; + statusCheck++; + try { + NamedList rsp = solrClient.request(req, daemonReplica.getCoreName()); + Map rs = (Map) rsp.get("result-set"); + if (rs == null || rs.isEmpty()) { throw new SolrException( SolrException.ErrorCode.SERVER_ERROR, - "Exception waiting for daemon " + daemonName + " at " + daemonReplica.getCoreUrl(), - e); + "Can't find daemon list: missing result-set: " + Utils.toJSONString(rsp)); } - if (statusCheck % 5 == 0) { - reindexingState.put("processedDocs", getNumberOfDocs(targetCollection)); - setReindexingState(sourceCollection, State.RUNNING, reindexingState); + List list = (List) rs.get("docs"); + if (list == null) { + throw new SolrException( + SolrException.ErrorCode.SERVER_ERROR, + "Can't find daemon list: missing result-set: " + Utils.toJSONString(rsp)); } - ccc.getSolrCloudManager().getTimeSource().sleep(2000); - } while (isRunning && !maybeAbort(sourceCollection)); - } + if (list.isEmpty()) { // finished? + break; + } + for (Object o : list) { + Map map = (Map) o; + String id = (String) map.get("id"); + if (daemonName.equals(id)) { + isRunning = true; + // fail here + TestInjection.injectReindexFailure(); + break; + } + } + } catch (Exception e) { + throw new SolrException( + SolrException.ErrorCode.SERVER_ERROR, + "Exception waiting for daemon " + daemonName + " at " + daemonReplica.getCoreUrl(), + e); + } + if (statusCheck % 5 == 0) { + reindexingState.put("processedDocs", getNumberOfDocs(targetCollection)); + setReindexingState(sourceCollection, State.RUNNING, reindexingState); + } + ccc.getSolrCloudManager().getTimeSource().sleep(2000); + } while (isRunning && !maybeAbort(sourceCollection)); } @SuppressWarnings({"unchecked"}) @@ -792,107 +786,99 @@ private void killDaemon(String daemonName, Replica daemonReplica) throws Excepti if (log.isDebugEnabled()) { log.debug("-- killing daemon {} at {}", daemonName, daemonReplica.getCoreUrl()); } - HttpClient client = ccc.getCoreContainer().getUpdateShardHandler().getDefaultHttpClient(); - try (SolrClient solrClient = - new HttpSolrClient.Builder() - .withHttpClient(client) - .withDefaultCollection(daemonReplica.getCoreName()) - .withBaseSolrUrl(daemonReplica.getBaseUrl()) - .build()) { - ModifiableSolrParams q = new ModifiableSolrParams(); - q.set(CommonParams.QT, "/stream"); - // we should really use 'kill' here, but then we will never - // know when the daemon actually finishes running - 'kill' only - // sets a flag that may be noticed much later - q.set("action", "stop"); - q.set(CommonParams.ID, daemonName); - q.set(CommonParams.DISTRIB, false); - QueryRequest req = new QueryRequest(q); - NamedList rsp = solrClient.request(req); - // /result-set/docs/[0]/DaemonOp : Deamon:id killed on coreName - if (log.isDebugEnabled()) { - log.debug(" -- stop daemon response: {}", Utils.toJSONString(rsp)); - } - Map rs = (Map) rsp.get("result-set"); - if (rs == null || rs.isEmpty()) { - log.warn( - "Problem killing daemon {}: missing result-set: {}", - daemonName, - Utils.toJSONString(rsp)); - return; - } - List list = (List) rs.get("docs"); - if (list == null) { - log.warn( - "Problem killing daemon {}: missing result-set: {}", - daemonName, - Utils.toJSONString(rsp)); - return; - } - if (list.isEmpty()) { // already finished? - return; + + var solrClient = ccc.getCoreContainer().getDefaultHttpClient(); + ModifiableSolrParams q = new ModifiableSolrParams(); + q.set(CommonParams.QT, "/stream"); + // we should really use 'kill' here, but then we will never + // know when the daemon actually finishes running - 'kill' only + // sets a flag that may be noticed much later + q.set("action", "stop"); + q.set(CommonParams.ID, daemonName); + q.set(CommonParams.DISTRIB, false); + QueryRequest req = new QueryRequest(q); + req.setBasePath(daemonReplica.getBaseUrl()); + NamedList rsp = solrClient.request(req, daemonReplica.getCoreName()); + // /result-set/docs/[0]/DaemonOp : Deamon:id killed on coreName + if (log.isDebugEnabled()) { + log.debug(" -- stop daemon response: {}", Utils.toJSONString(rsp)); + } + Map rs = (Map) rsp.get("result-set"); + if (rs == null || rs.isEmpty()) { + log.warn( + "Problem killing daemon {}: missing result-set: {}", daemonName, Utils.toJSONString(rsp)); + return; + } + List list = (List) rs.get("docs"); + if (list == null) { + log.warn( + "Problem killing daemon {}: missing result-set: {}", daemonName, Utils.toJSONString(rsp)); + return; + } + if (list.isEmpty()) { // already finished? + return; + } + for (Object o : list) { + Map map = (Map) o; + String op = (String) map.get("DaemonOp"); + if (op == null) { + continue; } - for (Object o : list) { - Map map = (Map) o; - String op = (String) map.get("DaemonOp"); - if (op == null) { - continue; - } - if (op.contains(daemonName) && op.contains("stopped")) { - // now wait for the daemon to really stop - q.set("action", "list"); - req = new QueryRequest(q); - TimeOut timeOut = - new TimeOut(60, TimeUnit.SECONDS, ccc.getSolrCloudManager().getTimeSource()); - while (!timeOut.hasTimedOut()) { - rsp = solrClient.request(req); - rs = (Map) rsp.get("result-set"); - if (rs == null || rs.isEmpty()) { - log.warn( - "Problem killing daemon {}: missing result-set: {}", - daemonName, - Utils.toJSONString(rsp)); - break; - } - List list2 = (List) rs.get("docs"); - if (list2 == null) { - log.warn( - "Problem killing daemon {}: missing result-set: {}", - daemonName, - Utils.toJSONString(rsp)); - break; - } - if (list2.isEmpty()) { // already finished? - break; - } - Map status2 = null; - for (Object o2 : list2) { - Map map2 = (Map) o2; - if (daemonName.equals(map2.get("id"))) { - status2 = map2; - break; - } - } - if (status2 == null) { // finished? - break; - } - Number stopTime = (Number) status2.get("stopTime"); - if (stopTime.longValue() > 0) { + if (op.contains(daemonName) && op.contains("stopped")) { + // now wait for the daemon to really stop + q.set("action", "list"); + req = new QueryRequest(q); + req.setBasePath(daemonReplica.getBaseUrl()); + TimeOut timeOut = + new TimeOut(60, TimeUnit.SECONDS, ccc.getSolrCloudManager().getTimeSource()); + while (!timeOut.hasTimedOut()) { + rsp = solrClient.request(req, daemonReplica.getCoreName()); + rs = (Map) rsp.get("result-set"); + if (rs == null || rs.isEmpty()) { + log.warn( + "Problem killing daemon {}: missing result-set: {}", + daemonName, + Utils.toJSONString(rsp)); + break; + } + List list2 = (List) rs.get("docs"); + if (list2 == null) { + log.warn( + "Problem killing daemon {}: missing result-set: {}", + daemonName, + Utils.toJSONString(rsp)); + break; + } + if (list2.isEmpty()) { // already finished? + break; + } + Map status2 = null; + for (Object o2 : list2) { + Map map2 = (Map) o2; + if (daemonName.equals(map2.get("id"))) { + status2 = map2; break; } } - if (timeOut.hasTimedOut()) { - log.warn( - "Problem killing daemon {}: timed out waiting for daemon to stop.", daemonName); - // proceed anyway + if (status2 == null) { // finished? + break; + } + Number stopTime = (Number) status2.get("stopTime"); + if (stopTime.longValue() > 0) { + break; } } + if (timeOut.hasTimedOut()) { + log.warn("Problem killing daemon {}: timed out waiting for daemon to stop.", daemonName); + // proceed anyway + } } - // now kill it - it's already stopped, this simply removes its status - q.set("action", "kill"); - req = new QueryRequest(q); - solrClient.request(req); } + // now kill it - it's already stopped, this simply removes its status + q.set("action", "kill"); + req = new QueryRequest(q); + req.setBasePath(daemonReplica.getBaseUrl()); + solrClient.request(req, daemonReplica.getCoreName()); } private void cleanup( diff --git a/solr/core/src/java/org/apache/solr/core/CoreContainer.java b/solr/core/src/java/org/apache/solr/core/CoreContainer.java index d8573a83ff4..ccb30c3043c 100644 --- a/solr/core/src/java/org/apache/solr/core/CoreContainer.java +++ b/solr/core/src/java/org/apache/solr/core/CoreContainer.java @@ -67,6 +67,7 @@ import org.apache.solr.api.ClusterPluginsSource; import org.apache.solr.api.ContainerPluginsRegistry; import org.apache.solr.api.JerseyResource; +import org.apache.solr.client.solrj.SolrClient; import org.apache.solr.client.solrj.impl.HttpClientUtil; import org.apache.solr.client.solrj.impl.SolrHttpClientBuilder; import org.apache.solr.client.solrj.impl.SolrHttpClientContextBuilder; @@ -236,6 +237,8 @@ public JerseyAppHandlerCache getJerseyAppHandlerCache() { private volatile UpdateShardHandler updateShardHandler; + private volatile HttpSolrClientProvider solrClientProvider; + private volatile ExecutorService coreContainerWorkExecutor = ExecutorUtil.newMDCAwareCachedThreadPool( new SolrNamedThreadFactory("coreContainerWorkExecutor")); @@ -652,6 +655,7 @@ public Lookup getAuthSchemeRegistry() { pkiAuthenticationSecurityBuilder.getHttpClientBuilder(HttpClientUtil.getHttpClientBuilder()); shardHandlerFactory.setSecurityBuilder(pkiAuthenticationSecurityBuilder); updateShardHandler.setSecurityBuilder(pkiAuthenticationSecurityBuilder); + solrClientProvider.setSecurityBuilder(pkiAuthenticationSecurityBuilder); if (solrClientCache instanceof ServerSolrClientCache) { ServerSolrClientCache serverSolrClientCache = (ServerSolrClientCache) solrClientCache; serverSolrClientCache.setSecurityBuilder(pkiAuthenticationSecurityBuilder); @@ -839,8 +843,9 @@ private void loadInternal() { } updateShardHandler = new UpdateShardHandler(cfg.getUpdateShardHandlerConfig()); + solrClientProvider = new HttpSolrClientProvider(cfg.getUpdateShardHandlerConfig()); updateShardHandler.initializeMetrics(solrMetricsContext, "updateShardHandler"); - + solrClientProvider.initializeMetrics(solrMetricsContext, HttpSolrClientProvider.METRIC_SCOPE_NAME); solrClientCache = new ServerSolrClientCache(updateShardHandler.getDefaultHttpClient()); Map cachesConfig = cfg.getCachesConfig(); @@ -1228,6 +1233,11 @@ private void reloadSecurityProperties() { initializeAuditloggerPlugin((Map) securityConfig.getData().get("auditlogging")); } + private SolrClient createDefaultHttpSolrClient() { + + return null; + } + private void warnUsersOfInsecureSettings() { if (authenticationPlugin == null || authorizationPlugin == null) { log.warn( @@ -1413,6 +1423,9 @@ public void shutdown() { if (updateShardHandler != null) { customThreadPool.submit(updateShardHandler::close); } + if (solrClientProvider != null) { + customThreadPool.submit(solrClientProvider::close); + } } finally { try { // we want to close zk stuff last @@ -2567,6 +2580,11 @@ public PlacementPluginFactory getPlacementPlugi return this.distributedCollectionCommandRunner; } + /** Returns default http solr client. */ + public SolrClient getDefaultHttpClient() { + return solrClientProvider.getSolrClient(); + } + /** * Run an arbitrary task in its own thread. This is an expert option and is a method you should * use with great care. It would be bad to run something that never stopped or run something that diff --git a/solr/core/src/java/org/apache/solr/core/HttpSolrClientProvider.java b/solr/core/src/java/org/apache/solr/core/HttpSolrClientProvider.java new file mode 100644 index 00000000000..a118429f960 --- /dev/null +++ b/solr/core/src/java/org/apache/solr/core/HttpSolrClientProvider.java @@ -0,0 +1,151 @@ +/* + * 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.core; + +import static org.apache.solr.util.stats.InstrumentedHttpRequestExecutor.KNOWN_METRIC_NAME_STRATEGIES; + +import java.lang.invoke.MethodHandles; +import java.util.List; +import java.util.concurrent.TimeUnit; +import org.apache.solr.client.solrj.SolrClient; +import org.apache.solr.client.solrj.impl.Http2SolrClient; +import org.apache.solr.client.solrj.impl.HttpClientUtil; +import org.apache.solr.common.SolrException; +import org.apache.solr.common.util.IOUtils; +import org.apache.solr.metrics.SolrMetricManager; +import org.apache.solr.metrics.SolrMetricsContext; +import org.apache.solr.security.HttpClientBuilderPlugin; +import org.apache.solr.update.UpdateShardHandlerConfig; +import org.apache.solr.util.stats.HttpClientMetricNameStrategy; +import org.apache.solr.util.stats.InstrumentedHttpListenerFactory; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** Internal use only. Provider of the default SolrClient implementation. */ +public class HttpSolrClientProvider implements SolrInfoBean { + private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass()); + + public static final String METRIC_SCOPE_NAME = "defaultHttpSolrClientProvider"; + + private final Http2SolrClient httpSolrClient; + + private final InstrumentedHttpListenerFactory trackHttpSolrMetrics; + + private SolrMetricsContext solrMetricsContext; + + private int socketTimeout = HttpClientUtil.DEFAULT_SO_TIMEOUT; + + private int connectionTimeout = HttpClientUtil.DEFAULT_CONNECT_TIMEOUT; + + public HttpSolrClientProvider(UpdateShardHandlerConfig cfg) { + Http2SolrClient.Builder httpClientBuilder = new Http2SolrClient.Builder(); + trackHttpSolrMetrics = new InstrumentedHttpListenerFactory(getNameStrategy(cfg)); + + if (cfg != null) { + httpClientBuilder.withMaxConnectionsPerHost(cfg.getMaxUpdateConnectionsPerHost()); + socketTimeout = Math.max(cfg.getDistributedConnectionTimeout(), connectionTimeout); + connectionTimeout = Math.max(cfg.getDistributedSocketTimeout(), socketTimeout); + } + + httpClientBuilder + .withConnectionTimeout(connectionTimeout, TimeUnit.MILLISECONDS) + .withIdleTimeout(socketTimeout, TimeUnit.MILLISECONDS) + .withListenerFactory(List.of(trackHttpSolrMetrics)); + + httpSolrClient = httpClientBuilder.build(); + } + + private HttpClientMetricNameStrategy getMetricNameStrategy(UpdateShardHandlerConfig cfg) { + HttpClientMetricNameStrategy metricNameStrategy = + KNOWN_METRIC_NAME_STRATEGIES.get(UpdateShardHandlerConfig.DEFAULT_METRICNAMESTRATEGY); + if (cfg != null) { + metricNameStrategy = KNOWN_METRIC_NAME_STRATEGIES.get(cfg.getMetricNameStrategy()); + if (metricNameStrategy == null) { + throw new SolrException( + SolrException.ErrorCode.SERVER_ERROR, + "Unknown metricNameStrategy: " + + cfg.getMetricNameStrategy() + + " found. Must be one of: " + + KNOWN_METRIC_NAME_STRATEGIES.keySet()); + } + } + return metricNameStrategy; + } + + private InstrumentedHttpListenerFactory.NameStrategy getNameStrategy( + UpdateShardHandlerConfig cfg) { + InstrumentedHttpListenerFactory.NameStrategy nameStrategy = + InstrumentedHttpListenerFactory.KNOWN_METRIC_NAME_STRATEGIES.get( + UpdateShardHandlerConfig.DEFAULT_METRICNAMESTRATEGY); + + if (cfg != null) { + nameStrategy = + InstrumentedHttpListenerFactory.KNOWN_METRIC_NAME_STRATEGIES.get( + cfg.getMetricNameStrategy()); + if (nameStrategy == null) { + throw new SolrException( + SolrException.ErrorCode.SERVER_ERROR, + "Unknown metricNameStrategy: " + + cfg.getMetricNameStrategy() + + " found. Must be one of: " + + KNOWN_METRIC_NAME_STRATEGIES.keySet()); + } + } + return nameStrategy; + } + + // Return a default http client for all-purpose usage. + public SolrClient getSolrClient() { + return httpSolrClient; + } + + public void setSecurityBuilder(HttpClientBuilderPlugin builder) { + builder.setup(httpSolrClient); + } + + @Override + public void initializeMetrics(SolrMetricsContext parentContext, String scope) { + solrMetricsContext = parentContext.getChildContext(this); + String expandedScope = SolrMetricManager.mkName(scope, getCategory().name()); + trackHttpSolrMetrics.initializeMetrics(solrMetricsContext, expandedScope); + } + + @Override + public SolrMetricsContext getSolrMetricsContext() { + return solrMetricsContext; + } + + @Override + public void close() { + IOUtils.closeQuietly(httpSolrClient); + } + + @Override + public String getName() { + return this.getClass().getName(); + } + + @Override + public String getDescription() { + return "Metrics tracked by HttpSolrClientProvider related to distributed updates and recovery"; + } + + @Override + public Category getCategory() { + return Category.HTTP; + } +} diff --git a/solr/core/src/java/org/apache/solr/security/PKIAuthenticationPlugin.java b/solr/core/src/java/org/apache/solr/security/PKIAuthenticationPlugin.java index 1b01e4f8a7a..74ecc88d8f9 100644 --- a/solr/core/src/java/org/apache/solr/security/PKIAuthenticationPlugin.java +++ b/solr/core/src/java/org/apache/solr/security/PKIAuthenticationPlugin.java @@ -347,26 +347,26 @@ PublicKey fetchPublicKeyFromRemote(String nodename) { String url = cores.getZkController().getZkStateReader().getBaseUrlForNodeName(nodename); HttpEntity entity = null; try { - String uri = url + PublicKeyHandler.PATH + "?wt=json&omitHeader=true"; ModifiableSolrParams solrParams = new ModifiableSolrParams(); solrParams.add("wt", "json"); solrParams.add("omitHeader", "true"); GenericSolrRequest request = new GenericSolrRequest(SolrRequest.METHOD.GET, PublicKeyHandler.PATH, solrParams); + request.setBasePath(url); - log.debug("Fetching fresh public key from: {}", uri); + final var solrClient = cores.getDefaultHttpClient(); - String key; - try (Http2SolrClient solrClient = new Http2SolrClient.Builder(url).build()) { - NamedList resp = solrClient.request(request, null); - key = (String) resp.get("key"); - if (key == null) { - log.error("No key available from {}{}", url, PublicKeyHandler.PATH); - return null; - } else { - log.info("New key obtained from node={}, key={}", nodename, key); - } + log.debug("Fetching fresh public key from: {}{}", url, PublicKeyHandler.PATH); + NamedList resp = solrClient.request(request); + + String key = (String) resp.get("key"); + + if (key == null) { + log.error("No key available from {}{}", url, PublicKeyHandler.PATH); + return null; + } else { + log.info("New key obtained from node={}, key={}", nodename, key); } PublicKey pubKey = CryptoKeys.deserializeX509PublicKey(key); From f80d3d264080489868914bbfa4135d760e0df5c4 Mon Sep 17 00:00:00 2001 From: Sanjay Dutt Date: Wed, 4 Sep 2024 22:31:50 +0530 Subject: [PATCH 04/26] format code --- solr/core/src/java/org/apache/solr/core/CoreContainer.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/solr/core/src/java/org/apache/solr/core/CoreContainer.java b/solr/core/src/java/org/apache/solr/core/CoreContainer.java index ccb30c3043c..137c32eb0f6 100644 --- a/solr/core/src/java/org/apache/solr/core/CoreContainer.java +++ b/solr/core/src/java/org/apache/solr/core/CoreContainer.java @@ -845,7 +845,8 @@ private void loadInternal() { updateShardHandler = new UpdateShardHandler(cfg.getUpdateShardHandlerConfig()); solrClientProvider = new HttpSolrClientProvider(cfg.getUpdateShardHandlerConfig()); updateShardHandler.initializeMetrics(solrMetricsContext, "updateShardHandler"); - solrClientProvider.initializeMetrics(solrMetricsContext, HttpSolrClientProvider.METRIC_SCOPE_NAME); + solrClientProvider.initializeMetrics( + solrMetricsContext, HttpSolrClientProvider.METRIC_SCOPE_NAME); solrClientCache = new ServerSolrClientCache(updateShardHandler.getDefaultHttpClient()); Map cachesConfig = cfg.getCachesConfig(); From 82a625596d1935b963e62d98878437144d728137 Mon Sep 17 00:00:00 2001 From: Sanjay Dutt Date: Thu, 5 Sep 2024 21:10:03 +0530 Subject: [PATCH 05/26] Deleted ServerSolrClientCache and related code --- .../org/apache/solr/core/CoreContainer.java | 6 +- .../solr/core/HttpSolrClientProvider.java | 26 +++---- .../solr/core/ServerSolrClientCache.java | 68 ------------------- .../solr/client/solrj/io/SolrClientCache.java | 12 ++-- 4 files changed, 13 insertions(+), 99 deletions(-) delete mode 100644 solr/core/src/java/org/apache/solr/core/ServerSolrClientCache.java diff --git a/solr/core/src/java/org/apache/solr/core/CoreContainer.java b/solr/core/src/java/org/apache/solr/core/CoreContainer.java index 137c32eb0f6..40b01ff64f5 100644 --- a/solr/core/src/java/org/apache/solr/core/CoreContainer.java +++ b/solr/core/src/java/org/apache/solr/core/CoreContainer.java @@ -656,10 +656,6 @@ public Lookup getAuthSchemeRegistry() { shardHandlerFactory.setSecurityBuilder(pkiAuthenticationSecurityBuilder); updateShardHandler.setSecurityBuilder(pkiAuthenticationSecurityBuilder); solrClientProvider.setSecurityBuilder(pkiAuthenticationSecurityBuilder); - if (solrClientCache instanceof ServerSolrClientCache) { - ServerSolrClientCache serverSolrClientCache = (ServerSolrClientCache) solrClientCache; - serverSolrClientCache.setSecurityBuilder(pkiAuthenticationSecurityBuilder); - } } } @@ -847,7 +843,7 @@ private void loadInternal() { updateShardHandler.initializeMetrics(solrMetricsContext, "updateShardHandler"); solrClientProvider.initializeMetrics( solrMetricsContext, HttpSolrClientProvider.METRIC_SCOPE_NAME); - solrClientCache = new ServerSolrClientCache(updateShardHandler.getDefaultHttpClient()); + solrClientCache = new SolrClientCache(updateShardHandler.getDefaultHttpClient()); Map cachesConfig = cfg.getCachesConfig(); if (cachesConfig.isEmpty()) { 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 a118429f960..1848ee9d41b 100644 --- a/solr/core/src/java/org/apache/solr/core/HttpSolrClientProvider.java +++ b/solr/core/src/java/org/apache/solr/core/HttpSolrClientProvider.java @@ -27,6 +27,7 @@ import org.apache.solr.common.SolrException; import org.apache.solr.common.util.IOUtils; import org.apache.solr.metrics.SolrMetricManager; +import org.apache.solr.metrics.SolrMetricProducer; import org.apache.solr.metrics.SolrMetricsContext; import org.apache.solr.security.HttpClientBuilderPlugin; import org.apache.solr.update.UpdateShardHandlerConfig; @@ -35,8 +36,12 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -/** Internal use only. Provider of the default SolrClient implementation. */ -public class HttpSolrClientProvider implements SolrInfoBean { +/** + * Provider of the default SolrClient implementation. + * + * @lucene.internal + */ +class HttpSolrClientProvider implements SolrMetricProducer { private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass()); public static final String METRIC_SCOPE_NAME = "defaultHttpSolrClientProvider"; @@ -120,7 +125,7 @@ public void setSecurityBuilder(HttpClientBuilderPlugin builder) { @Override public void initializeMetrics(SolrMetricsContext parentContext, String scope) { solrMetricsContext = parentContext.getChildContext(this); - String expandedScope = SolrMetricManager.mkName(scope, getCategory().name()); + String expandedScope = SolrMetricManager.mkName(scope, SolrInfoBean.Category.HTTP.name()); trackHttpSolrMetrics.initializeMetrics(solrMetricsContext, expandedScope); } @@ -133,19 +138,4 @@ public SolrMetricsContext getSolrMetricsContext() { public void close() { IOUtils.closeQuietly(httpSolrClient); } - - @Override - public String getName() { - return this.getClass().getName(); - } - - @Override - public String getDescription() { - return "Metrics tracked by HttpSolrClientProvider related to distributed updates and recovery"; - } - - @Override - public Category getCategory() { - return Category.HTTP; - } } diff --git a/solr/core/src/java/org/apache/solr/core/ServerSolrClientCache.java b/solr/core/src/java/org/apache/solr/core/ServerSolrClientCache.java deleted file mode 100644 index be113a892ce..00000000000 --- a/solr/core/src/java/org/apache/solr/core/ServerSolrClientCache.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * 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.core; - -import java.util.List; -import java.util.concurrent.TimeUnit; -import org.apache.http.client.HttpClient; -import org.apache.solr.client.solrj.SolrClient; -import org.apache.solr.client.solrj.impl.Http2SolrClient; -import org.apache.solr.client.solrj.io.SolrClientCache; -import org.apache.solr.common.util.IOUtils; -import org.apache.solr.security.HttpClientBuilderPlugin; -import org.apache.solr.update.UpdateShardHandlerConfig; -import org.apache.solr.util.stats.InstrumentedHttpListenerFactory; - -/** New home for default http client. */ -public class ServerSolrClientCache extends SolrClientCache { - - public ServerSolrClientCache(HttpClient solrClient) { - super(solrClient); - Http2SolrClient.Builder http2SolrClientBuilder = new Http2SolrClient.Builder(); - InstrumentedHttpListenerFactory trackHttpSolrMetrics = - new InstrumentedHttpListenerFactory( - InstrumentedHttpListenerFactory.KNOWN_METRIC_NAME_STRATEGIES.get( - UpdateShardHandlerConfig.DEFAULT_METRICNAMESTRATEGY)); - long idleTimeout = minSocketTimeout; - if (http2SolrClientBuilder.getIdleTimeoutMillis() != null) { - idleTimeout = Math.max(idleTimeout, http2SolrClientBuilder.getIdleTimeoutMillis()); - } - http2SolrClientBuilder.withIdleTimeout(idleTimeout, TimeUnit.MILLISECONDS); - long connTimeout = minConnTimeout; - if (http2SolrClientBuilder.getConnectionTimeout() != null) { - connTimeout = Math.max(idleTimeout, http2SolrClientBuilder.getConnectionTimeout()); - } - http2SolrClientBuilder.withConnectionTimeout(connTimeout, TimeUnit.MILLISECONDS); - http2SolrClientBuilder.withListenerFactory(List.of(trackHttpSolrMetrics)); - - http2SolrClient = http2SolrClientBuilder.build(); - } - - public SolrClient getHttpSolrClient() { - return http2SolrClient; - } - - @Override - public synchronized void close() { - super.close(); - IOUtils.closeQuietly(http2SolrClient); - } - - public void setSecurityBuilder(HttpClientBuilderPlugin builder) { - builder.setup(http2SolrClient); - } -} diff --git a/solr/solrj-streaming/src/java/org/apache/solr/client/solrj/io/SolrClientCache.java b/solr/solrj-streaming/src/java/org/apache/solr/client/solrj/io/SolrClientCache.java index b4f1d875ef5..45ce93c30c4 100644 --- a/solr/solrj-streaming/src/java/org/apache/solr/client/solrj/io/SolrClientCache.java +++ b/solr/solrj-streaming/src/java/org/apache/solr/client/solrj/io/SolrClientCache.java @@ -48,16 +48,16 @@ public class SolrClientCache implements Closeable { // Set the floor for timeouts to 60 seconds. // Timeouts can be increased by setting the system properties defined below. - protected static final int MIN_TIMEOUT = 60000; - protected static final int minConnTimeout = + private static final int MIN_TIMEOUT = 60000; + private static final int minConnTimeout = Math.max( Integer.getInteger(HttpClientUtil.PROP_CONNECTION_TIMEOUT, MIN_TIMEOUT), MIN_TIMEOUT); - protected static final int minSocketTimeout = + private static final int minSocketTimeout = Math.max(Integer.getInteger(HttpClientUtil.PROP_SO_TIMEOUT, MIN_TIMEOUT), MIN_TIMEOUT); private final Map solrClients = new HashMap<>(); private final HttpClient apacheHttpClient; - protected Http2SolrClient http2SolrClient; + private final Http2SolrClient http2SolrClient; private final AtomicBoolean isClosed = new AtomicBoolean(false); private final AtomicReference defaultZkHost = new AtomicReference<>(); @@ -169,10 +169,6 @@ public synchronized SolrClient getHttpSolrClient(String baseUrl) { return client; } - public SolrClient getHttp2SolrClient() { - return http2SolrClient; - } - @Deprecated private static SolrClient newHttpSolrClient(String url, HttpClient httpClient) { final var builder = From 05630c41f4e481c2c4215e4069e604df15bd408a Mon Sep 17 00:00:00 2001 From: Sanjay Dutt Date: Fri, 6 Sep 2024 16:07:59 +0530 Subject: [PATCH 06/26] Change return type to Http2SolrClient --- .../org/apache/solr/core/CoreContainer.java | 3 +- .../solr/core/HttpSolrClientProvider.java | 30 ++++++++++++------- 2 files changed, 21 insertions(+), 12 deletions(-) diff --git a/solr/core/src/java/org/apache/solr/core/CoreContainer.java b/solr/core/src/java/org/apache/solr/core/CoreContainer.java index 40b01ff64f5..4b79bfeb9aa 100644 --- a/solr/core/src/java/org/apache/solr/core/CoreContainer.java +++ b/solr/core/src/java/org/apache/solr/core/CoreContainer.java @@ -68,6 +68,7 @@ import org.apache.solr.api.ContainerPluginsRegistry; import org.apache.solr.api.JerseyResource; import org.apache.solr.client.solrj.SolrClient; +import org.apache.solr.client.solrj.impl.Http2SolrClient; import org.apache.solr.client.solrj.impl.HttpClientUtil; import org.apache.solr.client.solrj.impl.SolrHttpClientBuilder; import org.apache.solr.client.solrj.impl.SolrHttpClientContextBuilder; @@ -2578,7 +2579,7 @@ public PlacementPluginFactory getPlacementPlugi } /** Returns default http solr client. */ - public SolrClient getDefaultHttpClient() { + public Http2SolrClient getDefaultHttpClient() { return solrClientProvider.getSolrClient(); } 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 1848ee9d41b..2c478cd785a 100644 --- a/solr/core/src/java/org/apache/solr/core/HttpSolrClientProvider.java +++ b/solr/core/src/java/org/apache/solr/core/HttpSolrClientProvider.java @@ -21,7 +21,6 @@ import java.lang.invoke.MethodHandles; import java.util.List; import java.util.concurrent.TimeUnit; -import org.apache.solr.client.solrj.SolrClient; import org.apache.solr.client.solrj.impl.Http2SolrClient; import org.apache.solr.client.solrj.impl.HttpClientUtil; import org.apache.solr.common.SolrException; @@ -52,19 +51,14 @@ class HttpSolrClientProvider implements SolrMetricProducer { private SolrMetricsContext solrMetricsContext; - private int socketTimeout = HttpClientUtil.DEFAULT_SO_TIMEOUT; + private int socketTimeout; - private int connectionTimeout = HttpClientUtil.DEFAULT_CONNECT_TIMEOUT; + private int connectionTimeout; public HttpSolrClientProvider(UpdateShardHandlerConfig cfg) { Http2SolrClient.Builder httpClientBuilder = new Http2SolrClient.Builder(); trackHttpSolrMetrics = new InstrumentedHttpListenerFactory(getNameStrategy(cfg)); - - if (cfg != null) { - httpClientBuilder.withMaxConnectionsPerHost(cfg.getMaxUpdateConnectionsPerHost()); - socketTimeout = Math.max(cfg.getDistributedConnectionTimeout(), connectionTimeout); - connectionTimeout = Math.max(cfg.getDistributedSocketTimeout(), socketTimeout); - } + configureTimeouts(cfg); httpClientBuilder .withConnectionTimeout(connectionTimeout, TimeUnit.MILLISECONDS) @@ -74,6 +68,16 @@ public HttpSolrClientProvider(UpdateShardHandlerConfig cfg) { httpSolrClient = httpClientBuilder.build(); } + private void configureTimeouts(UpdateShardHandlerConfig cfg) { + socketTimeout = HttpClientUtil.DEFAULT_SO_TIMEOUT; + connectionTimeout = HttpClientUtil.DEFAULT_CONNECT_TIMEOUT; + + if (cfg != null) { + socketTimeout = Math.max(cfg.getDistributedSocketTimeout(), socketTimeout); + connectionTimeout = Math.max(cfg.getDistributedConnectionTimeout(), connectionTimeout); + } + } + private HttpClientMetricNameStrategy getMetricNameStrategy(UpdateShardHandlerConfig cfg) { HttpClientMetricNameStrategy metricNameStrategy = KNOWN_METRIC_NAME_STRATEGIES.get(UpdateShardHandlerConfig.DEFAULT_METRICNAMESTRATEGY); @@ -113,8 +117,7 @@ private InstrumentedHttpListenerFactory.NameStrategy getNameStrategy( return nameStrategy; } - // Return a default http client for all-purpose usage. - public SolrClient getSolrClient() { + public Http2SolrClient getSolrClient() { return httpSolrClient; } @@ -136,6 +139,11 @@ public SolrMetricsContext getSolrMetricsContext() { @Override public void close() { + try { + SolrMetricProducer.super.close(); + } catch (Exception e) { + log.error("Error closing SolrMetricProducer", e); + } IOUtils.closeQuietly(httpSolrClient); } } From ec1d9b56a2cd9bbbf751d85d32538afba9ae12e6 Mon Sep 17 00:00:00 2001 From: Sanjay Dutt Date: Fri, 6 Sep 2024 18:04:28 +0530 Subject: [PATCH 07/26] refector ReindexCollectionCmd --- .../api/collections/ReindexCollectionCmd.java | 43 ++++++++----------- 1 file changed, 18 insertions(+), 25 deletions(-) diff --git a/solr/core/src/java/org/apache/solr/cloud/api/collections/ReindexCollectionCmd.java b/solr/core/src/java/org/apache/solr/cloud/api/collections/ReindexCollectionCmd.java index 8bc7f85c215..62c95049816 100644 --- a/solr/core/src/java/org/apache/solr/cloud/api/collections/ReindexCollectionCmd.java +++ b/solr/core/src/java/org/apache/solr/cloud/api/collections/ReindexCollectionCmd.java @@ -726,14 +726,6 @@ private void waitForDaemon( String targetCollection, Map reindexingState) throws Exception { - var solrClient = ccc.getCoreContainer().getDefaultHttpClient(); - - ModifiableSolrParams q = new ModifiableSolrParams(); - q.set(CommonParams.QT, "/stream"); - q.set("action", "list"); - q.set(CommonParams.DISTRIB, false); - QueryRequest req = new QueryRequest(q); - req.setBasePath(daemonReplica.getBaseUrl()); boolean isRunning; int statusCheck = 0; @@ -741,7 +733,7 @@ private void waitForDaemon( isRunning = false; statusCheck++; try { - NamedList rsp = solrClient.request(req, daemonReplica.getCoreName()); + NamedList rsp = executeDaemonAction("list", daemonName, daemonReplica); Map rs = (Map) rsp.get("result-set"); if (rs == null || rs.isEmpty()) { throw new SolrException( @@ -787,18 +779,10 @@ private void killDaemon(String daemonName, Replica daemonReplica) throws Excepti log.debug("-- killing daemon {} at {}", daemonName, daemonReplica.getCoreUrl()); } - var solrClient = ccc.getCoreContainer().getDefaultHttpClient(); - ModifiableSolrParams q = new ModifiableSolrParams(); - q.set(CommonParams.QT, "/stream"); // we should really use 'kill' here, but then we will never // know when the daemon actually finishes running - 'kill' only // sets a flag that may be noticed much later - q.set("action", "stop"); - q.set(CommonParams.ID, daemonName); - q.set(CommonParams.DISTRIB, false); - QueryRequest req = new QueryRequest(q); - req.setBasePath(daemonReplica.getBaseUrl()); - NamedList rsp = solrClient.request(req, daemonReplica.getCoreName()); + NamedList rsp = executeDaemonAction("stop", daemonName, daemonReplica); // /result-set/docs/[0]/DaemonOp : Deamon:id killed on coreName if (log.isDebugEnabled()) { log.debug(" -- stop daemon response: {}", Utils.toJSONString(rsp)); @@ -826,13 +810,10 @@ private void killDaemon(String daemonName, Replica daemonReplica) throws Excepti } if (op.contains(daemonName) && op.contains("stopped")) { // now wait for the daemon to really stop - q.set("action", "list"); - req = new QueryRequest(q); - req.setBasePath(daemonReplica.getBaseUrl()); TimeOut timeOut = new TimeOut(60, TimeUnit.SECONDS, ccc.getSolrCloudManager().getTimeSource()); while (!timeOut.hasTimedOut()) { - rsp = solrClient.request(req, daemonReplica.getCoreName()); + rsp = executeDaemonAction("list", daemonName, daemonReplica); rs = (Map) rsp.get("result-set"); if (rs == null || rs.isEmpty()) { log.warn( @@ -875,10 +856,22 @@ private void killDaemon(String daemonName, Replica daemonReplica) throws Excepti } } // now kill it - it's already stopped, this simply removes its status - q.set("action", "kill"); - req = new QueryRequest(q); + executeDaemonAction("kill", daemonName, daemonReplica); + } + + private NamedList executeDaemonAction( + String action, String daemonName, Replica daemonReplica) throws Exception { + var solrClient = ccc.getCoreContainer().getDefaultHttpClient(); + var q = new ModifiableSolrParams(); + q.set(CommonParams.QT, "/stream"); + q.set("action", action); + q.set(CommonParams.ID, daemonName); + q.set(CommonParams.DISTRIB, false); + + QueryRequest req = new QueryRequest(q); req.setBasePath(daemonReplica.getBaseUrl()); - solrClient.request(req, daemonReplica.getCoreName()); + + return solrClient.request(req, daemonReplica.getCoreName()); } private void cleanup( From ee0e8886139fa3121857fc94b365d18598852829 Mon Sep 17 00:00:00 2001 From: Sanjay Dutt Date: Mon, 9 Sep 2024 19:19:04 +0530 Subject: [PATCH 08/26] Added test cases --- .../org/apache/solr/core/CoreContainer.java | 3 +- .../solr/core/HttpSolrClientProvider.java | 102 ++++-------------- .../InstrumentedHttpListenerFactory.java | 16 +++ .../apache/solr/core/TestCoreContainer.java | 43 ++++++++ .../solr/core/TestHttpSolrClientProvider.java | 72 +++++++++++++ 5 files changed, 154 insertions(+), 82 deletions(-) create mode 100644 solr/core/src/test/org/apache/solr/core/TestHttpSolrClientProvider.java diff --git a/solr/core/src/java/org/apache/solr/core/CoreContainer.java b/solr/core/src/java/org/apache/solr/core/CoreContainer.java index 4b79bfeb9aa..c4445885824 100644 --- a/solr/core/src/java/org/apache/solr/core/CoreContainer.java +++ b/solr/core/src/java/org/apache/solr/core/CoreContainer.java @@ -842,8 +842,7 @@ private void loadInternal() { updateShardHandler = new UpdateShardHandler(cfg.getUpdateShardHandlerConfig()); solrClientProvider = new HttpSolrClientProvider(cfg.getUpdateShardHandlerConfig()); updateShardHandler.initializeMetrics(solrMetricsContext, "updateShardHandler"); - solrClientProvider.initializeMetrics( - solrMetricsContext, HttpSolrClientProvider.METRIC_SCOPE_NAME); + solrClientProvider.initializeMetrics(solrMetricsContext); solrClientCache = new SolrClientCache(updateShardHandler.getDefaultHttpClient()); Map cachesConfig = cfg.getCachesConfig(); 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 2c478cd785a..cc00d25ef10 100644 --- a/solr/core/src/java/org/apache/solr/core/HttpSolrClientProvider.java +++ b/solr/core/src/java/org/apache/solr/core/HttpSolrClientProvider.java @@ -16,21 +16,15 @@ */ package org.apache.solr.core; -import static org.apache.solr.util.stats.InstrumentedHttpRequestExecutor.KNOWN_METRIC_NAME_STRATEGIES; - import java.lang.invoke.MethodHandles; import java.util.List; import java.util.concurrent.TimeUnit; import org.apache.solr.client.solrj.impl.Http2SolrClient; -import org.apache.solr.client.solrj.impl.HttpClientUtil; -import org.apache.solr.common.SolrException; import org.apache.solr.common.util.IOUtils; import org.apache.solr.metrics.SolrMetricManager; -import org.apache.solr.metrics.SolrMetricProducer; import org.apache.solr.metrics.SolrMetricsContext; import org.apache.solr.security.HttpClientBuilderPlugin; import org.apache.solr.update.UpdateShardHandlerConfig; -import org.apache.solr.util.stats.HttpClientMetricNameStrategy; import org.apache.solr.util.stats.InstrumentedHttpListenerFactory; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -40,107 +34,55 @@ * * @lucene.internal */ -class HttpSolrClientProvider implements SolrMetricProducer { +class HttpSolrClientProvider { private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass()); - public static final String METRIC_SCOPE_NAME = "defaultHttpSolrClientProvider"; + static final String METRIC_SCOPE_NAME = "defaultHttpSolrClientProvider"; private final Http2SolrClient httpSolrClient; private final InstrumentedHttpListenerFactory trackHttpSolrMetrics; - private SolrMetricsContext solrMetricsContext; - - private int socketTimeout; - - private int connectionTimeout; - - public HttpSolrClientProvider(UpdateShardHandlerConfig cfg) { - Http2SolrClient.Builder httpClientBuilder = new Http2SolrClient.Builder(); + HttpSolrClientProvider(UpdateShardHandlerConfig cfg) { trackHttpSolrMetrics = new InstrumentedHttpListenerFactory(getNameStrategy(cfg)); - configureTimeouts(cfg); - - httpClientBuilder - .withConnectionTimeout(connectionTimeout, TimeUnit.MILLISECONDS) - .withIdleTimeout(socketTimeout, TimeUnit.MILLISECONDS) - .withListenerFactory(List.of(trackHttpSolrMetrics)); - - httpSolrClient = httpClientBuilder.build(); - } - - private void configureTimeouts(UpdateShardHandlerConfig cfg) { - socketTimeout = HttpClientUtil.DEFAULT_SO_TIMEOUT; - connectionTimeout = HttpClientUtil.DEFAULT_CONNECT_TIMEOUT; + Http2SolrClient.Builder httpClientBuilder = + new Http2SolrClient.Builder().withListenerFactory(List.of(trackHttpSolrMetrics)); if (cfg != null) { - socketTimeout = Math.max(cfg.getDistributedSocketTimeout(), socketTimeout); - connectionTimeout = Math.max(cfg.getDistributedConnectionTimeout(), connectionTimeout); + httpClientBuilder + .withConnectionTimeout(cfg.getDistributedConnectionTimeout(), TimeUnit.MILLISECONDS) + .withIdleTimeout(cfg.getDistributedSocketTimeout(), TimeUnit.MILLISECONDS); } - } - - private HttpClientMetricNameStrategy getMetricNameStrategy(UpdateShardHandlerConfig cfg) { - HttpClientMetricNameStrategy metricNameStrategy = - KNOWN_METRIC_NAME_STRATEGIES.get(UpdateShardHandlerConfig.DEFAULT_METRICNAMESTRATEGY); - if (cfg != null) { - metricNameStrategy = KNOWN_METRIC_NAME_STRATEGIES.get(cfg.getMetricNameStrategy()); - if (metricNameStrategy == null) { - throw new SolrException( - SolrException.ErrorCode.SERVER_ERROR, - "Unknown metricNameStrategy: " - + cfg.getMetricNameStrategy() - + " found. Must be one of: " - + KNOWN_METRIC_NAME_STRATEGIES.keySet()); - } - } - return metricNameStrategy; + httpSolrClient = httpClientBuilder.build(); } private InstrumentedHttpListenerFactory.NameStrategy getNameStrategy( UpdateShardHandlerConfig cfg) { - InstrumentedHttpListenerFactory.NameStrategy nameStrategy = - InstrumentedHttpListenerFactory.KNOWN_METRIC_NAME_STRATEGIES.get( - UpdateShardHandlerConfig.DEFAULT_METRICNAMESTRATEGY); - - if (cfg != null) { - nameStrategy = - InstrumentedHttpListenerFactory.KNOWN_METRIC_NAME_STRATEGIES.get( - cfg.getMetricNameStrategy()); - if (nameStrategy == null) { - throw new SolrException( - SolrException.ErrorCode.SERVER_ERROR, - "Unknown metricNameStrategy: " - + cfg.getMetricNameStrategy() - + " found. Must be one of: " - + KNOWN_METRIC_NAME_STRATEGIES.keySet()); - } - } - return nameStrategy; + String metricNameStrategy = + cfg != null && cfg.getMetricNameStrategy() != null + ? cfg.getMetricNameStrategy() + : UpdateShardHandlerConfig.DEFAULT_METRICNAMESTRATEGY; + return InstrumentedHttpListenerFactory.getNameStrategy(metricNameStrategy); } - public Http2SolrClient getSolrClient() { + Http2SolrClient getSolrClient() { return httpSolrClient; } - public void setSecurityBuilder(HttpClientBuilderPlugin builder) { + void setSecurityBuilder(HttpClientBuilderPlugin builder) { builder.setup(httpSolrClient); } - @Override - public void initializeMetrics(SolrMetricsContext parentContext, String scope) { - solrMetricsContext = parentContext.getChildContext(this); - String expandedScope = SolrMetricManager.mkName(scope, SolrInfoBean.Category.HTTP.name()); + void initializeMetrics(SolrMetricsContext parentContext) { + var solrMetricsContext = parentContext.getChildContext(this); + String expandedScope = + SolrMetricManager.mkName(METRIC_SCOPE_NAME, SolrInfoBean.Category.HTTP.name()); trackHttpSolrMetrics.initializeMetrics(solrMetricsContext, expandedScope); } - @Override - public SolrMetricsContext getSolrMetricsContext() { - return solrMetricsContext; - } - - @Override - public void close() { + void close() { try { - SolrMetricProducer.super.close(); + trackHttpSolrMetrics.close(); } catch (Exception e) { log.error("Error closing SolrMetricProducer", e); } diff --git a/solr/core/src/java/org/apache/solr/util/stats/InstrumentedHttpListenerFactory.java b/solr/core/src/java/org/apache/solr/util/stats/InstrumentedHttpListenerFactory.java index 31523a5882f..025b6c1793b 100644 --- a/solr/core/src/java/org/apache/solr/util/stats/InstrumentedHttpListenerFactory.java +++ b/solr/core/src/java/org/apache/solr/util/stats/InstrumentedHttpListenerFactory.java @@ -18,12 +18,14 @@ package org.apache.solr.util.stats; import static org.apache.solr.metrics.SolrMetricManager.mkName; +import static org.apache.solr.util.stats.InstrumentedHttpRequestExecutor.KNOWN_METRIC_NAME_STRATEGIES; import com.codahale.metrics.Timer; import io.opentelemetry.api.trace.Span; import java.util.Locale; import java.util.Map; import org.apache.solr.client.solrj.impl.HttpListenerFactory; +import org.apache.solr.common.SolrException; import org.apache.solr.common.util.CollectionUtil; import org.apache.solr.metrics.SolrMetricProducer; import org.apache.solr.metrics.SolrMetricsContext; @@ -133,4 +135,18 @@ public void initializeMetrics(SolrMetricsContext parentContext, String scope) { public SolrMetricsContext getSolrMetricsContext() { return solrMetricsContext; } + + public static NameStrategy getNameStrategy(String name) { + InstrumentedHttpListenerFactory.NameStrategy nameStrategy = + InstrumentedHttpListenerFactory.KNOWN_METRIC_NAME_STRATEGIES.get(name); + if (nameStrategy == null) { + throw new SolrException( + SolrException.ErrorCode.SERVER_ERROR, + "Unknown metricNameStrategy: " + + name + + " found. Must be one of: " + + KNOWN_METRIC_NAME_STRATEGIES.keySet()); + } + return nameStrategy; + } } diff --git a/solr/core/src/test/org/apache/solr/core/TestCoreContainer.java b/solr/core/src/test/org/apache/solr/core/TestCoreContainer.java index 4aaea27c857..3e9afc4f4aa 100644 --- a/solr/core/src/test/org/apache/solr/core/TestCoreContainer.java +++ b/solr/core/src/test/org/apache/solr/core/TestCoreContainer.java @@ -40,6 +40,7 @@ import java.util.regex.Pattern; import org.apache.commons.exec.OS; import org.apache.solr.SolrTestCaseJ4; +import org.apache.solr.client.solrj.impl.HttpClientUtil; import org.apache.solr.common.SolrException; import org.apache.solr.handler.admin.CollectionsHandler; import org.apache.solr.handler.admin.ConfigSetsHandler; @@ -1131,6 +1132,48 @@ public void testCoreInitFailuresOnReload() throws Exception { cc.shutdown(); } + public void testCustomSocketTimeoutForDefaultHttpClient() throws Exception { + CoreContainer cc = null; + var socketTimeout = 15000; + try { + String solrXml = + "\n" + + "\n" + + "\n" + + " " + + socketTimeout + + "\n" + + "" + + ""; + cc = init(solrXml); + var http2SolrClient = cc.getDefaultHttpClient(); + assertEquals(http2SolrClient.getIdleTimeout(), socketTimeout); + } finally { + if (cc != null) { + cc.shutdown(); + } + } + } + + public void testDefaultSocketTimeoutForDefaultHttpClient() throws Exception { + CoreContainer cc = null; + try { + String solrXml = + "\n" + + "\n" + + "\n" + + "" + + ""; + cc = init(solrXml); + var http2SolrClient = cc.getDefaultHttpClient(); + assertEquals(http2SolrClient.getIdleTimeout(), HttpClientUtil.DEFAULT_SO_TIMEOUT); + } finally { + if (cc != null) { + cc.shutdown(); + } + } + } + private long getCoreStartTime(final CoreContainer cc, final String name) { try (SolrCore tmp = cc.getCore(name)) { return tmp.getStartTimeStamp().getTime(); diff --git a/solr/core/src/test/org/apache/solr/core/TestHttpSolrClientProvider.java b/solr/core/src/test/org/apache/solr/core/TestHttpSolrClientProvider.java new file mode 100644 index 00000000000..bebda1c8b94 --- /dev/null +++ b/solr/core/src/test/org/apache/solr/core/TestHttpSolrClientProvider.java @@ -0,0 +1,72 @@ +/* + * 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.core; + +import static org.junit.Assert.assertEquals; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; + +import org.apache.solr.client.solrj.impl.HttpClientUtil; +import org.apache.solr.metrics.SolrMetricsContext; +import org.apache.solr.update.UpdateShardHandlerConfig; +import org.junit.Test; +import org.mockito.Mockito; + +public class TestHttpSolrClientProvider { + + HttpSolrClientProvider httpSolrClientProvider; + + @Test + public void test_when_updateShardHandler_cfg_is_null() { + try { + httpSolrClientProvider = new HttpSolrClientProvider(null); + assertEquals( + httpSolrClientProvider.getSolrClient().getIdleTimeout(), + HttpClientUtil.DEFAULT_SO_TIMEOUT); + } finally { + httpSolrClientProvider.close(); + } + } + + @Test + public void test_when_updateShardHandler_cfg_is_not_null() { + var idleTimeout = 10000; + UpdateShardHandlerConfig cfg = new UpdateShardHandlerConfig(-1, -1, idleTimeout, -1, null, -1); + try { + httpSolrClientProvider = new HttpSolrClientProvider(cfg); + assertEquals(httpSolrClientProvider.getSolrClient().getIdleTimeout(), idleTimeout); + } finally { + httpSolrClientProvider.close(); + } + } + + @Test + public void test_closing_solr_metric_context() { + SolrMetricsContext childSolrMetricContext = Mockito.mock(SolrMetricsContext.class); + SolrMetricsContext parentSolrMetricCtx = Mockito.mock(SolrMetricsContext.class); + Mockito.when(parentSolrMetricCtx.getChildContext(any(HttpSolrClientProvider.class))) + .thenReturn(childSolrMetricContext); + try { + httpSolrClientProvider = new HttpSolrClientProvider(null); + httpSolrClientProvider.initializeMetrics(parentSolrMetricCtx); + } finally { + httpSolrClientProvider.close(); + verify(childSolrMetricContext, times(1)).unregister(); + } + } +} From 7729fd9631af86af13e62b33e8392e9a8045954e Mon Sep 17 00:00:00 2001 From: Sanjay Dutt Date: Mon, 9 Sep 2024 20:01:03 +0530 Subject: [PATCH 09/26] tidy code --- .../util/stats/InstrumentedHttpListenerFactory.java | 3 +-- .../apache/solr/core/TestHttpSolrClientProvider.java | 12 ++++++++++-- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/solr/core/src/java/org/apache/solr/util/stats/InstrumentedHttpListenerFactory.java b/solr/core/src/java/org/apache/solr/util/stats/InstrumentedHttpListenerFactory.java index 025b6c1793b..ae27a52840c 100644 --- a/solr/core/src/java/org/apache/solr/util/stats/InstrumentedHttpListenerFactory.java +++ b/solr/core/src/java/org/apache/solr/util/stats/InstrumentedHttpListenerFactory.java @@ -18,7 +18,6 @@ package org.apache.solr.util.stats; import static org.apache.solr.metrics.SolrMetricManager.mkName; -import static org.apache.solr.util.stats.InstrumentedHttpRequestExecutor.KNOWN_METRIC_NAME_STRATEGIES; import com.codahale.metrics.Timer; import io.opentelemetry.api.trace.Span; @@ -138,7 +137,7 @@ public SolrMetricsContext getSolrMetricsContext() { public static NameStrategy getNameStrategy(String name) { InstrumentedHttpListenerFactory.NameStrategy nameStrategy = - InstrumentedHttpListenerFactory.KNOWN_METRIC_NAME_STRATEGIES.get(name); + KNOWN_METRIC_NAME_STRATEGIES.get(name); if (nameStrategy == null) { throw new SolrException( SolrException.ErrorCode.SERVER_ERROR, diff --git a/solr/core/src/test/org/apache/solr/core/TestHttpSolrClientProvider.java b/solr/core/src/test/org/apache/solr/core/TestHttpSolrClientProvider.java index bebda1c8b94..1e902f3ac22 100644 --- a/solr/core/src/test/org/apache/solr/core/TestHttpSolrClientProvider.java +++ b/solr/core/src/test/org/apache/solr/core/TestHttpSolrClientProvider.java @@ -16,21 +16,29 @@ */ package org.apache.solr.core; -import static org.junit.Assert.assertEquals; +import static org.apache.solr.SolrTestCaseJ4.assumeWorkingMockito; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; +import org.apache.solr.SolrTestCase; import org.apache.solr.client.solrj.impl.HttpClientUtil; import org.apache.solr.metrics.SolrMetricsContext; import org.apache.solr.update.UpdateShardHandlerConfig; +import org.junit.Before; import org.junit.Test; import org.mockito.Mockito; -public class TestHttpSolrClientProvider { +public class TestHttpSolrClientProvider extends SolrTestCase { HttpSolrClientProvider httpSolrClientProvider; + @Before + public void setUp() throws Exception { + super.setUp(); + assumeWorkingMockito(); + } + @Test public void test_when_updateShardHandler_cfg_is_null() { try { From f27a07fd7173c62e1dd3f5f3d488fe35197eafa0 Mon Sep 17 00:00:00 2001 From: Sanjay Dutt Date: Mon, 9 Sep 2024 20:22:30 +0530 Subject: [PATCH 10/26] Revert default usage to http2 for now --- .../api/collections/ReindexCollectionCmd.java | 275 ++++++++++-------- .../security/PKIAuthenticationPlugin.java | 34 +-- 2 files changed, 162 insertions(+), 147 deletions(-) diff --git a/solr/core/src/java/org/apache/solr/cloud/api/collections/ReindexCollectionCmd.java b/solr/core/src/java/org/apache/solr/cloud/api/collections/ReindexCollectionCmd.java index 62c95049816..91299b3c259 100644 --- a/solr/core/src/java/org/apache/solr/cloud/api/collections/ReindexCollectionCmd.java +++ b/solr/core/src/java/org/apache/solr/cloud/api/collections/ReindexCollectionCmd.java @@ -31,9 +31,12 @@ import java.util.function.Function; import java.util.stream.Collectors; import java.util.stream.Stream; +import org.apache.http.client.HttpClient; +import org.apache.solr.client.solrj.SolrClient; import org.apache.solr.client.solrj.SolrResponse; import org.apache.solr.client.solrj.cloud.DistribStateManager; import org.apache.solr.client.solrj.impl.CloudSolrClient; +import org.apache.solr.client.solrj.impl.HttpSolrClient; import org.apache.solr.client.solrj.request.CollectionAdminRequest; import org.apache.solr.client.solrj.request.QueryRequest; import org.apache.solr.client.solrj.response.QueryResponse; @@ -726,51 +729,62 @@ private void waitForDaemon( String targetCollection, Map reindexingState) throws Exception { - - boolean isRunning; - int statusCheck = 0; - do { - isRunning = false; - statusCheck++; - try { - NamedList rsp = executeDaemonAction("list", daemonName, daemonReplica); - Map rs = (Map) rsp.get("result-set"); - if (rs == null || rs.isEmpty()) { - throw new SolrException( - SolrException.ErrorCode.SERVER_ERROR, - "Can't find daemon list: missing result-set: " + Utils.toJSONString(rsp)); - } - List list = (List) rs.get("docs"); - if (list == null) { + HttpClient client = ccc.getCoreContainer().getUpdateShardHandler().getDefaultHttpClient(); + try (SolrClient solrClient = + new HttpSolrClient.Builder() + .withHttpClient(client) + .withBaseSolrUrl(daemonReplica.getBaseUrl()) + .build()) { + ModifiableSolrParams q = new ModifiableSolrParams(); + q.set(CommonParams.QT, "/stream"); + q.set("action", "list"); + q.set(CommonParams.DISTRIB, false); + QueryRequest req = new QueryRequest(q); + boolean isRunning; + int statusCheck = 0; + do { + isRunning = false; + statusCheck++; + try { + NamedList rsp = solrClient.request(req, daemonReplica.getCoreName()); + Map rs = (Map) rsp.get("result-set"); + if (rs == null || rs.isEmpty()) { + throw new SolrException( + SolrException.ErrorCode.SERVER_ERROR, + "Can't find daemon list: missing result-set: " + Utils.toJSONString(rsp)); + } + List list = (List) rs.get("docs"); + if (list == null) { + throw new SolrException( + SolrException.ErrorCode.SERVER_ERROR, + "Can't find daemon list: missing result-set: " + Utils.toJSONString(rsp)); + } + if (list.isEmpty()) { // finished? + break; + } + for (Object o : list) { + Map map = (Map) o; + String id = (String) map.get("id"); + if (daemonName.equals(id)) { + isRunning = true; + // fail here + TestInjection.injectReindexFailure(); + break; + } + } + } catch (Exception e) { throw new SolrException( SolrException.ErrorCode.SERVER_ERROR, - "Can't find daemon list: missing result-set: " + Utils.toJSONString(rsp)); - } - if (list.isEmpty()) { // finished? - break; + "Exception waiting for daemon " + daemonName + " at " + daemonReplica.getCoreUrl(), + e); } - for (Object o : list) { - Map map = (Map) o; - String id = (String) map.get("id"); - if (daemonName.equals(id)) { - isRunning = true; - // fail here - TestInjection.injectReindexFailure(); - break; - } + if (statusCheck % 5 == 0) { + reindexingState.put("processedDocs", getNumberOfDocs(targetCollection)); + setReindexingState(sourceCollection, State.RUNNING, reindexingState); } - } catch (Exception e) { - throw new SolrException( - SolrException.ErrorCode.SERVER_ERROR, - "Exception waiting for daemon " + daemonName + " at " + daemonReplica.getCoreUrl(), - e); - } - if (statusCheck % 5 == 0) { - reindexingState.put("processedDocs", getNumberOfDocs(targetCollection)); - setReindexingState(sourceCollection, State.RUNNING, reindexingState); - } - ccc.getSolrCloudManager().getTimeSource().sleep(2000); - } while (isRunning && !maybeAbort(sourceCollection)); + ccc.getSolrCloudManager().getTimeSource().sleep(2000); + } while (isRunning && !maybeAbort(sourceCollection)); + } } @SuppressWarnings({"unchecked"}) @@ -778,100 +792,107 @@ private void killDaemon(String daemonName, Replica daemonReplica) throws Excepti if (log.isDebugEnabled()) { log.debug("-- killing daemon {} at {}", daemonName, daemonReplica.getCoreUrl()); } - - // we should really use 'kill' here, but then we will never - // know when the daemon actually finishes running - 'kill' only - // sets a flag that may be noticed much later - NamedList rsp = executeDaemonAction("stop", daemonName, daemonReplica); - // /result-set/docs/[0]/DaemonOp : Deamon:id killed on coreName - if (log.isDebugEnabled()) { - log.debug(" -- stop daemon response: {}", Utils.toJSONString(rsp)); - } - Map rs = (Map) rsp.get("result-set"); - if (rs == null || rs.isEmpty()) { - log.warn( - "Problem killing daemon {}: missing result-set: {}", daemonName, Utils.toJSONString(rsp)); - return; - } - List list = (List) rs.get("docs"); - if (list == null) { - log.warn( - "Problem killing daemon {}: missing result-set: {}", daemonName, Utils.toJSONString(rsp)); - return; - } - if (list.isEmpty()) { // already finished? - return; - } - for (Object o : list) { - Map map = (Map) o; - String op = (String) map.get("DaemonOp"); - if (op == null) { - continue; + HttpClient client = ccc.getCoreContainer().getUpdateShardHandler().getDefaultHttpClient(); + try (SolrClient solrClient = + new HttpSolrClient.Builder() + .withHttpClient(client) + .withDefaultCollection(daemonReplica.getCoreName()) + .withBaseSolrUrl(daemonReplica.getBaseUrl()) + .build()) { + ModifiableSolrParams q = new ModifiableSolrParams(); + q.set(CommonParams.QT, "/stream"); + // we should really use 'kill' here, but then we will never + // know when the daemon actually finishes running - 'kill' only + // sets a flag that may be noticed much later + q.set("action", "stop"); + q.set(CommonParams.ID, daemonName); + q.set(CommonParams.DISTRIB, false); + QueryRequest req = new QueryRequest(q); + NamedList rsp = solrClient.request(req); + // /result-set/docs/[0]/DaemonOp : Deamon:id killed on coreName + if (log.isDebugEnabled()) { + log.debug(" -- stop daemon response: {}", Utils.toJSONString(rsp)); + } + Map rs = (Map) rsp.get("result-set"); + if (rs == null || rs.isEmpty()) { + log.warn( + "Problem killing daemon {}: missing result-set: {}", + daemonName, + Utils.toJSONString(rsp)); + return; } - if (op.contains(daemonName) && op.contains("stopped")) { - // now wait for the daemon to really stop - TimeOut timeOut = - new TimeOut(60, TimeUnit.SECONDS, ccc.getSolrCloudManager().getTimeSource()); - while (!timeOut.hasTimedOut()) { - rsp = executeDaemonAction("list", daemonName, daemonReplica); - rs = (Map) rsp.get("result-set"); - if (rs == null || rs.isEmpty()) { - log.warn( - "Problem killing daemon {}: missing result-set: {}", - daemonName, - Utils.toJSONString(rsp)); - break; - } - List list2 = (List) rs.get("docs"); - if (list2 == null) { - log.warn( - "Problem killing daemon {}: missing result-set: {}", - daemonName, - Utils.toJSONString(rsp)); - break; - } - if (list2.isEmpty()) { // already finished? - break; - } - Map status2 = null; - for (Object o2 : list2) { - Map map2 = (Map) o2; - if (daemonName.equals(map2.get("id"))) { - status2 = map2; + List list = (List) rs.get("docs"); + if (list == null) { + log.warn( + "Problem killing daemon {}: missing result-set: {}", + daemonName, + Utils.toJSONString(rsp)); + return; + } + if (list.isEmpty()) { // already finished? + return; + } + for (Object o : list) { + Map map = (Map) o; + String op = (String) map.get("DaemonOp"); + if (op == null) { + continue; + } + if (op.contains(daemonName) && op.contains("stopped")) { + // now wait for the daemon to really stop + q.set("action", "list"); + req = new QueryRequest(q); + TimeOut timeOut = + new TimeOut(60, TimeUnit.SECONDS, ccc.getSolrCloudManager().getTimeSource()); + while (!timeOut.hasTimedOut()) { + rsp = solrClient.request(req); + rs = (Map) rsp.get("result-set"); + if (rs == null || rs.isEmpty()) { + log.warn( + "Problem killing daemon {}: missing result-set: {}", + daemonName, + Utils.toJSONString(rsp)); + break; + } + List list2 = (List) rs.get("docs"); + if (list2 == null) { + log.warn( + "Problem killing daemon {}: missing result-set: {}", + daemonName, + Utils.toJSONString(rsp)); + break; + } + if (list2.isEmpty()) { // already finished? + break; + } + Map status2 = null; + for (Object o2 : list2) { + Map map2 = (Map) o2; + if (daemonName.equals(map2.get("id"))) { + status2 = map2; + break; + } + } + if (status2 == null) { // finished? + break; + } + Number stopTime = (Number) status2.get("stopTime"); + if (stopTime.longValue() > 0) { break; } } - if (status2 == null) { // finished? - break; - } - Number stopTime = (Number) status2.get("stopTime"); - if (stopTime.longValue() > 0) { - break; + if (timeOut.hasTimedOut()) { + log.warn( + "Problem killing daemon {}: timed out waiting for daemon to stop.", daemonName); + // proceed anyway } } - if (timeOut.hasTimedOut()) { - log.warn("Problem killing daemon {}: timed out waiting for daemon to stop.", daemonName); - // proceed anyway - } } + // now kill it - it's already stopped, this simply removes its status + q.set("action", "kill"); + req = new QueryRequest(q); + solrClient.request(req); } - // now kill it - it's already stopped, this simply removes its status - executeDaemonAction("kill", daemonName, daemonReplica); - } - - private NamedList executeDaemonAction( - String action, String daemonName, Replica daemonReplica) throws Exception { - var solrClient = ccc.getCoreContainer().getDefaultHttpClient(); - var q = new ModifiableSolrParams(); - q.set(CommonParams.QT, "/stream"); - q.set("action", action); - q.set(CommonParams.ID, daemonName); - q.set(CommonParams.DISTRIB, false); - - QueryRequest req = new QueryRequest(q); - req.setBasePath(daemonReplica.getBaseUrl()); - - return solrClient.request(req, daemonReplica.getCoreName()); } private void cleanup( diff --git a/solr/core/src/java/org/apache/solr/security/PKIAuthenticationPlugin.java b/solr/core/src/java/org/apache/solr/security/PKIAuthenticationPlugin.java index 74ecc88d8f9..b1f6e6b6eed 100644 --- a/solr/core/src/java/org/apache/solr/security/PKIAuthenticationPlugin.java +++ b/solr/core/src/java/org/apache/solr/security/PKIAuthenticationPlugin.java @@ -41,17 +41,16 @@ import org.apache.http.HttpHeaders; import org.apache.http.HttpRequest; import org.apache.http.HttpRequestInterceptor; +import org.apache.http.HttpResponse; import org.apache.http.auth.BasicUserPrincipal; +import org.apache.http.client.methods.HttpGet; import org.apache.http.protocol.HttpContext; -import org.apache.solr.client.solrj.SolrRequest; +import org.apache.http.util.EntityUtils; import org.apache.solr.client.solrj.impl.Http2SolrClient; import org.apache.solr.client.solrj.impl.HttpClientUtil; import org.apache.solr.client.solrj.impl.HttpListenerFactory; import org.apache.solr.client.solrj.impl.SolrHttpClientBuilder; -import org.apache.solr.client.solrj.request.GenericSolrRequest; -import org.apache.solr.common.params.ModifiableSolrParams; import org.apache.solr.common.util.ExecutorUtil; -import org.apache.solr.common.util.NamedList; import org.apache.solr.common.util.StrUtils; import org.apache.solr.common.util.SuppressForbidden; import org.apache.solr.common.util.Utils; @@ -347,28 +346,23 @@ PublicKey fetchPublicKeyFromRemote(String nodename) { String url = cores.getZkController().getZkStateReader().getBaseUrlForNodeName(nodename); HttpEntity entity = null; try { - ModifiableSolrParams solrParams = new ModifiableSolrParams(); - solrParams.add("wt", "json"); - solrParams.add("omitHeader", "true"); - - GenericSolrRequest request = - new GenericSolrRequest(SolrRequest.METHOD.GET, PublicKeyHandler.PATH, solrParams); - request.setBasePath(url); - - final var solrClient = cores.getDefaultHttpClient(); - - log.debug("Fetching fresh public key from: {}{}", url, PublicKeyHandler.PATH); - NamedList resp = solrClient.request(request); - - String key = (String) resp.get("key"); - + String uri = url + PublicKeyHandler.PATH + "?wt=json&omitHeader=true"; + log.debug("Fetching fresh public key from: {}", uri); + HttpResponse rsp = + cores + .getUpdateShardHandler() + .getDefaultHttpClient() + .execute(new HttpGet(uri), HttpClientUtil.createNewHttpClientRequestContext()); + entity = rsp.getEntity(); + byte[] bytes = EntityUtils.toByteArray(entity); + Map m = (Map) Utils.fromJSON(bytes); + String key = (String) m.get("key"); if (key == null) { log.error("No key available from {}{}", url, PublicKeyHandler.PATH); return null; } else { log.info("New key obtained from node={}, key={}", nodename, key); } - PublicKey pubKey = CryptoKeys.deserializeX509PublicKey(key); keyCache.put(nodename, pubKey); return pubKey; From c7e8ed9176acf74395edd8f9d118378cba43d69f Mon Sep 17 00:00:00 2001 From: Sanjay Dutt Date: Mon, 9 Sep 2024 20:37:16 +0530 Subject: [PATCH 11/26] Added override anotation for setup --- .../test/org/apache/solr/core/TestHttpSolrClientProvider.java | 1 + 1 file changed, 1 insertion(+) diff --git a/solr/core/src/test/org/apache/solr/core/TestHttpSolrClientProvider.java b/solr/core/src/test/org/apache/solr/core/TestHttpSolrClientProvider.java index 1e902f3ac22..dea34e5ecb9 100644 --- a/solr/core/src/test/org/apache/solr/core/TestHttpSolrClientProvider.java +++ b/solr/core/src/test/org/apache/solr/core/TestHttpSolrClientProvider.java @@ -33,6 +33,7 @@ public class TestHttpSolrClientProvider extends SolrTestCase { HttpSolrClientProvider httpSolrClientProvider; + @Override @Before public void setUp() throws Exception { super.setUp(); From bebaf2dd8d25fa4df84569fc5a43a8955ab227a0 Mon Sep 17 00:00:00 2001 From: Sanjay Dutt Date: Tue, 10 Sep 2024 20:17:36 +0530 Subject: [PATCH 12/26] Reverting TestCoreContainer --- .../apache/solr/core/TestCoreContainer.java | 43 ------------------- 1 file changed, 43 deletions(-) diff --git a/solr/core/src/test/org/apache/solr/core/TestCoreContainer.java b/solr/core/src/test/org/apache/solr/core/TestCoreContainer.java index 3e9afc4f4aa..4aaea27c857 100644 --- a/solr/core/src/test/org/apache/solr/core/TestCoreContainer.java +++ b/solr/core/src/test/org/apache/solr/core/TestCoreContainer.java @@ -40,7 +40,6 @@ import java.util.regex.Pattern; import org.apache.commons.exec.OS; import org.apache.solr.SolrTestCaseJ4; -import org.apache.solr.client.solrj.impl.HttpClientUtil; import org.apache.solr.common.SolrException; import org.apache.solr.handler.admin.CollectionsHandler; import org.apache.solr.handler.admin.ConfigSetsHandler; @@ -1132,48 +1131,6 @@ public void testCoreInitFailuresOnReload() throws Exception { cc.shutdown(); } - public void testCustomSocketTimeoutForDefaultHttpClient() throws Exception { - CoreContainer cc = null; - var socketTimeout = 15000; - try { - String solrXml = - "\n" - + "\n" - + "\n" - + " " - + socketTimeout - + "\n" - + "" - + ""; - cc = init(solrXml); - var http2SolrClient = cc.getDefaultHttpClient(); - assertEquals(http2SolrClient.getIdleTimeout(), socketTimeout); - } finally { - if (cc != null) { - cc.shutdown(); - } - } - } - - public void testDefaultSocketTimeoutForDefaultHttpClient() throws Exception { - CoreContainer cc = null; - try { - String solrXml = - "\n" - + "\n" - + "\n" - + "" - + ""; - cc = init(solrXml); - var http2SolrClient = cc.getDefaultHttpClient(); - assertEquals(http2SolrClient.getIdleTimeout(), HttpClientUtil.DEFAULT_SO_TIMEOUT); - } finally { - if (cc != null) { - cc.shutdown(); - } - } - } - private long getCoreStartTime(final CoreContainer cc, final String name) { try (SolrCore tmp = cc.getCore(name)) { return tmp.getStartTimeStamp().getTime(); From 6db8ee63ff8093612f52633b67b2fbbbc7ca71b5 Mon Sep 17 00:00:00 2001 From: Sanjay Dutt Date: Tue, 10 Sep 2024 20:26:58 +0530 Subject: [PATCH 13/26] Enabling option for maxUpdateConnectionsPerHost setting for default client --- .../src/java/org/apache/solr/core/HttpSolrClientProvider.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) 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 cc00d25ef10..e237d7fe9c3 100644 --- a/solr/core/src/java/org/apache/solr/core/HttpSolrClientProvider.java +++ b/solr/core/src/java/org/apache/solr/core/HttpSolrClientProvider.java @@ -51,7 +51,8 @@ class HttpSolrClientProvider { if (cfg != null) { httpClientBuilder .withConnectionTimeout(cfg.getDistributedConnectionTimeout(), TimeUnit.MILLISECONDS) - .withIdleTimeout(cfg.getDistributedSocketTimeout(), TimeUnit.MILLISECONDS); + .withIdleTimeout(cfg.getDistributedSocketTimeout(), TimeUnit.MILLISECONDS) + .withMaxConnectionsPerHost(cfg.getMaxUpdateConnectionsPerHost()); } httpSolrClient = httpClientBuilder.build(); } From 212c65b94e5f991e4586312f207419f099383c06 Mon Sep 17 00:00:00 2001 From: Sanjay Dutt Date: Tue, 10 Sep 2024 22:07:28 +0530 Subject: [PATCH 14/26] Change Closeable to AutoCloseable for broader resource management --- .../java/org/apache/solr/core/HttpSolrClientProvider.java | 6 +----- .../solrj/src/java/org/apache/solr/common/util/IOUtils.java | 3 +-- 2 files changed, 2 insertions(+), 7 deletions(-) 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 e237d7fe9c3..3e20fc00b2c 100644 --- a/solr/core/src/java/org/apache/solr/core/HttpSolrClientProvider.java +++ b/solr/core/src/java/org/apache/solr/core/HttpSolrClientProvider.java @@ -82,11 +82,7 @@ void initializeMetrics(SolrMetricsContext parentContext) { } void close() { - try { - trackHttpSolrMetrics.close(); - } catch (Exception e) { - log.error("Error closing SolrMetricProducer", e); - } IOUtils.closeQuietly(httpSolrClient); + IOUtils.closeQuietly(trackHttpSolrMetrics); } } diff --git a/solr/solrj/src/java/org/apache/solr/common/util/IOUtils.java b/solr/solrj/src/java/org/apache/solr/common/util/IOUtils.java index 901b8c722e5..b91553a1813 100644 --- a/solr/solrj/src/java/org/apache/solr/common/util/IOUtils.java +++ b/solr/solrj/src/java/org/apache/solr/common/util/IOUtils.java @@ -16,7 +16,6 @@ */ package org.apache.solr.common.util; -import java.io.Closeable; import java.lang.invoke.MethodHandles; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -24,7 +23,7 @@ public class IOUtils { private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass()); - public static void closeQuietly(Closeable closeable) { + public static void closeQuietly(AutoCloseable closeable) { try { if (closeable != null) { closeable.close(); From 1695d1ede1ab0b4f543fadea74e6c02c40ccee87 Mon Sep 17 00:00:00 2001 From: Sanjay Dutt Date: Thu, 26 Sep 2024 21:27:17 +0530 Subject: [PATCH 15/26] Added doc, chnaged names and return new Http2SolrClient --- .../org/apache/solr/core/CoreContainer.java | 29 ++++++++++++------- .../solr/core/HttpSolrClientProvider.java | 27 +++++++++-------- .../solr/core/TestHttpSolrClientProvider.java | 10 +++---- 3 files changed, 36 insertions(+), 30 deletions(-) diff --git a/solr/core/src/java/org/apache/solr/core/CoreContainer.java b/solr/core/src/java/org/apache/solr/core/CoreContainer.java index c4445885824..72f35dc95d5 100644 --- a/solr/core/src/java/org/apache/solr/core/CoreContainer.java +++ b/solr/core/src/java/org/apache/solr/core/CoreContainer.java @@ -67,7 +67,6 @@ import org.apache.solr.api.ClusterPluginsSource; import org.apache.solr.api.ContainerPluginsRegistry; import org.apache.solr.api.JerseyResource; -import org.apache.solr.client.solrj.SolrClient; import org.apache.solr.client.solrj.impl.Http2SolrClient; import org.apache.solr.client.solrj.impl.HttpClientUtil; import org.apache.solr.client.solrj.impl.SolrHttpClientBuilder; @@ -840,9 +839,9 @@ private void loadInternal() { } updateShardHandler = new UpdateShardHandler(cfg.getUpdateShardHandlerConfig()); - solrClientProvider = new HttpSolrClientProvider(cfg.getUpdateShardHandlerConfig()); + solrClientProvider = + new HttpSolrClientProvider(cfg.getUpdateShardHandlerConfig(), solrMetricsContext); updateShardHandler.initializeMetrics(solrMetricsContext, "updateShardHandler"); - solrClientProvider.initializeMetrics(solrMetricsContext); solrClientCache = new SolrClientCache(updateShardHandler.getDefaultHttpClient()); Map cachesConfig = cfg.getCachesConfig(); @@ -1230,11 +1229,6 @@ private void reloadSecurityProperties() { initializeAuditloggerPlugin((Map) securityConfig.getData().get("auditlogging")); } - private SolrClient createDefaultHttpSolrClient() { - - return null; - } - private void warnUsersOfInsecureSettings() { if (authenticationPlugin == null || authorizationPlugin == null) { log.warn( @@ -2577,9 +2571,22 @@ public PlacementPluginFactory getPlacementPlugi return this.distributedCollectionCommandRunner; } - /** Returns default http solr client. */ - public Http2SolrClient getDefaultHttpClient() { - return solrClientProvider.getSolrClient(); + /** + * Creates a general-purpose HTTP/2 Solr client, re-using the existing client from {@link + * HttpSolrClientProvider}. + * + *

The base path is set at the client level as {@link + * org.apache.solr.client.solrj.SolrRequest#setBasePath(String)} is deprecated. This method is + * experimental, and the caller is responsible for managing the client lifecycle (e.g., using + * try-with-resources). + * + * @param basePath the base URL for the Solr client. + * @return a new {@link Http2SolrClient} using the provided base path. + */ + public Http2SolrClient getDefaultHttpSolrClient(String basePath) { + return new Http2SolrClient.Builder(basePath) + .withHttpClient(solrClientProvider.getSolrClient()) + .build(); } /** 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 3e20fc00b2c..2bf25a896f6 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.lang.invoke.MethodHandles; import java.util.List; import java.util.concurrent.TimeUnit; import org.apache.solr.client.solrj.impl.Http2SolrClient; @@ -26,16 +25,13 @@ import org.apache.solr.security.HttpClientBuilderPlugin; import org.apache.solr.update.UpdateShardHandlerConfig; import org.apache.solr.util.stats.InstrumentedHttpListenerFactory; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; /** * Provider of the default SolrClient implementation. * * @lucene.internal */ -class HttpSolrClientProvider { - private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass()); +final class HttpSolrClientProvider implements AutoCloseable { static final String METRIC_SCOPE_NAME = "defaultHttpSolrClientProvider"; @@ -43,8 +39,10 @@ class HttpSolrClientProvider { private final InstrumentedHttpListenerFactory trackHttpSolrMetrics; - HttpSolrClientProvider(UpdateShardHandlerConfig cfg) { + HttpSolrClientProvider(UpdateShardHandlerConfig cfg, SolrMetricsContext parentContext) { trackHttpSolrMetrics = new InstrumentedHttpListenerFactory(getNameStrategy(cfg)); + initializeMetrics(parentContext); + Http2SolrClient.Builder httpClientBuilder = new Http2SolrClient.Builder().withListenerFactory(List.of(trackHttpSolrMetrics)); @@ -66,6 +64,13 @@ private InstrumentedHttpListenerFactory.NameStrategy getNameStrategy( return InstrumentedHttpListenerFactory.getNameStrategy(metricNameStrategy); } + private void initializeMetrics(SolrMetricsContext parentContext) { + var solrMetricsContext = parentContext.getChildContext(this); + String expandedScope = + SolrMetricManager.mkName(METRIC_SCOPE_NAME, SolrInfoBean.Category.HTTP.name()); + trackHttpSolrMetrics.initializeMetrics(solrMetricsContext, expandedScope); + } + Http2SolrClient getSolrClient() { return httpSolrClient; } @@ -74,14 +79,8 @@ void setSecurityBuilder(HttpClientBuilderPlugin builder) { builder.setup(httpSolrClient); } - void initializeMetrics(SolrMetricsContext parentContext) { - var solrMetricsContext = parentContext.getChildContext(this); - String expandedScope = - SolrMetricManager.mkName(METRIC_SCOPE_NAME, SolrInfoBean.Category.HTTP.name()); - trackHttpSolrMetrics.initializeMetrics(solrMetricsContext, expandedScope); - } - - void close() { + @Override + public void close() { IOUtils.closeQuietly(httpSolrClient); IOUtils.closeQuietly(trackHttpSolrMetrics); } diff --git a/solr/core/src/test/org/apache/solr/core/TestHttpSolrClientProvider.java b/solr/core/src/test/org/apache/solr/core/TestHttpSolrClientProvider.java index dea34e5ecb9..28fe819df30 100644 --- a/solr/core/src/test/org/apache/solr/core/TestHttpSolrClientProvider.java +++ b/solr/core/src/test/org/apache/solr/core/TestHttpSolrClientProvider.java @@ -32,18 +32,20 @@ public class TestHttpSolrClientProvider extends SolrTestCase { HttpSolrClientProvider httpSolrClientProvider; + SolrMetricsContext parentSolrMetricCtx; @Override @Before public void setUp() throws Exception { super.setUp(); assumeWorkingMockito(); + parentSolrMetricCtx = Mockito.mock(SolrMetricsContext.class); } @Test public void test_when_updateShardHandler_cfg_is_null() { try { - httpSolrClientProvider = new HttpSolrClientProvider(null); + httpSolrClientProvider = new HttpSolrClientProvider(null, parentSolrMetricCtx); assertEquals( httpSolrClientProvider.getSolrClient().getIdleTimeout(), HttpClientUtil.DEFAULT_SO_TIMEOUT); @@ -57,7 +59,7 @@ public void test_when_updateShardHandler_cfg_is_not_null() { var idleTimeout = 10000; UpdateShardHandlerConfig cfg = new UpdateShardHandlerConfig(-1, -1, idleTimeout, -1, null, -1); try { - httpSolrClientProvider = new HttpSolrClientProvider(cfg); + httpSolrClientProvider = new HttpSolrClientProvider(cfg, parentSolrMetricCtx); assertEquals(httpSolrClientProvider.getSolrClient().getIdleTimeout(), idleTimeout); } finally { httpSolrClientProvider.close(); @@ -67,12 +69,10 @@ public void test_when_updateShardHandler_cfg_is_not_null() { @Test public void test_closing_solr_metric_context() { SolrMetricsContext childSolrMetricContext = Mockito.mock(SolrMetricsContext.class); - SolrMetricsContext parentSolrMetricCtx = Mockito.mock(SolrMetricsContext.class); Mockito.when(parentSolrMetricCtx.getChildContext(any(HttpSolrClientProvider.class))) .thenReturn(childSolrMetricContext); try { - httpSolrClientProvider = new HttpSolrClientProvider(null); - httpSolrClientProvider.initializeMetrics(parentSolrMetricCtx); + httpSolrClientProvider = new HttpSolrClientProvider(null, parentSolrMetricCtx); } finally { httpSolrClientProvider.close(); verify(childSolrMetricContext, times(1)).unregister(); From f849ad09a2a4bd4cb669f40b2db4f0e7cb36009c Mon Sep 17 00:00:00 2001 From: Sanjay Dutt Date: Fri, 4 Oct 2024 12:24:44 +0530 Subject: [PATCH 16/26] Added doc and changed method signature --- .../org/apache/solr/core/CoreContainer.java | 18 ++++++------------ .../apache/solr/update/UpdateShardHandler.java | 12 +++++++++++- 2 files changed, 17 insertions(+), 13 deletions(-) diff --git a/solr/core/src/java/org/apache/solr/core/CoreContainer.java b/solr/core/src/java/org/apache/solr/core/CoreContainer.java index 6093a50eada..b78475d8ad5 100644 --- a/solr/core/src/java/org/apache/solr/core/CoreContainer.java +++ b/solr/core/src/java/org/apache/solr/core/CoreContainer.java @@ -2563,21 +2563,15 @@ public PlacementPluginFactory getPlacementPlugi } /** - * Creates a general-purpose HTTP/2 Solr client, re-using the existing client from {@link - * HttpSolrClientProvider}. + * Provides the existing general-purpose HTTP/2 Solr client from {@link HttpSolrClientProvider}. * - *

The base path is set at the client level as {@link - * org.apache.solr.client.solrj.SolrRequest#setBasePath(String)} is deprecated. This method is - * experimental, and the caller is responsible for managing the client lifecycle (e.g., using - * try-with-resources). + *

The caller does not need to close the client, as its lifecycle is managed by {@link + * HttpSolrClientProvider}. * - * @param basePath the base URL for the Solr client. - * @return a new {@link Http2SolrClient} using the provided base path. + * @return the existing {@link Http2SolrClient} */ - public Http2SolrClient getDefaultHttpSolrClient(String basePath) { - return new Http2SolrClient.Builder(basePath) - .withHttpClient(solrClientProvider.getSolrClient()) - .build(); + public Http2SolrClient getDefaultHttpSolrClient() { + return solrClientProvider.getSolrClient(); } /** 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 650a61dc41d..f03ef161441 100644 --- a/solr/core/src/java/org/apache/solr/update/UpdateShardHandler.java +++ b/solr/core/src/java/org/apache/solr/update/UpdateShardHandler.java @@ -236,7 +236,17 @@ public SolrMetricsContext getSolrMetricsContext() { return solrMetricsContext; } - // if you are looking for a client to use, it's probably this one. + /** + * Returns the default HTTP client for general-purpose usage. + * + *

This method is deprecated as the default client is now provided by {@link + * org.apache.solr.core.CoreContainer#getDefaultHttpSolrClient()}. Users should prefer that method + * to retrieve the default Solr client. + * + * @return the default {@link HttpClient}. + * @deprecated Use {@link org.apache.solr.core.CoreContainer#getDefaultHttpSolrClient()} instead. + */ + @Deprecated public HttpClient getDefaultHttpClient() { return defaultClient; } From dffd95c9ef9686583909f1a5d1386f51a4ec7359 Mon Sep 17 00:00:00 2001 From: Sanjay Dutt Date: Fri, 4 Oct 2024 19:16:57 +0530 Subject: [PATCH 17/26] Replace usage of default apache http client --- .../java/org/apache/solr/cloud/Overseer.java | 11 +- .../api/collections/ReindexCollectionCmd.java | 278 ++++++++---------- .../solr/filestore/DistribFileStore.java | 128 +++++--- .../java/org/apache/solr/pkg/PackageAPI.java | 60 +++- .../security/PKIAuthenticationPlugin.java | 47 +-- 5 files changed, 306 insertions(+), 218 deletions(-) diff --git a/solr/core/src/java/org/apache/solr/cloud/Overseer.java b/solr/core/src/java/org/apache/solr/cloud/Overseer.java index bd91a226a5d..a53b54bdfa9 100644 --- a/solr/core/src/java/org/apache/solr/cloud/Overseer.java +++ b/solr/core/src/java/org/apache/solr/cloud/Overseer.java @@ -36,7 +36,7 @@ import org.apache.lucene.util.Version; import org.apache.solr.client.solrj.SolrServerException; import org.apache.solr.client.solrj.cloud.SolrCloudManager; -import org.apache.solr.client.solrj.impl.CloudLegacySolrClient; +import org.apache.solr.client.solrj.impl.CloudHttp2SolrClient; import org.apache.solr.client.solrj.impl.CloudSolrClient; import org.apache.solr.client.solrj.request.CollectionAdminRequest; import org.apache.solr.client.solrj.response.CollectionAdminResponse; @@ -856,12 +856,13 @@ private void doCompatCheck(BiConsumer consumer) { } else { return; } + try (CloudSolrClient client = - new CloudLegacySolrClient.Builder( + new CloudHttp2SolrClient.Builder( Collections.singletonList(getZkController().getZkServerAddress()), Optional.empty()) - .withSocketTimeout(30000, TimeUnit.MILLISECONDS) - .withConnectionTimeout(15000, TimeUnit.MILLISECONDS) - .withHttpClient(updateShardHandler.getDefaultHttpClient()) + .withZkClientTimeout(30000, TimeUnit.MILLISECONDS) + .withZkConnectTimeout(15000, TimeUnit.MILLISECONDS) + .withHttpClient(getCoreContainer().getDefaultHttpSolrClient()) .build()) { CollectionAdminRequest.ColStatus req = CollectionAdminRequest.collectionStatus(CollectionAdminParams.SYSTEM_COLL) diff --git a/solr/core/src/java/org/apache/solr/cloud/api/collections/ReindexCollectionCmd.java b/solr/core/src/java/org/apache/solr/cloud/api/collections/ReindexCollectionCmd.java index 91299b3c259..6848cd73655 100644 --- a/solr/core/src/java/org/apache/solr/cloud/api/collections/ReindexCollectionCmd.java +++ b/solr/core/src/java/org/apache/solr/cloud/api/collections/ReindexCollectionCmd.java @@ -31,12 +31,10 @@ import java.util.function.Function; import java.util.stream.Collectors; import java.util.stream.Stream; -import org.apache.http.client.HttpClient; -import org.apache.solr.client.solrj.SolrClient; import org.apache.solr.client.solrj.SolrResponse; import org.apache.solr.client.solrj.cloud.DistribStateManager; import org.apache.solr.client.solrj.impl.CloudSolrClient; -import org.apache.solr.client.solrj.impl.HttpSolrClient; +import org.apache.solr.client.solrj.impl.Http2SolrClient; import org.apache.solr.client.solrj.request.CollectionAdminRequest; import org.apache.solr.client.solrj.request.QueryRequest; import org.apache.solr.client.solrj.response.QueryResponse; @@ -729,62 +727,51 @@ private void waitForDaemon( String targetCollection, Map reindexingState) throws Exception { - HttpClient client = ccc.getCoreContainer().getUpdateShardHandler().getDefaultHttpClient(); - try (SolrClient solrClient = - new HttpSolrClient.Builder() - .withHttpClient(client) - .withBaseSolrUrl(daemonReplica.getBaseUrl()) - .build()) { - ModifiableSolrParams q = new ModifiableSolrParams(); - q.set(CommonParams.QT, "/stream"); - q.set("action", "list"); - q.set(CommonParams.DISTRIB, false); - QueryRequest req = new QueryRequest(q); - boolean isRunning; - int statusCheck = 0; - do { - isRunning = false; - statusCheck++; - try { - NamedList rsp = solrClient.request(req, daemonReplica.getCoreName()); - Map rs = (Map) rsp.get("result-set"); - if (rs == null || rs.isEmpty()) { - throw new SolrException( - SolrException.ErrorCode.SERVER_ERROR, - "Can't find daemon list: missing result-set: " + Utils.toJSONString(rsp)); - } - List list = (List) rs.get("docs"); - if (list == null) { - throw new SolrException( - SolrException.ErrorCode.SERVER_ERROR, - "Can't find daemon list: missing result-set: " + Utils.toJSONString(rsp)); - } - if (list.isEmpty()) { // finished? - break; - } - for (Object o : list) { - Map map = (Map) o; - String id = (String) map.get("id"); - if (daemonName.equals(id)) { - isRunning = true; - // fail here - TestInjection.injectReindexFailure(); - break; - } - } - } catch (Exception e) { + + boolean isRunning; + int statusCheck = 0; + do { + isRunning = false; + statusCheck++; + try { + NamedList rsp = executeDaemonAction("list", daemonName, daemonReplica); + Map rs = (Map) rsp.get("result-set"); + if (rs == null || rs.isEmpty()) { throw new SolrException( SolrException.ErrorCode.SERVER_ERROR, - "Exception waiting for daemon " + daemonName + " at " + daemonReplica.getCoreUrl(), - e); + "Can't find daemon list: missing result-set: " + Utils.toJSONString(rsp)); } - if (statusCheck % 5 == 0) { - reindexingState.put("processedDocs", getNumberOfDocs(targetCollection)); - setReindexingState(sourceCollection, State.RUNNING, reindexingState); + List list = (List) rs.get("docs"); + if (list == null) { + throw new SolrException( + SolrException.ErrorCode.SERVER_ERROR, + "Can't find daemon list: missing result-set: " + Utils.toJSONString(rsp)); } - ccc.getSolrCloudManager().getTimeSource().sleep(2000); - } while (isRunning && !maybeAbort(sourceCollection)); - } + if (list.isEmpty()) { // finished? + break; + } + for (Object o : list) { + Map map = (Map) o; + String id = (String) map.get("id"); + if (daemonName.equals(id)) { + isRunning = true; + // fail here + TestInjection.injectReindexFailure(); + break; + } + } + } catch (Exception e) { + throw new SolrException( + SolrException.ErrorCode.SERVER_ERROR, + "Exception waiting for daemon " + daemonName + " at " + daemonReplica.getCoreUrl(), + e); + } + if (statusCheck % 5 == 0) { + reindexingState.put("processedDocs", getNumberOfDocs(targetCollection)); + setReindexingState(sourceCollection, State.RUNNING, reindexingState); + } + ccc.getSolrCloudManager().getTimeSource().sleep(2000); + } while (isRunning && !maybeAbort(sourceCollection)); } @SuppressWarnings({"unchecked"}) @@ -792,106 +779,101 @@ private void killDaemon(String daemonName, Replica daemonReplica) throws Excepti if (log.isDebugEnabled()) { log.debug("-- killing daemon {} at {}", daemonName, daemonReplica.getCoreUrl()); } - HttpClient client = ccc.getCoreContainer().getUpdateShardHandler().getDefaultHttpClient(); - try (SolrClient solrClient = - new HttpSolrClient.Builder() - .withHttpClient(client) - .withDefaultCollection(daemonReplica.getCoreName()) - .withBaseSolrUrl(daemonReplica.getBaseUrl()) - .build()) { - ModifiableSolrParams q = new ModifiableSolrParams(); - q.set(CommonParams.QT, "/stream"); - // we should really use 'kill' here, but then we will never - // know when the daemon actually finishes running - 'kill' only - // sets a flag that may be noticed much later - q.set("action", "stop"); - q.set(CommonParams.ID, daemonName); - q.set(CommonParams.DISTRIB, false); - QueryRequest req = new QueryRequest(q); - NamedList rsp = solrClient.request(req); - // /result-set/docs/[0]/DaemonOp : Deamon:id killed on coreName - if (log.isDebugEnabled()) { - log.debug(" -- stop daemon response: {}", Utils.toJSONString(rsp)); - } - Map rs = (Map) rsp.get("result-set"); - if (rs == null || rs.isEmpty()) { - log.warn( - "Problem killing daemon {}: missing result-set: {}", - daemonName, - Utils.toJSONString(rsp)); - return; - } - List list = (List) rs.get("docs"); - if (list == null) { - log.warn( - "Problem killing daemon {}: missing result-set: {}", - daemonName, - Utils.toJSONString(rsp)); - return; - } - if (list.isEmpty()) { // already finished? - return; + + // we should really use 'kill' here, but then we will never + // know when the daemon actually finishes running - 'kill' only + // sets a flag that may be noticed much later + NamedList rsp = executeDaemonAction("stop", daemonName, daemonReplica); + // /result-set/docs/[0]/DaemonOp : Deamon:id killed on coreName + if (log.isDebugEnabled()) { + log.debug(" -- stop daemon response: {}", Utils.toJSONString(rsp)); + } + Map rs = (Map) rsp.get("result-set"); + if (rs == null || rs.isEmpty()) { + log.warn( + "Problem killing daemon {}: missing result-set: {}", daemonName, Utils.toJSONString(rsp)); + return; + } + List list = (List) rs.get("docs"); + if (list == null) { + log.warn( + "Problem killing daemon {}: missing result-set: {}", daemonName, Utils.toJSONString(rsp)); + return; + } + if (list.isEmpty()) { // already finished? + return; + } + for (Object o : list) { + Map map = (Map) o; + String op = (String) map.get("DaemonOp"); + if (op == null) { + continue; } - for (Object o : list) { - Map map = (Map) o; - String op = (String) map.get("DaemonOp"); - if (op == null) { - continue; - } - if (op.contains(daemonName) && op.contains("stopped")) { - // now wait for the daemon to really stop - q.set("action", "list"); - req = new QueryRequest(q); - TimeOut timeOut = - new TimeOut(60, TimeUnit.SECONDS, ccc.getSolrCloudManager().getTimeSource()); - while (!timeOut.hasTimedOut()) { - rsp = solrClient.request(req); - rs = (Map) rsp.get("result-set"); - if (rs == null || rs.isEmpty()) { - log.warn( - "Problem killing daemon {}: missing result-set: {}", - daemonName, - Utils.toJSONString(rsp)); - break; - } - List list2 = (List) rs.get("docs"); - if (list2 == null) { - log.warn( - "Problem killing daemon {}: missing result-set: {}", - daemonName, - Utils.toJSONString(rsp)); - break; - } - if (list2.isEmpty()) { // already finished? - break; - } - Map status2 = null; - for (Object o2 : list2) { - Map map2 = (Map) o2; - if (daemonName.equals(map2.get("id"))) { - status2 = map2; - break; - } - } - if (status2 == null) { // finished? - break; - } - Number stopTime = (Number) status2.get("stopTime"); - if (stopTime.longValue() > 0) { + if (op.contains(daemonName) && op.contains("stopped")) { + // now wait for the daemon to really stop + TimeOut timeOut = + new TimeOut(60, TimeUnit.SECONDS, ccc.getSolrCloudManager().getTimeSource()); + while (!timeOut.hasTimedOut()) { + rsp = executeDaemonAction("list", daemonName, daemonReplica); + rs = (Map) rsp.get("result-set"); + if (rs == null || rs.isEmpty()) { + log.warn( + "Problem killing daemon {}: missing result-set: {}", + daemonName, + Utils.toJSONString(rsp)); + break; + } + List list2 = (List) rs.get("docs"); + if (list2 == null) { + log.warn( + "Problem killing daemon {}: missing result-set: {}", + daemonName, + Utils.toJSONString(rsp)); + break; + } + if (list2.isEmpty()) { // already finished? + break; + } + Map status2 = null; + for (Object o2 : list2) { + Map map2 = (Map) o2; + if (daemonName.equals(map2.get("id"))) { + status2 = map2; break; } } - if (timeOut.hasTimedOut()) { - log.warn( - "Problem killing daemon {}: timed out waiting for daemon to stop.", daemonName); - // proceed anyway + if (status2 == null) { // finished? + break; } + Number stopTime = (Number) status2.get("stopTime"); + if (stopTime.longValue() > 0) { + break; + } + } + if (timeOut.hasTimedOut()) { + log.warn("Problem killing daemon {}: timed out waiting for daemon to stop.", daemonName); + // proceed anyway } } - // now kill it - it's already stopped, this simply removes its status - q.set("action", "kill"); - req = new QueryRequest(q); - solrClient.request(req); + } + // now kill it - it's already stopped, this simply removes its status + executeDaemonAction("kill", daemonName, daemonReplica); + } + + private NamedList executeDaemonAction( + String action, String daemonName, Replica daemonReplica) throws Exception { + try (var solrClient = + new Http2SolrClient.Builder(daemonReplica.getBaseUrl()) + .withHttpClient(ccc.getCoreContainer().getDefaultHttpSolrClient()) + .build()) { + final var q = new ModifiableSolrParams(); + q.set(CommonParams.QT, "/stream"); + q.set("action", action); + q.set(CommonParams.ID, daemonName); + q.set(CommonParams.DISTRIB, false); + + final var req = new QueryRequest(q); + return solrClient.request(req, daemonReplica.getCoreName()); } } diff --git a/solr/core/src/java/org/apache/solr/filestore/DistribFileStore.java b/solr/core/src/java/org/apache/solr/filestore/DistribFileStore.java index 1a462dee26e..70f46089626 100644 --- a/solr/core/src/java/org/apache/solr/filestore/DistribFileStore.java +++ b/solr/core/src/java/org/apache/solr/filestore/DistribFileStore.java @@ -18,6 +18,8 @@ package org.apache.solr.filestore; import static java.nio.charset.StandardCharsets.UTF_8; +import static org.apache.solr.client.solrj.SolrRequest.METHOD.DELETE; +import static org.apache.solr.client.solrj.SolrRequest.METHOD.GET; import static org.apache.solr.common.SolrException.ErrorCode.BAD_REQUEST; import static org.apache.solr.common.SolrException.ErrorCode.SERVER_ERROR; @@ -45,15 +47,20 @@ import java.util.function.Predicate; import net.jcip.annotations.NotThreadSafe; import org.apache.commons.codec.digest.DigestUtils; -import org.apache.http.client.HttpClient; -import org.apache.http.client.methods.HttpDelete; import org.apache.lucene.util.IOUtils; +import org.apache.solr.client.solrj.SolrRequest; +import org.apache.solr.client.solrj.SolrServerException; +import org.apache.solr.client.solrj.impl.Http2SolrClient; +import org.apache.solr.client.solrj.impl.InputStreamResponseParser; +import org.apache.solr.client.solrj.request.GenericSolrRequest; import org.apache.solr.common.SolrException; import org.apache.solr.common.cloud.SolrZkClient; +import org.apache.solr.common.params.ModifiableSolrParams; import org.apache.solr.common.util.Utils; import org.apache.solr.core.CoreContainer; import org.apache.solr.core.SolrPaths; import org.apache.solr.filestore.FileStoreAPI.MetaData; +import org.apache.solr.handler.ReplicationHandler; import org.apache.zookeeper.CreateMode; import org.apache.zookeeper.KeeperException; import org.apache.zookeeper.server.ByteBufferInputStream; @@ -180,23 +187,47 @@ private boolean fetchFileFromNodeAndPersist(String fromNode) { ByteBuffer metadata = null; Map m = null; - try { + + InputStream is = null; + + try (var solrClient = new Http2SolrClient.Builder(baseUrl).withHttpClient(coreContainer.getDefaultHttpSolrClient()).build()) { + GenericSolrRequest request = + new GenericSolrRequest(GET, "/node/files" + getMetaPath()); + + request.setResponseParser( + new InputStreamResponseParser(null)); + var response = solrClient.request(request); + + is = (InputStream) response.get("stream"); + metadata = - Utils.executeGET( - coreContainer.getUpdateShardHandler().getDefaultHttpClient(), - baseUrl + "/node/files" + getMetaPath(), - Utils.newBytesConsumer((int) MAX_PKG_SIZE)); + Utils.newBytesConsumer((int) MAX_PKG_SIZE).accept((InputStream) response.get("stream")); + m = (Map) Utils.fromJSON(metadata.array(), metadata.arrayOffset(), metadata.limit()); - } catch (SolrException e) { + + } catch (SolrServerException | IOException e) { throw new SolrException(SolrException.ErrorCode.SERVER_ERROR, "Error fetching metadata", e); } + finally { + try { + IOUtils.close(is); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + try (var solrClient = new Http2SolrClient.Builder(baseUrl).withHttpClient(coreContainer.getDefaultHttpSolrClient()).build()){ + GenericSolrRequest solrRequest = + new GenericSolrRequest(GET, "/node/files" + path); + solrRequest.setResponseParser( + new InputStreamResponseParser(null)); + var response = solrClient.request(solrRequest); + + is = (InputStream) response.get("stream"); - try { ByteBuffer filedata = - Utils.executeGET( - coreContainer.getUpdateShardHandler().getDefaultHttpClient(), - baseUrl + "/node/files" + path, - Utils.newBytesConsumer((int) MAX_PKG_SIZE)); + Utils.newBytesConsumer((int) MAX_PKG_SIZE).accept((InputStream) response.get("stream")); + filedata.mark(); String sha512 = DigestUtils.sha512Hex(new ByteBufferInputStream(filedata)); String expected = (String) m.get("sha512"); @@ -207,10 +238,15 @@ private boolean fetchFileFromNodeAndPersist(String fromNode) { filedata.reset(); persistToFile(filedata, metadata); return true; - } catch (SolrException e) { + + } catch (SolrServerException | IOException e) { throw new SolrException(SolrException.ErrorCode.SERVER_ERROR, "Error fetching data", e); - } catch (IOException ioe) { - throw new SolrException(SERVER_ERROR, "Error persisting file", ioe); + } finally { + try { + IOUtils.close(is); + } catch (IOException e) { + throw new RuntimeException(e); + } } } @@ -221,15 +257,23 @@ boolean fetchFromAnyNode() { try { String baseUrl = coreContainer.getZkController().getZkStateReader().getBaseUrlV2ForNodeName(liveNode); - String reqUrl = baseUrl + "/node/files" + path + "?meta=true&wt=javabin&omitHeader=true"; + final var solrParams = new ModifiableSolrParams(); + solrParams.add("meta", "true"); + solrParams.add("omitHeader", "true"); + + final var request = + new GenericSolrRequest(GET, "/node/files" + path, solrParams); boolean nodeHasBlob = false; - Object nl = - Utils.executeGET( - coreContainer.getUpdateShardHandler().getDefaultHttpClient(), - reqUrl, - Utils.JAVABINCONSUMER); - if (Utils.getObjectByPath(nl, false, Arrays.asList("files", path)) != null) { - nodeHasBlob = true; + + try (var solrClient = + new Http2SolrClient.Builder(baseUrl) + .withHttpClient(coreContainer.getDefaultHttpSolrClient()) + .build()) { + var resp = solrClient.request(request); + + if (Utils.getObjectByPath(resp, false, Arrays.asList("files", path)) != null) { + nodeHasBlob = true; + } } if (nodeHasBlob) { @@ -348,12 +392,12 @@ private void distribute(FileInfo info) { for (String node : nodes) { String baseUrl = coreContainer.getZkController().getZkStateReader().getBaseUrlV2ForNodeName(node); - String url = baseUrl + "/node/files" + info.path + "?getFrom="; + String getFrom = ""; if (i < FETCHFROM_SRC) { // this is to protect very large clusters from overwhelming a single node // the first FETCHFROM_SRC nodes will be asked to fetch from this node. // it's there in the memory now. So , it must be served fast - url += myNodeName; + getFrom += myNodeName; } else { if (i == FETCHFROM_SRC) { // This is just an optimization @@ -367,11 +411,19 @@ private void distribute(FileInfo info) { // trying to avoid the thundering herd problem when there are a very large no:of nodes // others should try to fetch it from any node where it is available. By now, // almost FETCHFROM_SRC other nodes may have it - url += "*"; + getFrom += "*"; } - try { + try (var solrClient = + new Http2SolrClient.Builder(baseUrl) + .withHttpClient(coreContainer.getDefaultHttpSolrClient()) + .build()) { + var solrParams = new ModifiableSolrParams(); + solrParams.set("getFrom", getFrom); + + var solrRequest = + new GenericSolrRequest(GET, "/node/files" + info.path, solrParams); // fire and forget - Utils.executeGET(coreContainer.getUpdateShardHandler().getDefaultHttpClient(), url, null); + solrClient.request(solrRequest); } catch (Exception e) { log.info("Node: {} failed to respond for file fetch notification", node, e); // ignore the exception @@ -484,14 +536,22 @@ public List list(String path, Predicate predicate) { public void delete(String path) { deleteLocal(path); List nodes = FileStoreUtils.fetchAndShuffleRemoteLiveNodes(coreContainer); - HttpClient client = coreContainer.getUpdateShardHandler().getDefaultHttpClient(); + + final var solrParams = new ModifiableSolrParams(); + solrParams.add("localDelete", "true"); + final var solrRequest = + new GenericSolrRequest(DELETE, "/cluster/files" + path, solrParams); + for (String node : nodes) { String baseUrl = coreContainer.getZkController().getZkStateReader().getBaseUrlV2ForNodeName(node); - String url = baseUrl + "/cluster/files" + path + "?localDelete=true"; - HttpDelete del = new HttpDelete(url); - // invoke delete command on all nodes asynchronously - coreContainer.runAsync(() -> Utils.executeHttpMethod(client, url, null, del)); + try (var solrClient = + new Http2SolrClient.Builder(baseUrl) + .withHttpClient(coreContainer.getDefaultHttpSolrClient()) + .build()) { + // invoke delete command on all nodes asynchronously + solrClient.requestAsync(solrRequest); + } } } diff --git a/solr/core/src/java/org/apache/solr/pkg/PackageAPI.java b/solr/core/src/java/org/apache/solr/pkg/PackageAPI.java index 24339feefe8..cbfd6ee829d 100644 --- a/solr/core/src/java/org/apache/solr/pkg/PackageAPI.java +++ b/solr/core/src/java/org/apache/solr/pkg/PackageAPI.java @@ -35,11 +35,16 @@ import org.apache.solr.api.EndPoint; import org.apache.solr.api.PayloadObj; import org.apache.solr.client.solrj.SolrRequest; +import org.apache.solr.client.solrj.SolrServerException; +import org.apache.solr.client.solrj.impl.BinaryResponseParser; +import org.apache.solr.client.solrj.impl.Http2SolrClient; +import org.apache.solr.client.solrj.request.GenericSolrRequest; import org.apache.solr.client.solrj.request.beans.PackagePayload; import org.apache.solr.common.SolrException; import org.apache.solr.common.annotation.JsonProperty; import org.apache.solr.common.cloud.SolrZkClient; import org.apache.solr.common.cloud.ZooKeeperException; +import org.apache.solr.common.params.ModifiableSolrParams; import org.apache.solr.common.util.CommandOperation; import org.apache.solr.common.util.EnvUtils; import org.apache.solr.common.util.ReflectMapWriter; @@ -250,13 +255,29 @@ public void refresh(PayloadObj payload) { } // first refresh my own packageLoader.notifyListeners(p); + + final var solrParams = new ModifiableSolrParams(); + solrParams.add("omitHeader", "true"); + solrParams.add("refreshPackage", p); + + final var solrRequest = + new GenericSolrRequest(SolrRequest.METHOD.GET, "/cluster/package", solrParams); + solrRequest.setResponseParser(new BinaryResponseParser()); + for (String liveNode : FileStoreUtils.fetchAndShuffleRemoteLiveNodes(coreContainer)) { - Utils.executeGET( - coreContainer.getUpdateShardHandler().getDefaultHttpClient(), - coreContainer.getZkController().zkStateReader.getBaseUrlV2ForNodeName(liveNode) - + "/cluster/package?wt=javabin&omitHeader=true&refreshPackage=" - + p, - Utils.JAVABINCONSUMER); + final var baseUrl = + coreContainer.getZkController().zkStateReader.getBaseUrlV2ForNodeName(liveNode); + try (var solrClient = + new Http2SolrClient.Builder(baseUrl) + .withHttpClient(coreContainer.getDefaultHttpSolrClient()) + .build()) { + solrClient.request(solrRequest); + } catch (SolrServerException | IOException e) { + throw new SolrException( + SolrException.ErrorCode.SERVER_ERROR, + "Failed to refresh package on node: " + liveNode, + e); + } } } @@ -418,13 +439,28 @@ private void syncToVersion(int expectedVersion) { } void notifyAllNodesToSync(int expected) { + + final var solrParams = new ModifiableSolrParams(); + solrParams.add("omitHeader", "true"); + solrParams.add("expectedVersion", String.valueOf(expected)); + + final var solrRequest = + new GenericSolrRequest(SolrRequest.METHOD.GET, "/cluster/package", solrParams); + solrRequest.setResponseParser(new BinaryResponseParser()); + for (String liveNode : FileStoreUtils.fetchAndShuffleRemoteLiveNodes(coreContainer)) { - Utils.executeGET( - coreContainer.getUpdateShardHandler().getDefaultHttpClient(), - coreContainer.getZkController().zkStateReader.getBaseUrlV2ForNodeName(liveNode) - + "/cluster/package?wt=javabin&omitHeader=true&expectedVersion" - + expected, - Utils.JAVABINCONSUMER); + var baseUrl = coreContainer.getZkController().zkStateReader.getBaseUrlV2ForNodeName(liveNode); + try (var solrClient = + new Http2SolrClient.Builder(baseUrl) + .withHttpClient(coreContainer.getDefaultHttpSolrClient()) + .build()) { + solrClient.request(solrRequest); + } catch (SolrServerException | IOException e) { + throw new SolrException( + SolrException.ErrorCode.SERVER_ERROR, + "Failed to notify node: " + liveNode + " to sync expected package version: " + expected, + e); + } } } diff --git a/solr/core/src/java/org/apache/solr/security/PKIAuthenticationPlugin.java b/solr/core/src/java/org/apache/solr/security/PKIAuthenticationPlugin.java index b1f6e6b6eed..0e7dec13a07 100644 --- a/solr/core/src/java/org/apache/solr/security/PKIAuthenticationPlugin.java +++ b/solr/core/src/java/org/apache/solr/security/PKIAuthenticationPlugin.java @@ -17,6 +17,7 @@ package org.apache.solr.security; import static java.nio.charset.StandardCharsets.UTF_8; +import static org.apache.solr.client.solrj.SolrRequest.METHOD.GET; import com.google.common.annotations.VisibleForTesting; import java.io.IOException; @@ -41,16 +42,17 @@ import org.apache.http.HttpHeaders; import org.apache.http.HttpRequest; import org.apache.http.HttpRequestInterceptor; -import org.apache.http.HttpResponse; import org.apache.http.auth.BasicUserPrincipal; -import org.apache.http.client.methods.HttpGet; import org.apache.http.protocol.HttpContext; -import org.apache.http.util.EntityUtils; +import org.apache.solr.client.solrj.SolrRequest; import org.apache.solr.client.solrj.impl.Http2SolrClient; import org.apache.solr.client.solrj.impl.HttpClientUtil; import org.apache.solr.client.solrj.impl.HttpListenerFactory; import org.apache.solr.client.solrj.impl.SolrHttpClientBuilder; +import org.apache.solr.client.solrj.request.GenericSolrRequest; +import org.apache.solr.common.params.ModifiableSolrParams; import org.apache.solr.common.util.ExecutorUtil; +import org.apache.solr.common.util.NamedList; import org.apache.solr.common.util.StrUtils; import org.apache.solr.common.util.SuppressForbidden; import org.apache.solr.common.util.Utils; @@ -346,23 +348,30 @@ PublicKey fetchPublicKeyFromRemote(String nodename) { String url = cores.getZkController().getZkStateReader().getBaseUrlForNodeName(nodename); HttpEntity entity = null; try { - String uri = url + PublicKeyHandler.PATH + "?wt=json&omitHeader=true"; - log.debug("Fetching fresh public key from: {}", uri); - HttpResponse rsp = - cores - .getUpdateShardHandler() - .getDefaultHttpClient() - .execute(new HttpGet(uri), HttpClientUtil.createNewHttpClientRequestContext()); - entity = rsp.getEntity(); - byte[] bytes = EntityUtils.toByteArray(entity); - Map m = (Map) Utils.fromJSON(bytes); - String key = (String) m.get("key"); - if (key == null) { - log.error("No key available from {}{}", url, PublicKeyHandler.PATH); - return null; - } else { - log.info("New key obtained from node={}, key={}", nodename, key); + final var solrParams = new ModifiableSolrParams(); + solrParams.add("wt", "json"); + solrParams.add("omitHeader", "true"); + + final var request = + new GenericSolrRequest(GET, PublicKeyHandler.PATH, solrParams); + + log.debug("Fetching fresh public key from: {}", url); + + String key; + try (var solrClient = + new Http2SolrClient.Builder(url) + .withHttpClient(cores.getDefaultHttpSolrClient()) + .build()) { + NamedList resp = solrClient.request(request, null); + key = (String) resp.get("key"); + if (key == null) { + log.error("No key available from {}{}", url, PublicKeyHandler.PATH); + return null; + } else { + log.info("New key obtained from node={}, key={}", nodename, key); + } } + PublicKey pubKey = CryptoKeys.deserializeX509PublicKey(key); keyCache.put(nodename, pubKey); return pubKey; From 76e92841e2b546ace2ba61afb032b0f6e394658e Mon Sep 17 00:00:00 2001 From: Sanjay Dutt Date: Fri, 4 Oct 2024 19:17:49 +0530 Subject: [PATCH 18/26] tidy --- .../solr/filestore/DistribFileStore.java | 36 +++++++++---------- .../security/PKIAuthenticationPlugin.java | 4 +-- 2 files changed, 17 insertions(+), 23 deletions(-) diff --git a/solr/core/src/java/org/apache/solr/filestore/DistribFileStore.java b/solr/core/src/java/org/apache/solr/filestore/DistribFileStore.java index 70f46089626..c18928ff224 100644 --- a/solr/core/src/java/org/apache/solr/filestore/DistribFileStore.java +++ b/solr/core/src/java/org/apache/solr/filestore/DistribFileStore.java @@ -48,7 +48,6 @@ import net.jcip.annotations.NotThreadSafe; import org.apache.commons.codec.digest.DigestUtils; import org.apache.lucene.util.IOUtils; -import org.apache.solr.client.solrj.SolrRequest; import org.apache.solr.client.solrj.SolrServerException; import org.apache.solr.client.solrj.impl.Http2SolrClient; import org.apache.solr.client.solrj.impl.InputStreamResponseParser; @@ -60,7 +59,6 @@ import org.apache.solr.core.CoreContainer; import org.apache.solr.core.SolrPaths; import org.apache.solr.filestore.FileStoreAPI.MetaData; -import org.apache.solr.handler.ReplicationHandler; import org.apache.zookeeper.CreateMode; import org.apache.zookeeper.KeeperException; import org.apache.zookeeper.server.ByteBufferInputStream; @@ -190,12 +188,13 @@ private boolean fetchFileFromNodeAndPersist(String fromNode) { InputStream is = null; - try (var solrClient = new Http2SolrClient.Builder(baseUrl).withHttpClient(coreContainer.getDefaultHttpSolrClient()).build()) { - GenericSolrRequest request = - new GenericSolrRequest(GET, "/node/files" + getMetaPath()); + try (var solrClient = + new Http2SolrClient.Builder(baseUrl) + .withHttpClient(coreContainer.getDefaultHttpSolrClient()) + .build()) { + GenericSolrRequest request = new GenericSolrRequest(GET, "/node/files" + getMetaPath()); - request.setResponseParser( - new InputStreamResponseParser(null)); + request.setResponseParser(new InputStreamResponseParser(null)); var response = solrClient.request(request); is = (InputStream) response.get("stream"); @@ -207,8 +206,7 @@ private boolean fetchFileFromNodeAndPersist(String fromNode) { } catch (SolrServerException | IOException e) { throw new SolrException(SolrException.ErrorCode.SERVER_ERROR, "Error fetching metadata", e); - } - finally { + } finally { try { IOUtils.close(is); } catch (IOException e) { @@ -216,11 +214,12 @@ private boolean fetchFileFromNodeAndPersist(String fromNode) { } } - try (var solrClient = new Http2SolrClient.Builder(baseUrl).withHttpClient(coreContainer.getDefaultHttpSolrClient()).build()){ - GenericSolrRequest solrRequest = - new GenericSolrRequest(GET, "/node/files" + path); - solrRequest.setResponseParser( - new InputStreamResponseParser(null)); + try (var solrClient = + new Http2SolrClient.Builder(baseUrl) + .withHttpClient(coreContainer.getDefaultHttpSolrClient()) + .build()) { + GenericSolrRequest solrRequest = new GenericSolrRequest(GET, "/node/files" + path); + solrRequest.setResponseParser(new InputStreamResponseParser(null)); var response = solrClient.request(solrRequest); is = (InputStream) response.get("stream"); @@ -261,8 +260,7 @@ boolean fetchFromAnyNode() { solrParams.add("meta", "true"); solrParams.add("omitHeader", "true"); - final var request = - new GenericSolrRequest(GET, "/node/files" + path, solrParams); + final var request = new GenericSolrRequest(GET, "/node/files" + path, solrParams); boolean nodeHasBlob = false; try (var solrClient = @@ -420,8 +418,7 @@ private void distribute(FileInfo info) { var solrParams = new ModifiableSolrParams(); solrParams.set("getFrom", getFrom); - var solrRequest = - new GenericSolrRequest(GET, "/node/files" + info.path, solrParams); + var solrRequest = new GenericSolrRequest(GET, "/node/files" + info.path, solrParams); // fire and forget solrClient.request(solrRequest); } catch (Exception e) { @@ -539,8 +536,7 @@ public void delete(String path) { final var solrParams = new ModifiableSolrParams(); solrParams.add("localDelete", "true"); - final var solrRequest = - new GenericSolrRequest(DELETE, "/cluster/files" + path, solrParams); + final var solrRequest = new GenericSolrRequest(DELETE, "/cluster/files" + path, solrParams); for (String node : nodes) { String baseUrl = diff --git a/solr/core/src/java/org/apache/solr/security/PKIAuthenticationPlugin.java b/solr/core/src/java/org/apache/solr/security/PKIAuthenticationPlugin.java index 0e7dec13a07..89f571b2015 100644 --- a/solr/core/src/java/org/apache/solr/security/PKIAuthenticationPlugin.java +++ b/solr/core/src/java/org/apache/solr/security/PKIAuthenticationPlugin.java @@ -44,7 +44,6 @@ import org.apache.http.HttpRequestInterceptor; import org.apache.http.auth.BasicUserPrincipal; import org.apache.http.protocol.HttpContext; -import org.apache.solr.client.solrj.SolrRequest; import org.apache.solr.client.solrj.impl.Http2SolrClient; import org.apache.solr.client.solrj.impl.HttpClientUtil; import org.apache.solr.client.solrj.impl.HttpListenerFactory; @@ -352,8 +351,7 @@ PublicKey fetchPublicKeyFromRemote(String nodename) { solrParams.add("wt", "json"); solrParams.add("omitHeader", "true"); - final var request = - new GenericSolrRequest(GET, PublicKeyHandler.PATH, solrParams); + final var request = new GenericSolrRequest(GET, PublicKeyHandler.PATH, solrParams); log.debug("Fetching fresh public key from: {}", url); From 7c160a50519c0fdebb1cb5ef982a96d532962f54 Mon Sep 17 00:00:00 2001 From: Sanjay Dutt Date: Sat, 5 Oct 2024 18:04:49 +0530 Subject: [PATCH 19/26] Start using requestWithBaseUrl --- .../api/collections/ReindexCollectionCmd.java | 26 +++++++++--------- .../solr/filestore/DistribFileStore.java | 27 +++++-------------- .../java/org/apache/solr/pkg/PackageAPI.java | 8 +++--- .../security/PKIAuthenticationPlugin.java | 23 +++++++--------- 4 files changed, 31 insertions(+), 53 deletions(-) diff --git a/solr/core/src/java/org/apache/solr/cloud/api/collections/ReindexCollectionCmd.java b/solr/core/src/java/org/apache/solr/cloud/api/collections/ReindexCollectionCmd.java index 6848cd73655..9166e32b03a 100644 --- a/solr/core/src/java/org/apache/solr/cloud/api/collections/ReindexCollectionCmd.java +++ b/solr/core/src/java/org/apache/solr/cloud/api/collections/ReindexCollectionCmd.java @@ -34,7 +34,6 @@ import org.apache.solr.client.solrj.SolrResponse; import org.apache.solr.client.solrj.cloud.DistribStateManager; import org.apache.solr.client.solrj.impl.CloudSolrClient; -import org.apache.solr.client.solrj.impl.Http2SolrClient; import org.apache.solr.client.solrj.request.CollectionAdminRequest; import org.apache.solr.client.solrj.request.QueryRequest; import org.apache.solr.client.solrj.response.QueryResponse; @@ -862,19 +861,18 @@ private void killDaemon(String daemonName, Replica daemonReplica) throws Excepti private NamedList executeDaemonAction( String action, String daemonName, Replica daemonReplica) throws Exception { - try (var solrClient = - new Http2SolrClient.Builder(daemonReplica.getBaseUrl()) - .withHttpClient(ccc.getCoreContainer().getDefaultHttpSolrClient()) - .build()) { - final var q = new ModifiableSolrParams(); - q.set(CommonParams.QT, "/stream"); - q.set("action", action); - q.set(CommonParams.ID, daemonName); - q.set(CommonParams.DISTRIB, false); - - final var req = new QueryRequest(q); - return solrClient.request(req, daemonReplica.getCoreName()); - } + final var solrClient = ccc.getCoreContainer().getDefaultHttpSolrClient(); + + final var solrParams = new ModifiableSolrParams(); + solrParams.set(CommonParams.QT, "/stream"); + solrParams.set("action", action); + solrParams.set(CommonParams.ID, daemonName); + solrParams.set(CommonParams.DISTRIB, false); + + final var req = new QueryRequest(solrParams); + final var solrResponse = + solrClient.requestWithBaseUrl(daemonReplica.getBaseUrl(), daemonReplica.getCoreName(), req); + return solrResponse.getResponse(); } private void cleanup( diff --git a/solr/core/src/java/org/apache/solr/filestore/DistribFileStore.java b/solr/core/src/java/org/apache/solr/filestore/DistribFileStore.java index c18928ff224..9aa86ecbac7 100644 --- a/solr/core/src/java/org/apache/solr/filestore/DistribFileStore.java +++ b/solr/core/src/java/org/apache/solr/filestore/DistribFileStore.java @@ -187,23 +187,16 @@ private boolean fetchFileFromNodeAndPersist(String fromNode) { Map m = null; InputStream is = null; + var solrClient = coreContainer.getDefaultHttpSolrClient(); - try (var solrClient = - new Http2SolrClient.Builder(baseUrl) - .withHttpClient(coreContainer.getDefaultHttpSolrClient()) - .build()) { + try { GenericSolrRequest request = new GenericSolrRequest(GET, "/node/files" + getMetaPath()); - request.setResponseParser(new InputStreamResponseParser(null)); - var response = solrClient.request(request); - + var response = solrClient.requestWithBaseUrl(baseUrl, client -> client.request(request)); is = (InputStream) response.get("stream"); - metadata = Utils.newBytesConsumer((int) MAX_PKG_SIZE).accept((InputStream) response.get("stream")); - m = (Map) Utils.fromJSON(metadata.array(), metadata.arrayOffset(), metadata.limit()); - } catch (SolrServerException | IOException e) { throw new SolrException(SolrException.ErrorCode.SERVER_ERROR, "Error fetching metadata", e); } finally { @@ -214,19 +207,13 @@ private boolean fetchFileFromNodeAndPersist(String fromNode) { } } - try (var solrClient = - new Http2SolrClient.Builder(baseUrl) - .withHttpClient(coreContainer.getDefaultHttpSolrClient()) - .build()) { - GenericSolrRequest solrRequest = new GenericSolrRequest(GET, "/node/files" + path); - solrRequest.setResponseParser(new InputStreamResponseParser(null)); - var response = solrClient.request(solrRequest); - + try { + GenericSolrRequest request = new GenericSolrRequest(GET, "/node/files" + path); + request.setResponseParser(new InputStreamResponseParser(null)); + var response = solrClient.requestWithBaseUrl(baseUrl, client -> client.request(request)); is = (InputStream) response.get("stream"); - ByteBuffer filedata = Utils.newBytesConsumer((int) MAX_PKG_SIZE).accept((InputStream) response.get("stream")); - filedata.mark(); String sha512 = DigestUtils.sha512Hex(new ByteBufferInputStream(filedata)); String expected = (String) m.get("sha512"); diff --git a/solr/core/src/java/org/apache/solr/pkg/PackageAPI.java b/solr/core/src/java/org/apache/solr/pkg/PackageAPI.java index cbfd6ee829d..6792c418fdb 100644 --- a/solr/core/src/java/org/apache/solr/pkg/PackageAPI.java +++ b/solr/core/src/java/org/apache/solr/pkg/PackageAPI.java @@ -450,11 +450,9 @@ void notifyAllNodesToSync(int expected) { for (String liveNode : FileStoreUtils.fetchAndShuffleRemoteLiveNodes(coreContainer)) { var baseUrl = coreContainer.getZkController().zkStateReader.getBaseUrlV2ForNodeName(liveNode); - try (var solrClient = - new Http2SolrClient.Builder(baseUrl) - .withHttpClient(coreContainer.getDefaultHttpSolrClient()) - .build()) { - solrClient.request(solrRequest); + try { + var solrClient = coreContainer.getDefaultHttpSolrClient(); + solrClient.requestWithBaseUrl(baseUrl, client -> client.request(solrRequest)); } catch (SolrServerException | IOException e) { throw new SolrException( SolrException.ErrorCode.SERVER_ERROR, diff --git a/solr/core/src/java/org/apache/solr/security/PKIAuthenticationPlugin.java b/solr/core/src/java/org/apache/solr/security/PKIAuthenticationPlugin.java index 89f571b2015..7519e351cd3 100644 --- a/solr/core/src/java/org/apache/solr/security/PKIAuthenticationPlugin.java +++ b/solr/core/src/java/org/apache/solr/security/PKIAuthenticationPlugin.java @@ -352,22 +352,17 @@ PublicKey fetchPublicKeyFromRemote(String nodename) { solrParams.add("omitHeader", "true"); final var request = new GenericSolrRequest(GET, PublicKeyHandler.PATH, solrParams); - log.debug("Fetching fresh public key from: {}", url); + var solrClient = cores.getDefaultHttpSolrClient(); + NamedList resp = + solrClient.requestWithBaseUrl(url, client -> client.request(request)); - String key; - try (var solrClient = - new Http2SolrClient.Builder(url) - .withHttpClient(cores.getDefaultHttpSolrClient()) - .build()) { - NamedList resp = solrClient.request(request, null); - key = (String) resp.get("key"); - if (key == null) { - log.error("No key available from {}{}", url, PublicKeyHandler.PATH); - return null; - } else { - log.info("New key obtained from node={}, key={}", nodename, key); - } + String key = (String) resp.get("key"); + if (key == null) { + log.error("No key available from {}{}", url, PublicKeyHandler.PATH); + return null; + } else { + log.info("New key obtained from node={}, key={}", nodename, key); } PublicKey pubKey = CryptoKeys.deserializeX509PublicKey(key); From 786cb6d6219ee75bd18225186f3ad3ec15f6f44c Mon Sep 17 00:00:00 2001 From: Sanjay Dutt Date: Mon, 7 Oct 2024 09:51:57 +0530 Subject: [PATCH 20/26] makes some changes to test --- .../InstrumentedHttpListenerFactory.java | 3 +-- .../solr/core/TestHttpSolrClientProvider.java | 20 +++++++------------ 2 files changed, 8 insertions(+), 15 deletions(-) diff --git a/solr/core/src/java/org/apache/solr/util/stats/InstrumentedHttpListenerFactory.java b/solr/core/src/java/org/apache/solr/util/stats/InstrumentedHttpListenerFactory.java index ae27a52840c..d91d1f83b68 100644 --- a/solr/core/src/java/org/apache/solr/util/stats/InstrumentedHttpListenerFactory.java +++ b/solr/core/src/java/org/apache/solr/util/stats/InstrumentedHttpListenerFactory.java @@ -136,8 +136,7 @@ public SolrMetricsContext getSolrMetricsContext() { } public static NameStrategy getNameStrategy(String name) { - InstrumentedHttpListenerFactory.NameStrategy nameStrategy = - KNOWN_METRIC_NAME_STRATEGIES.get(name); + var nameStrategy = KNOWN_METRIC_NAME_STRATEGIES.get(name); if (nameStrategy == null) { throw new SolrException( SolrException.ErrorCode.SERVER_ERROR, diff --git a/solr/core/src/test/org/apache/solr/core/TestHttpSolrClientProvider.java b/solr/core/src/test/org/apache/solr/core/TestHttpSolrClientProvider.java index 28fe819df30..4d60714a8ad 100644 --- a/solr/core/src/test/org/apache/solr/core/TestHttpSolrClientProvider.java +++ b/solr/core/src/test/org/apache/solr/core/TestHttpSolrClientProvider.java @@ -31,7 +31,6 @@ public class TestHttpSolrClientProvider extends SolrTestCase { - HttpSolrClientProvider httpSolrClientProvider; SolrMetricsContext parentSolrMetricCtx; @Override @@ -44,13 +43,10 @@ public void setUp() throws Exception { @Test public void test_when_updateShardHandler_cfg_is_null() { - try { - httpSolrClientProvider = new HttpSolrClientProvider(null, parentSolrMetricCtx); + try (var httpSolrClientProvider = new HttpSolrClientProvider(null, parentSolrMetricCtx); ) { assertEquals( httpSolrClientProvider.getSolrClient().getIdleTimeout(), HttpClientUtil.DEFAULT_SO_TIMEOUT); - } finally { - httpSolrClientProvider.close(); } } @@ -58,11 +54,10 @@ public void test_when_updateShardHandler_cfg_is_null() { public void test_when_updateShardHandler_cfg_is_not_null() { var idleTimeout = 10000; UpdateShardHandlerConfig cfg = new UpdateShardHandlerConfig(-1, -1, idleTimeout, -1, null, -1); - try { - httpSolrClientProvider = new HttpSolrClientProvider(cfg, parentSolrMetricCtx); - assertEquals(httpSolrClientProvider.getSolrClient().getIdleTimeout(), idleTimeout); - } finally { - httpSolrClientProvider.close(); + try (var httpSolrClientProvider = new HttpSolrClientProvider(cfg, parentSolrMetricCtx); ) { + assertNotEquals( + httpSolrClientProvider.getSolrClient().getIdleTimeout(), + UpdateShardHandlerConfig.DEFAULT.getDistributedSocketTimeout()); } } @@ -71,10 +66,9 @@ public void test_closing_solr_metric_context() { SolrMetricsContext childSolrMetricContext = Mockito.mock(SolrMetricsContext.class); Mockito.when(parentSolrMetricCtx.getChildContext(any(HttpSolrClientProvider.class))) .thenReturn(childSolrMetricContext); - try { - httpSolrClientProvider = new HttpSolrClientProvider(null, parentSolrMetricCtx); + try (var httpSolrClientProvider = new HttpSolrClientProvider(null, parentSolrMetricCtx)) { + // Just to make sure we are closing solr metrics object } finally { - httpSolrClientProvider.close(); verify(childSolrMetricContext, times(1)).unregister(); } } From 9331bbf8382dba5ef9eaaee0208c8b4e276cdf85 Mon Sep 17 00:00:00 2001 From: Sanjay Dutt Date: Mon, 7 Oct 2024 10:49:42 +0530 Subject: [PATCH 21/26] Add another assertion to make sure idleTimeout not set to defaultIdleTimeout --- .../org/apache/solr/core/TestHttpSolrClientProvider.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/solr/core/src/test/org/apache/solr/core/TestHttpSolrClientProvider.java b/solr/core/src/test/org/apache/solr/core/TestHttpSolrClientProvider.java index 4d60714a8ad..4a0b189bb54 100644 --- a/solr/core/src/test/org/apache/solr/core/TestHttpSolrClientProvider.java +++ b/solr/core/src/test/org/apache/solr/core/TestHttpSolrClientProvider.java @@ -53,11 +53,10 @@ public void test_when_updateShardHandler_cfg_is_null() { @Test public void test_when_updateShardHandler_cfg_is_not_null() { var idleTimeout = 10000; + assertNotEquals(idleTimeout, UpdateShardHandlerConfig.DEFAULT.getDistributedSocketTimeout()); UpdateShardHandlerConfig cfg = new UpdateShardHandlerConfig(-1, -1, idleTimeout, -1, null, -1); try (var httpSolrClientProvider = new HttpSolrClientProvider(cfg, parentSolrMetricCtx); ) { - assertNotEquals( - httpSolrClientProvider.getSolrClient().getIdleTimeout(), - UpdateShardHandlerConfig.DEFAULT.getDistributedSocketTimeout()); + assertEquals(httpSolrClientProvider.getSolrClient().getIdleTimeout(), idleTimeout); } } From 6a6f536bc70815556aca51e444b78a0c48406d2c Mon Sep 17 00:00:00 2001 From: Sanjay Dutt Date: Mon, 7 Oct 2024 11:06:12 +0530 Subject: [PATCH 22/26] gradlew check fix --- .../test/org/apache/solr/core/TestHttpSolrClientProvider.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/solr/core/src/test/org/apache/solr/core/TestHttpSolrClientProvider.java b/solr/core/src/test/org/apache/solr/core/TestHttpSolrClientProvider.java index 4a0b189bb54..14b5a504634 100644 --- a/solr/core/src/test/org/apache/solr/core/TestHttpSolrClientProvider.java +++ b/solr/core/src/test/org/apache/solr/core/TestHttpSolrClientProvider.java @@ -66,7 +66,7 @@ public void test_closing_solr_metric_context() { Mockito.when(parentSolrMetricCtx.getChildContext(any(HttpSolrClientProvider.class))) .thenReturn(childSolrMetricContext); try (var httpSolrClientProvider = new HttpSolrClientProvider(null, parentSolrMetricCtx)) { - // Just to make sure we are closing solr metrics object + assertNotNull(httpSolrClientProvider.getSolrClient()); } finally { verify(childSolrMetricContext, times(1)).unregister(); } From acecf82b21450a722975ff8ae68aab64e8f09f4c Mon Sep 17 00:00:00 2001 From: Sanjay Dutt Date: Mon, 7 Oct 2024 12:00:58 +0530 Subject: [PATCH 23/26] replaced with method reference --- .../java/org/apache/solr/cloud/Overseer.java | 21 ++++++++------ .../solr/filestore/DistribFileStore.java | 28 +++++++------------ .../java/org/apache/solr/pkg/PackageAPI.java | 19 ++++++------- .../security/PKIAuthenticationPlugin.java | 3 +- 4 files changed, 32 insertions(+), 39 deletions(-) diff --git a/solr/core/src/java/org/apache/solr/cloud/Overseer.java b/solr/core/src/java/org/apache/solr/cloud/Overseer.java index a53b54bdfa9..ab666a70bf4 100644 --- a/solr/core/src/java/org/apache/solr/cloud/Overseer.java +++ b/solr/core/src/java/org/apache/solr/cloud/Overseer.java @@ -37,7 +37,7 @@ import org.apache.solr.client.solrj.SolrServerException; import org.apache.solr.client.solrj.cloud.SolrCloudManager; import org.apache.solr.client.solrj.impl.CloudHttp2SolrClient; -import org.apache.solr.client.solrj.impl.CloudSolrClient; +import org.apache.solr.client.solrj.impl.Http2SolrClient; import org.apache.solr.client.solrj.request.CollectionAdminRequest; import org.apache.solr.client.solrj.response.CollectionAdminResponse; import org.apache.solr.cloud.api.collections.CreateCollectionCmd; @@ -857,13 +857,18 @@ private void doCompatCheck(BiConsumer consumer) { return; } - try (CloudSolrClient client = - new CloudHttp2SolrClient.Builder( - Collections.singletonList(getZkController().getZkServerAddress()), Optional.empty()) - .withZkClientTimeout(30000, TimeUnit.MILLISECONDS) - .withZkConnectTimeout(15000, TimeUnit.MILLISECONDS) - .withHttpClient(getCoreContainer().getDefaultHttpSolrClient()) - .build()) { + try (var solrClient = + new Http2SolrClient.Builder() + .withHttpClient(getCoreContainer().getDefaultHttpSolrClient()) + .withIdleTimeout(30000, TimeUnit.MILLISECONDS) + .withConnectionTimeout(15000, TimeUnit.MILLISECONDS) + .build(); + var client = + new CloudHttp2SolrClient.Builder( + Collections.singletonList(getZkController().getZkServerAddress()), + Optional.empty()) + .withHttpClient(solrClient) + .build()) { CollectionAdminRequest.ColStatus req = CollectionAdminRequest.collectionStatus(CollectionAdminParams.SYSTEM_COLL) .setWithSegments(true) diff --git a/solr/core/src/java/org/apache/solr/filestore/DistribFileStore.java b/solr/core/src/java/org/apache/solr/filestore/DistribFileStore.java index 9aa86ecbac7..c14afb8a352 100644 --- a/solr/core/src/java/org/apache/solr/filestore/DistribFileStore.java +++ b/solr/core/src/java/org/apache/solr/filestore/DistribFileStore.java @@ -192,7 +192,7 @@ private boolean fetchFileFromNodeAndPersist(String fromNode) { try { GenericSolrRequest request = new GenericSolrRequest(GET, "/node/files" + getMetaPath()); request.setResponseParser(new InputStreamResponseParser(null)); - var response = solrClient.requestWithBaseUrl(baseUrl, client -> client.request(request)); + var response = solrClient.requestWithBaseUrl(baseUrl, request::process).getResponse(); is = (InputStream) response.get("stream"); metadata = Utils.newBytesConsumer((int) MAX_PKG_SIZE).accept((InputStream) response.get("stream")); @@ -210,7 +210,7 @@ private boolean fetchFileFromNodeAndPersist(String fromNode) { try { GenericSolrRequest request = new GenericSolrRequest(GET, "/node/files" + path); request.setResponseParser(new InputStreamResponseParser(null)); - var response = solrClient.requestWithBaseUrl(baseUrl, client -> client.request(request)); + var response = solrClient.requestWithBaseUrl(baseUrl, request::process).getResponse(); is = (InputStream) response.get("stream"); ByteBuffer filedata = Utils.newBytesConsumer((int) MAX_PKG_SIZE).accept((InputStream) response.get("stream")); @@ -249,18 +249,12 @@ boolean fetchFromAnyNode() { final var request = new GenericSolrRequest(GET, "/node/files" + path, solrParams); boolean nodeHasBlob = false; + var solrClient = coreContainer.getDefaultHttpSolrClient(); + var resp = solrClient.requestWithBaseUrl(baseUrl, request::process).getResponse(); - try (var solrClient = - new Http2SolrClient.Builder(baseUrl) - .withHttpClient(coreContainer.getDefaultHttpSolrClient()) - .build()) { - var resp = solrClient.request(request); - - if (Utils.getObjectByPath(resp, false, Arrays.asList("files", path)) != null) { - nodeHasBlob = true; - } + if (Utils.getObjectByPath(resp, false, Arrays.asList("files", path)) != null) { + nodeHasBlob = true; } - if (nodeHasBlob) { boolean success = fetchFileFromNodeAndPersist(liveNode); if (success) return true; @@ -398,16 +392,14 @@ private void distribute(FileInfo info) { // almost FETCHFROM_SRC other nodes may have it getFrom += "*"; } - try (var solrClient = - new Http2SolrClient.Builder(baseUrl) - .withHttpClient(coreContainer.getDefaultHttpSolrClient()) - .build()) { + try { + var solrClient = coreContainer.getDefaultHttpSolrClient(); var solrParams = new ModifiableSolrParams(); solrParams.set("getFrom", getFrom); - var solrRequest = new GenericSolrRequest(GET, "/node/files" + info.path, solrParams); + var request = new GenericSolrRequest(GET, "/node/files" + info.path, solrParams); // fire and forget - solrClient.request(solrRequest); + solrClient.requestWithBaseUrl(baseUrl, request::process); } catch (Exception e) { log.info("Node: {} failed to respond for file fetch notification", node, e); // ignore the exception diff --git a/solr/core/src/java/org/apache/solr/pkg/PackageAPI.java b/solr/core/src/java/org/apache/solr/pkg/PackageAPI.java index 6792c418fdb..8053502cddf 100644 --- a/solr/core/src/java/org/apache/solr/pkg/PackageAPI.java +++ b/solr/core/src/java/org/apache/solr/pkg/PackageAPI.java @@ -37,7 +37,6 @@ import org.apache.solr.client.solrj.SolrRequest; import org.apache.solr.client.solrj.SolrServerException; import org.apache.solr.client.solrj.impl.BinaryResponseParser; -import org.apache.solr.client.solrj.impl.Http2SolrClient; import org.apache.solr.client.solrj.request.GenericSolrRequest; import org.apache.solr.client.solrj.request.beans.PackagePayload; import org.apache.solr.common.SolrException; @@ -260,18 +259,16 @@ public void refresh(PayloadObj payload) { solrParams.add("omitHeader", "true"); solrParams.add("refreshPackage", p); - final var solrRequest = + final var request = new GenericSolrRequest(SolrRequest.METHOD.GET, "/cluster/package", solrParams); - solrRequest.setResponseParser(new BinaryResponseParser()); + request.setResponseParser(new BinaryResponseParser()); for (String liveNode : FileStoreUtils.fetchAndShuffleRemoteLiveNodes(coreContainer)) { final var baseUrl = coreContainer.getZkController().zkStateReader.getBaseUrlV2ForNodeName(liveNode); - try (var solrClient = - new Http2SolrClient.Builder(baseUrl) - .withHttpClient(coreContainer.getDefaultHttpSolrClient()) - .build()) { - solrClient.request(solrRequest); + try { + var solrClient = coreContainer.getDefaultHttpSolrClient(); + solrClient.requestWithBaseUrl(baseUrl, request::process); } catch (SolrServerException | IOException e) { throw new SolrException( SolrException.ErrorCode.SERVER_ERROR, @@ -444,15 +441,15 @@ void notifyAllNodesToSync(int expected) { solrParams.add("omitHeader", "true"); solrParams.add("expectedVersion", String.valueOf(expected)); - final var solrRequest = + final var request = new GenericSolrRequest(SolrRequest.METHOD.GET, "/cluster/package", solrParams); - solrRequest.setResponseParser(new BinaryResponseParser()); + request.setResponseParser(new BinaryResponseParser()); for (String liveNode : FileStoreUtils.fetchAndShuffleRemoteLiveNodes(coreContainer)) { var baseUrl = coreContainer.getZkController().zkStateReader.getBaseUrlV2ForNodeName(liveNode); try { var solrClient = coreContainer.getDefaultHttpSolrClient(); - solrClient.requestWithBaseUrl(baseUrl, client -> client.request(solrRequest)); + solrClient.requestWithBaseUrl(baseUrl, request::process); } catch (SolrServerException | IOException e) { throw new SolrException( SolrException.ErrorCode.SERVER_ERROR, diff --git a/solr/core/src/java/org/apache/solr/security/PKIAuthenticationPlugin.java b/solr/core/src/java/org/apache/solr/security/PKIAuthenticationPlugin.java index 7519e351cd3..e23c90e9b23 100644 --- a/solr/core/src/java/org/apache/solr/security/PKIAuthenticationPlugin.java +++ b/solr/core/src/java/org/apache/solr/security/PKIAuthenticationPlugin.java @@ -354,8 +354,7 @@ PublicKey fetchPublicKeyFromRemote(String nodename) { final var request = new GenericSolrRequest(GET, PublicKeyHandler.PATH, solrParams); log.debug("Fetching fresh public key from: {}", url); var solrClient = cores.getDefaultHttpSolrClient(); - NamedList resp = - solrClient.requestWithBaseUrl(url, client -> client.request(request)); + NamedList resp = solrClient.requestWithBaseUrl(url, request::process).getResponse(); String key = (String) resp.get("key"); if (key == null) { From 3b432e6be0451923663b8a28b2b61375927197df Mon Sep 17 00:00:00 2001 From: Sanjay Dutt Date: Thu, 17 Oct 2024 13:24:41 +0530 Subject: [PATCH 24/26] removed creation of http2SolrClient instead uses requestWithBaseUrl --- .../solr/filestore/DistribFileStore.java | 20 ++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/solr/core/src/java/org/apache/solr/filestore/DistribFileStore.java b/solr/core/src/java/org/apache/solr/filestore/DistribFileStore.java index c14afb8a352..58554f73968 100644 --- a/solr/core/src/java/org/apache/solr/filestore/DistribFileStore.java +++ b/solr/core/src/java/org/apache/solr/filestore/DistribFileStore.java @@ -49,7 +49,6 @@ import org.apache.commons.codec.digest.DigestUtils; import org.apache.lucene.util.IOUtils; import org.apache.solr.client.solrj.SolrServerException; -import org.apache.solr.client.solrj.impl.Http2SolrClient; import org.apache.solr.client.solrj.impl.InputStreamResponseParser; import org.apache.solr.client.solrj.request.GenericSolrRequest; import org.apache.solr.common.SolrException; @@ -367,16 +366,16 @@ private void distribute(FileInfo info) { int i = 0; int FETCHFROM_SRC = 50; String myNodeName = coreContainer.getZkController().getNodeName(); + String getFrom = ""; try { for (String node : nodes) { String baseUrl = coreContainer.getZkController().getZkStateReader().getBaseUrlV2ForNodeName(node); - String getFrom = ""; if (i < FETCHFROM_SRC) { // this is to protect very large clusters from overwhelming a single node // the first FETCHFROM_SRC nodes will be asked to fetch from this node. // it's there in the memory now. So , it must be served fast - getFrom += myNodeName; + getFrom = myNodeName; } else { if (i == FETCHFROM_SRC) { // This is just an optimization @@ -390,7 +389,7 @@ private void distribute(FileInfo info) { // trying to avoid the thundering herd problem when there are a very large no:of nodes // others should try to fetch it from any node where it is available. By now, // almost FETCHFROM_SRC other nodes may have it - getFrom += "*"; + getFrom = "*"; } try { var solrClient = coreContainer.getDefaultHttpSolrClient(); @@ -520,12 +519,15 @@ public void delete(String path) { for (String node : nodes) { String baseUrl = coreContainer.getZkController().getZkStateReader().getBaseUrlV2ForNodeName(node); - try (var solrClient = - new Http2SolrClient.Builder(baseUrl) - .withHttpClient(coreContainer.getDefaultHttpSolrClient()) - .build()) { + try { + var solrClient = coreContainer.getDefaultHttpSolrClient(); // invoke delete command on all nodes asynchronously - solrClient.requestAsync(solrRequest); + solrClient.requestWithBaseUrl(baseUrl, client -> client.requestAsync(solrRequest)); + } catch (SolrServerException | IOException e) { + throw new SolrException( + SolrException.ErrorCode.SERVER_ERROR, + "Failed to delete " + path + " on node " + node, + e); } } } From 07e6bb401079ca1ac7a816696415aa768544c3b2 Mon Sep 17 00:00:00 2001 From: Sanjay Dutt Date: Fri, 25 Oct 2024 21:38:08 +0530 Subject: [PATCH 25/26] MirroringUpdateProcessor switch to Http2SolrClient --- .../processor/MirroringUpdateProcessor.java | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/solr/modules/cross-dc/src/java/org/apache/solr/crossdc/update/processor/MirroringUpdateProcessor.java b/solr/modules/cross-dc/src/java/org/apache/solr/crossdc/update/processor/MirroringUpdateProcessor.java index b5b3fbfb935..55ef97bea62 100644 --- a/solr/modules/cross-dc/src/java/org/apache/solr/crossdc/update/processor/MirroringUpdateProcessor.java +++ b/solr/modules/cross-dc/src/java/org/apache/solr/crossdc/update/processor/MirroringUpdateProcessor.java @@ -26,11 +26,9 @@ import java.util.List; import java.util.Map; import java.util.TreeMap; -import org.apache.http.client.HttpClient; 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.HttpSolrClient; import org.apache.solr.client.solrj.request.UpdateRequest; import org.apache.solr.client.solrj.response.QueryResponse; import org.apache.solr.cloud.CloudDescriptor; @@ -209,15 +207,7 @@ public void processDelete(final DeleteUpdateCommand cmd) throws IOException { CloudDescriptor cloudDesc = cmd.getReq().getCore().getCoreDescriptor().getCloudDescriptor(); String collection = cloudDesc.getCollectionName(); - HttpClient httpClient = - cmd.getReq().getCore().getCoreContainer().getUpdateShardHandler().getDefaultHttpClient(); - - try (HttpSolrClient client = - new HttpSolrClient.Builder( - cmd.getReq().getCore().getCoreContainer().getZkController().getBaseUrl()) - .withHttpClient(httpClient) - .build()) { - + try { String uniqueField = cmd.getReq().getSchema().getUniqueKeyField().getName(); // TODO: implement "expand without deep paging" @@ -233,7 +223,9 @@ public void processDelete(final DeleteUpdateCommand cmd) throws IOException { boolean done = false; while (!done) { q.set(CursorMarkParams.CURSOR_MARK_PARAM, cursorMark); - QueryResponse rsp = client.query(collection, q); + var baseUrl = cmd.getReq().getCore().getCoreContainer().getZkController().getBaseUrl(); + var client = cmd.getReq().getCoreContainer().getDefaultHttpSolrClient(); + QueryResponse rsp = client.requestWithBaseUrl(baseUrl, c -> c.query(collection, q)); String nextCursorMark = rsp.getNextCursorMark(); if (log.isDebugEnabled()) { From 1ba30bdb8461187adc21ee85ba4622374e930659 Mon Sep 17 00:00:00 2001 From: Sanjay Dutt Date: Fri, 25 Oct 2024 21:54:14 +0530 Subject: [PATCH 26/26] Removed httpclient dependency from cross-dc --- solr/modules/cross-dc/build.gradle | 1 - 1 file changed, 1 deletion(-) diff --git a/solr/modules/cross-dc/build.gradle b/solr/modules/cross-dc/build.gradle index dbd9c00c1bf..44143285d08 100644 --- a/solr/modules/cross-dc/build.gradle +++ b/solr/modules/cross-dc/build.gradle @@ -36,7 +36,6 @@ dependencies { implementation 'org.apache.kafka:kafka-clients' implementation 'com.google.guava:guava' implementation 'io.dropwizard.metrics:metrics-core' - implementation 'org.apache.httpcomponents:httpclient' implementation 'org.apache.zookeeper:zookeeper' implementation 'org.apache.zookeeper:zookeeper-jute'