This is an automated email from the ASF dual-hosted git repository.
dsmiley pushed a commit to branch branch_9x
in repository https://gitbox.apache.org/repos/asf/solr.git
The following commit(s) were added to refs/heads/branch_9x by this push:
new ff0f9050075 SOLR-17607: Http ClusterStateProvider, lazy connect (#3249)
ff0f9050075 is described below
commit ff0f9050075543d64d6ccc760466a233c00863e8
Author: David Smiley <[email protected]>
AuthorDate: Tue Mar 11 19:38:17 2025 -0400
SOLR-17607: Http ClusterStateProvider, lazy connect (#3249)
i.e. stop eagerly connecting when CloudSolrClient is created.
Update urlScheme on successful getLiveNodes
(cherry picked from commit 9918ee640dce7123ff51eb38d9eb1c6f4e06b487)
---
solr/CHANGES.txt | 3 +
.../solrj/impl/BaseHttpClusterStateProvider.java | 114 ++++++++-------------
.../solrj/impl/Http2ClusterStateProvider.java | 2 +-
.../solrj/impl/HttpClusterStateProvider.java | 2 +-
.../solrj/impl/CloudHttp2SolrClientTest.java | 1 +
5 files changed, 49 insertions(+), 73 deletions(-)
diff --git a/solr/CHANGES.txt b/solr/CHANGES.txt
index b14aff72a80..7301c7ffd86 100644
--- a/solr/CHANGES.txt
+++ b/solr/CHANGES.txt
@@ -33,6 +33,9 @@ Improvements
`org.apache.solr.client.solrj.request.FileStoreApi`. The older form of this
endpoint (`GET /api/node/files`) is deprecated and is slated to
be removed. (Jason Gerlowski)
+* SOLR-17607: SolrJ CloudSolrClient configured with HTTP URLs will no longer
eagerly connect to
+ anything. (David Smiley)
+
Optimizations
---------------------
* SOLR-17578: Remove ZkController internal core supplier, for slightly faster
reconnection after Zookeeper session loss. (Pierre Salagnac)
diff --git
a/solr/solrj/src/java/org/apache/solr/client/solrj/impl/BaseHttpClusterStateProvider.java
b/solr/solrj/src/java/org/apache/solr/client/solrj/impl/BaseHttpClusterStateProvider.java
index 8d956ca7a94..b1477a0f45a 100644
---
a/solr/solrj/src/java/org/apache/solr/client/solrj/impl/BaseHttpClusterStateProvider.java
+++
b/solr/solrj/src/java/org/apache/solr/client/solrj/impl/BaseHttpClusterStateProvider.java
@@ -56,7 +56,7 @@ public abstract class BaseHttpClusterStateProvider implements
ClusterStateProvid
private String urlScheme;
private List<URL> configuredNodes;
- volatile Set<String> liveNodes;
+ volatile Set<String> liveNodes; // initially null then never null
long liveNodesTimestamp = 0;
volatile Map<String, List<String>> aliases;
volatile Map<String, Map<String, String>> aliasProperties;
@@ -65,41 +65,24 @@ public abstract class BaseHttpClusterStateProvider
implements ClusterStateProvid
// the liveNodes and aliases cache will be invalidated after 5 secs
private int cacheTimeout =
EnvUtils.getPropertyAsInteger("solr.solrj.cache.timeout.sec", 5);
- public void init(List<String> solrUrls) throws Exception {
+ protected void initConfiguredNodes(List<String> solrUrls) throws Exception {
this.configuredNodes =
solrUrls.stream()
- .map(
- (solrUrl) -> {
- try {
- return new URI(solrUrl).toURL();
- } catch (MalformedURLException | URISyntaxException e) {
- throw new IllegalArgumentException(
- "Failed to parse base Solr URL " + solrUrl, e);
- }
- })
+ .map(BaseHttpClusterStateProvider::stringToUrl)
.collect(Collectors.toList());
+ }
- for (String solrUrl : solrUrls) {
- urlScheme = solrUrl.startsWith("https") ? "https" : "http";
- try (SolrClient initialClient = getSolrClient(solrUrl)) {
- this.liveNodes = fetchLiveNodes(initialClient);
- liveNodesTimestamp = System.nanoTime();
- break;
- } catch (SolrServerException | IOException e) {
- log.warn("Attempt to fetch cluster state from {} failed.", solrUrl, e);
- }
+ private static URL stringToUrl(String solrUrl) {
+ try {
+ return new URI(solrUrl).toURL();
+ } catch (MalformedURLException | URISyntaxException e) {
+ throw new IllegalArgumentException("Failed to parse base Solr URL " +
solrUrl, e);
}
+ }
- if (this.liveNodes == null || this.liveNodes.isEmpty()) {
- throw new RuntimeException(
- "Tried fetching live_nodes using Solr URLs provided, i.e. "
- + solrUrls
- + ". However, "
- + "succeeded in obtaining the cluster state from none of them."
- + "If you think your Solr cluster is up and is accessible,"
- + " you could try re-creating a new CloudSolrClient using
working"
- + " solrUrl(s).");
- }
+ @Override
+ public void connect() {
+ getLiveNodes();
}
/** Create a SolrClient implementation that uses the specified Solr node URL
*/
@@ -114,7 +97,7 @@ public abstract class BaseHttpClusterStateProvider
implements ClusterStateProvid
@Override
public ClusterState.CollectionRef getState(String collection) {
- for (String nodeName : liveNodes) {
+ for (String nodeName : getLiveNodes()) {
String baseUrl = Utils.getBaseUrlForNodeName(nodeName, urlScheme);
try (SolrClient client = getSolrClient(baseUrl)) {
DocCollection docCollection = fetchCollectionState(client, collection);
@@ -238,43 +221,44 @@ public abstract class BaseHttpClusterStateProvider
implements ClusterStateProvid
}
@Override
- public Set<String> getLiveNodes() {
- if (TimeUnit.SECONDS.convert((System.nanoTime() - liveNodesTimestamp),
TimeUnit.NANOSECONDS)
- > getCacheTimeout()) {
+ public synchronized Set<String> getLiveNodes() {
+ // synchronized because there's no value in multiple doing this at the
same time
+
+ // only in the initial state, liveNodes is null
+ if (liveNodes != null) {
+ if (TimeUnit.SECONDS.convert((System.nanoTime() - liveNodesTimestamp),
TimeUnit.NANOSECONDS)
+ <= getCacheTimeout()) {
+ return this.liveNodes; // cached copy is fresh enough
+ }
if (liveNodes.stream()
- .anyMatch((node) ->
updateLiveNodes(URLUtil.getBaseUrlForNodeName(node, urlScheme))))
- return this.liveNodes;
+ .map(node -> URLUtil.getBaseUrlForNodeName(node, urlScheme))
+ .map(BaseHttpClusterStateProvider::stringToUrl)
+ .anyMatch(this::updateLiveNodes)) return this.liveNodes;
- log.warn(
- "Attempt to fetch cluster state from all known live nodes {} failed.
Trying backup nodes",
- liveNodes);
+ log.warn("Failed fetching live_nodes from {}. Trying configured
nodes...", liveNodes);
+ }
- if (configuredNodes.stream().anyMatch((node) ->
updateLiveNodes(node.toString())))
- return this.liveNodes;
+ if (configuredNodes.stream().anyMatch(this::updateLiveNodes)) return
this.liveNodes;
- throw new RuntimeException(
- "Tried fetching live_nodes using all the node names we knew of, i.e.
"
- + liveNodes
- + ". However, "
- + "succeeded in obtaining the cluster state from none of them."
- + "If you think your Solr cluster is up and is accessible,"
- + " you could try re-creating a new CloudSolrClient using
working"
- + " solrUrl(s).");
- } else {
- return this.liveNodes; // cached copy is fresh enough
- }
+ throw new RuntimeException(
+ "Failed fetching live_nodes from "
+ + configuredNodes
+ + ". If you think your Solr cluster is up and is accessible,"
+ + " you could try re-creating a new CloudSolrClient using working"
+ + " solr URLs.");
}
- private boolean updateLiveNodes(String liveNode) {
- try (SolrClient client = getSolrClient(liveNode)) {
+ private boolean updateLiveNodes(URL url) {
+ try (SolrClient client = getSolrClient(url.toString())) {
this.liveNodes = fetchLiveNodes(client);
liveNodesTimestamp = System.nanoTime();
+ urlScheme = url.getProtocol();
return true;
} catch (Exception e) {
- log.warn("Attempt to fetch cluster state from {} failed.", liveNode, e);
+ log.warn("Attempt to fetch live_nodes from {} failed.", url, e);
+ return false;
}
- return false;
}
@SuppressWarnings({"unchecked"})
@@ -299,20 +283,11 @@ public abstract class BaseHttpClusterStateProvider
implements ClusterStateProvid
}
private Map<String, List<String>> getAliases(boolean forceFetch) {
- if (this.liveNodes == null) {
- throw new RuntimeException(
- "We don't know of any live_nodes to fetch the"
- + " latest aliases information from. "
- + "If you think your Solr cluster is up and is accessible,"
- + " you could try re-creating a new CloudSolrClient using
working"
- + " solrUrl(s).");
- }
-
if (forceFetch
|| this.aliases == null
|| TimeUnit.SECONDS.convert((System.nanoTime() - aliasesTimestamp),
TimeUnit.NANOSECONDS)
> getCacheTimeout()) {
- for (String nodeName : liveNodes) {
+ for (String nodeName : getLiveNodes()) {
String baseUrl = Utils.getBaseUrlForNodeName(nodeName, urlScheme);
try (SolrClient client = getSolrClient(baseUrl)) {
@@ -359,7 +334,7 @@ public abstract class BaseHttpClusterStateProvider
implements ClusterStateProvid
@Override
public ClusterState getClusterState() {
- for (String nodeName : liveNodes) {
+ for (String nodeName : getLiveNodes()) {
String baseUrl = Utils.getBaseUrlForNodeName(nodeName, urlScheme);
try (SolrClient client = getSolrClient(baseUrl)) {
return fetchClusterState(client);
@@ -385,7 +360,7 @@ public abstract class BaseHttpClusterStateProvider
implements ClusterStateProvid
@SuppressWarnings("unchecked")
@Override
public Map<String, Object> getClusterProperties() {
- for (String nodeName : liveNodes) {
+ for (String nodeName : getLiveNodes()) {
String baseUrl = Utils.getBaseUrlForNodeName(nodeName, urlScheme);
try (SolrClient client = getSolrClient(baseUrl)) {
SimpleOrderedMap<?> cluster =
@@ -421,9 +396,6 @@ public abstract class BaseHttpClusterStateProvider
implements ClusterStateProvid
return getClusterProperties().get(propertyName);
}
- @Override
- public void connect() {}
-
public int getCacheTimeout() {
return cacheTimeout;
}
diff --git
a/solr/solrj/src/java/org/apache/solr/client/solrj/impl/Http2ClusterStateProvider.java
b/solr/solrj/src/java/org/apache/solr/client/solrj/impl/Http2ClusterStateProvider.java
index 3bb222ae430..a7abb80b71d 100644
---
a/solr/solrj/src/java/org/apache/solr/client/solrj/impl/Http2ClusterStateProvider.java
+++
b/solr/solrj/src/java/org/apache/solr/client/solrj/impl/Http2ClusterStateProvider.java
@@ -29,7 +29,7 @@ public class Http2ClusterStateProvider extends
BaseHttpClusterStateProvider {
throws Exception {
this.httpClient = httpClient == null ? new
Http2SolrClient.Builder().build() : httpClient;
this.closeClient = httpClient == null;
- init(solrUrls);
+ initConfiguredNodes(solrUrls);
}
@Override
diff --git
a/solr/solrj/src/java/org/apache/solr/client/solrj/impl/HttpClusterStateProvider.java
b/solr/solrj/src/java/org/apache/solr/client/solrj/impl/HttpClusterStateProvider.java
index 56c6b08c7d9..353c15fd1b7 100644
---
a/solr/solrj/src/java/org/apache/solr/client/solrj/impl/HttpClusterStateProvider.java
+++
b/solr/solrj/src/java/org/apache/solr/client/solrj/impl/HttpClusterStateProvider.java
@@ -35,7 +35,7 @@ public class HttpClusterStateProvider extends
BaseHttpClusterStateProvider {
public HttpClusterStateProvider(List<String> solrUrls, HttpClient
httpClient) throws Exception {
this.httpClient = httpClient == null ? HttpClientUtil.createClient(null) :
httpClient;
this.clientIsInternal = httpClient == null;
- init(solrUrls);
+ initConfiguredNodes(solrUrls);
}
@Override
diff --git
a/solr/solrj/src/test/org/apache/solr/client/solrj/impl/CloudHttp2SolrClientTest.java
b/solr/solrj/src/test/org/apache/solr/client/solrj/impl/CloudHttp2SolrClientTest.java
index 9d5212ad0e7..86659a42420 100644
---
a/solr/solrj/src/test/org/apache/solr/client/solrj/impl/CloudHttp2SolrClientTest.java
+++
b/solr/solrj/src/test/org/apache/solr/client/solrj/impl/CloudHttp2SolrClientTest.java
@@ -261,6 +261,7 @@ public class CloudHttp2SolrClientTest extends
SolrCloudTestCase {
try (LogListener adminLogs =
LogListener.info(HttpSolrCall.class).substring("[admin]");
CloudSolrClient solrClient = createHttpCSPBasedCloudSolrClient(); ) {
+ solrClient.getClusterStateProvider().getLiveNodes(); // talks to Solr
assertEquals(1, adminLogs.getCount());
assertTrue(