You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@solr.apache.org by no...@apache.org on 2022/04/13 08:47:44 UTC
[solr] 01/01: Lazily load and cache node properties
This is an automated email from the ASF dual-hosted git repository.
noble pushed a commit to branch jira/solr16146
in repository https://gitbox.apache.org/repos/asf/solr.git
commit 02fa8e68021c738e4a85a622df74cda124f07f38
Author: Noble Paul <no...@gmail.com>
AuthorDate: Wed Apr 13 18:47:16 2022 +1000
Lazily load and cache node properties
---
.../java/org/apache/solr/cloud/ZkController.java | 12 +-
.../org/apache/solr/handler/StreamHandler.java | 2 +-
.../handler/component/HttpShardHandlerFactory.java | 2 +-
.../routing/NodePreferenceRulesComparator.java | 12 +-
.../RequestReplicaListTransformerGenerator.java | 17 +-
.../solr/common/cloud/NodePropsProvider.java | 106 +++++++++++
.../solr/common/cloud/NodesSysPropsCacher.java | 209 ---------------------
.../solr/common/cloud/TestNodePropsProvider.java | 56 ++++++
8 files changed, 184 insertions(+), 232 deletions(-)
diff --git a/solr/core/src/java/org/apache/solr/cloud/ZkController.java b/solr/core/src/java/org/apache/solr/cloud/ZkController.java
index 0778f7e9b66..3120cad4778 100644
--- a/solr/core/src/java/org/apache/solr/cloud/ZkController.java
+++ b/solr/core/src/java/org/apache/solr/cloud/ZkController.java
@@ -131,6 +131,7 @@ public class ZkController implements Closeable {
private final DistributedMap overseerCompletedMap;
private final DistributedMap overseerFailureMap;
private final DistributedMap asyncIdsMap;
+ private final NodePropsProvider nodePropsProvider;
public static final String COLLECTION_PARAM_PREFIX = "collection.";
public static final String CONFIGNAME_PROP = "configName";
@@ -191,7 +192,6 @@ public class ZkController implements Closeable {
private String baseURL; // example: http://127.0.0.1:54065/solr
private final CloudConfig cloudConfig;
- private final NodesSysPropsCacher sysPropsCacher;
private final DistributedClusterStateUpdater distributedClusterStateUpdater;
@@ -501,9 +501,7 @@ public class ZkController implements Closeable {
}
this.overseerCollectionQueue = overseer.getCollectionQueue(zkClient);
this.overseerConfigSetQueue = overseer.getConfigSetQueue(zkClient);
- this.sysPropsCacher =
- new NodesSysPropsCacher(
- getSolrCloudManager().getNodeStateProvider(), getNodeName(), zkStateReader);
+ this.nodePropsProvider = new NodePropsProvider(cloudSolrClient, zkStateReader);
assert ObjectReleaseTracker.track(this);
}
@@ -628,8 +626,8 @@ public class ZkController implements Closeable {
}
}
- public NodesSysPropsCacher getSysPropsCacher() {
- return sysPropsCacher;
+ public NodePropsProvider getNodePropsProvider() {
+ return nodePropsProvider;
}
private void closeOutstandingElections(final Supplier<List<CoreDescriptor>> registerOnReconnect) {
@@ -729,7 +727,7 @@ public class ZkController implements Closeable {
} finally {
- sysPropsCacher.close();
+ nodePropsProvider.close();
customThreadPool.submit(() -> IOUtils.closeQuietly(cloudSolrClient));
customThreadPool.submit(() -> IOUtils.closeQuietly(cloudManager));
diff --git a/solr/core/src/java/org/apache/solr/handler/StreamHandler.java b/solr/core/src/java/org/apache/solr/handler/StreamHandler.java
index ff190ab0b40..50cd8c03fea 100644
--- a/solr/core/src/java/org/apache/solr/handler/StreamHandler.java
+++ b/solr/core/src/java/org/apache/solr/handler/StreamHandler.java
@@ -214,7 +214,7 @@ public class StreamHandler extends RequestHandlerBase
.toString(),
zkController.getNodeName(),
zkController.getBaseUrl(),
- zkController.getSysPropsCacher());
+ zkController.getNodePropsProvider());
} else {
requestReplicaListTransformerGenerator = new RequestReplicaListTransformerGenerator();
}
diff --git a/solr/core/src/java/org/apache/solr/handler/component/HttpShardHandlerFactory.java b/solr/core/src/java/org/apache/solr/handler/component/HttpShardHandlerFactory.java
index 275403426c5..63041bb2548 100644
--- a/solr/core/src/java/org/apache/solr/handler/component/HttpShardHandlerFactory.java
+++ b/solr/core/src/java/org/apache/solr/handler/component/HttpShardHandlerFactory.java
@@ -380,7 +380,7 @@ public class HttpShardHandlerFactory extends ShardHandlerFactory
.toString(),
zkController.getNodeName(),
zkController.getBaseUrl(),
- zkController.getSysPropsCacher());
+ zkController.getNodePropsProvider());
} else {
return requestReplicaListTransformerGenerator.getReplicaListTransformer(params);
}
diff --git a/solr/solrj/src/java/org/apache/solr/client/solrj/routing/NodePreferenceRulesComparator.java b/solr/solrj/src/java/org/apache/solr/client/solrj/routing/NodePreferenceRulesComparator.java
index 11560817b70..6221a573787 100644
--- a/solr/solrj/src/java/org/apache/solr/client/solrj/routing/NodePreferenceRulesComparator.java
+++ b/solr/solrj/src/java/org/apache/solr/client/solrj/routing/NodePreferenceRulesComparator.java
@@ -23,7 +23,7 @@ import java.util.Comparator;
import java.util.List;
import java.util.Map;
import org.apache.solr.common.StringUtils;
-import org.apache.solr.common.cloud.NodesSysPropsCacher;
+import org.apache.solr.common.cloud.NodePropsProvider;
import org.apache.solr.common.cloud.Replica;
import org.apache.solr.common.params.ShardParams;
import org.apache.solr.common.params.SolrParams;
@@ -40,7 +40,7 @@ import org.apache.solr.common.params.SolrParams;
*/
public class NodePreferenceRulesComparator implements Comparator<Object> {
- private final NodesSysPropsCacher sysPropsCache;
+ private final NodePropsProvider sysPropsCache;
private final String nodeName;
private final List<PreferenceRule> sortRules;
private final List<PreferenceRule> preferenceRules;
@@ -60,10 +60,10 @@ public class NodePreferenceRulesComparator implements Comparator<Object> {
final SolrParams requestParams,
final String nodeName,
final String localHostAddress,
- final NodesSysPropsCacher sysPropsCache,
+ final NodePropsProvider nodePropsProvider,
final ReplicaListTransformerFactory defaultRltFactory,
final ReplicaListTransformerFactory stableRltFactory) {
- this.sysPropsCache = sysPropsCache;
+ this.sysPropsCache = nodePropsProvider;
this.preferenceRules = preferenceRules;
this.nodeName = nodeName;
this.localHostAddress = localHostAddress;
@@ -175,8 +175,8 @@ public class NodePreferenceRulesComparator implements Comparator<Object> {
Collection<String> tags = Collections.singletonList(metricTag);
String otherNodeName = ((Replica) o).getNodeName();
- Map<String, Object> currentNodeMetric = sysPropsCache.getSysProps(nodeName, tags);
- Map<String, Object> otherNodeMetric = sysPropsCache.getSysProps(otherNodeName, tags);
+ Map<String, Object> currentNodeMetric = sysPropsCache.getSystemProperties(nodeName, tags);
+ Map<String, Object> otherNodeMetric = sysPropsCache.getSystemProperties(otherNodeName, tags);
return currentNodeMetric.equals(otherNodeMetric);
}
diff --git a/solr/solrj/src/java/org/apache/solr/client/solrj/routing/RequestReplicaListTransformerGenerator.java b/solr/solrj/src/java/org/apache/solr/client/solrj/routing/RequestReplicaListTransformerGenerator.java
index d7eb93ba245..94091bb83cc 100644
--- a/solr/solrj/src/java/org/apache/solr/client/solrj/routing/RequestReplicaListTransformerGenerator.java
+++ b/solr/solrj/src/java/org/apache/solr/client/solrj/routing/RequestReplicaListTransformerGenerator.java
@@ -22,9 +22,10 @@ import java.util.Iterator;
import java.util.List;
import java.util.Objects;
import java.util.Random;
+
import org.apache.solr.common.SolrException;
import org.apache.solr.common.SolrException.ErrorCode;
-import org.apache.solr.common.cloud.NodesSysPropsCacher;
+import org.apache.solr.common.cloud.NodePropsProvider;
import org.apache.solr.common.params.ShardParams;
import org.apache.solr.common.params.SolrParams;
import org.slf4j.Logger;
@@ -45,7 +46,7 @@ public class RequestReplicaListTransformerGenerator {
private final String defaultShardPreferences;
private final String nodeName;
private final String localHostAddress;
- private final NodesSysPropsCacher sysPropsCacher;
+ private final NodePropsProvider nodePropsProvider;
public RequestReplicaListTransformerGenerator() {
this(null);
@@ -65,8 +66,8 @@ public class RequestReplicaListTransformerGenerator {
String defaultShardPreferences,
String nodeName,
String localHostAddress,
- NodesSysPropsCacher sysPropsCacher) {
- this(null, null, defaultShardPreferences, nodeName, localHostAddress, sysPropsCacher);
+ NodePropsProvider nodePropsProvider) {
+ this(null, null, defaultShardPreferences, nodeName, localHostAddress, nodePropsProvider);
}
public RequestReplicaListTransformerGenerator(
@@ -75,14 +76,14 @@ public class RequestReplicaListTransformerGenerator {
String defaultShardPreferences,
String nodeName,
String localHostAddress,
- NodesSysPropsCacher sysPropsCacher) {
+ NodePropsProvider nodePropsProvider) {
this.defaultRltFactory = Objects.requireNonNullElse(defaultRltFactory, RANDOM_RLTF);
this.stableRltFactory =
Objects.requireNonNullElseGet(stableRltFactory, AffinityReplicaListTransformerFactory::new);
this.defaultShardPreferences = Objects.requireNonNullElse(defaultShardPreferences, "");
this.nodeName = nodeName;
this.localHostAddress = localHostAddress;
- this.sysPropsCacher = sysPropsCacher;
+ this.nodePropsProvider = nodePropsProvider;
}
public ReplicaListTransformer getReplicaListTransformer(final SolrParams requestParams) {
@@ -99,7 +100,7 @@ public class RequestReplicaListTransformerGenerator {
String defaultShardPreferences,
String nodeName,
String localHostAddress,
- NodesSysPropsCacher sysPropsCacher) {
+ NodePropsProvider nodePropsProvider) {
defaultShardPreferences =
Objects.requireNonNullElse(defaultShardPreferences, this.defaultShardPreferences);
final String shardsPreferenceSpec =
@@ -115,7 +116,7 @@ public class RequestReplicaListTransformerGenerator {
localHostAddress != null
? localHostAddress
: this.localHostAddress, // could still be null
- sysPropsCacher != null ? sysPropsCacher : this.sysPropsCacher, // could still be null
+ nodePropsProvider != null ? nodePropsProvider : this.nodePropsProvider, // could still be null
defaultRltFactory,
stableRltFactory);
ReplicaListTransformer baseReplicaListTransformer =
diff --git a/solr/solrj/src/java/org/apache/solr/common/cloud/NodePropsProvider.java b/solr/solrj/src/java/org/apache/solr/common/cloud/NodePropsProvider.java
new file mode 100644
index 00000000000..f7c8e1ca16f
--- /dev/null
+++ b/solr/solrj/src/java/org/apache/solr/common/cloud/NodePropsProvider.java
@@ -0,0 +1,106 @@
+/*
+ * 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.common.cloud;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+import org.apache.solr.client.solrj.SolrRequest;
+import org.apache.solr.client.solrj.impl.CloudLegacySolrClient;
+import org.apache.solr.client.solrj.request.GenericSolrRequest;
+import org.apache.solr.common.params.ModifiableSolrParams;
+import org.apache.solr.common.params.SolrParams;
+import org.apache.solr.common.util.Utils;
+
+import org.apache.solr.common.NavigableObject;
+
+/**
+ * Fetch lazily and cache a node's system properties
+ *
+ */
+public class NodePropsProvider implements AutoCloseable {
+ private volatile boolean isClosed = false;
+ private final Map<String ,Map<String, Object>> nodeVsTagsCache = new ConcurrentHashMap<>();
+ private ZkStateReader zkStateReader;
+ private final CloudLegacySolrClient solrClient;
+
+ public NodePropsProvider(CloudLegacySolrClient solrClient, ZkStateReader zkStateReader) {
+ this.zkStateReader = zkStateReader;
+ this.solrClient = solrClient;
+ zkStateReader.registerLiveNodesListener((oldNodes, newNodes) -> {
+ for (String n : oldNodes) {
+ if(!newNodes.contains(n)) {
+ //this node has gone down, clear data
+ nodeVsTagsCache.remove(n);
+ }
+ }
+ return isClosed;
+ });
+
+ }
+
+ public Map<String, Object> getSystemProperties(String nodeName, Collection<String> tags) {
+ Map<String, Object> cached = nodeVsTagsCache.computeIfAbsent(nodeName, s -> new LinkedHashMap<>());
+ Map<String, Object> result = new LinkedHashMap<>();
+ for (String tag : tags) {
+ if (!cached.containsKey(tag)) {
+ //at least one property is missing. fetch properties from the node
+ Map<String, Object> props = fetchProps(nodeName, tags);
+ //make a copy
+ cached = new LinkedHashMap<>(cached);
+ //merge all properties
+ cached.putAll(props);
+ //update the cache with the new set of properties
+ nodeVsTagsCache.put(nodeName, cached);
+ return props;
+ } else {
+ result.put(tag, cached.get(tag));
+ }
+ }
+ return result;
+ }
+
+ private Map<String, Object> fetchProps(String nodeName, Collection<String> tags) {
+ SolrParams p = new ModifiableSolrParams();
+ StringBuilder sb = new StringBuilder(zkStateReader.getBaseUrlForNodeName(nodeName));
+ sb.append("/admin/metrics?omitHeader=true&wt=javabin");
+ LinkedHashMap<String,String> keys= new LinkedHashMap<>();
+ for (String tag : tags) {
+ String metricsKey = "solr.jvm:system.properties:"+tag;
+ keys.put(tag, metricsKey);
+ sb.append("&key=").append(metricsKey);
+ }
+
+ GenericSolrRequest req = new GenericSolrRequest(SolrRequest.METHOD.GET, "/admin/metrics", p);
+
+ Map<String, Object> result = new LinkedHashMap<>();
+ NavigableObject response = (NavigableObject) Utils.executeGET(solrClient.getHttpClient(), sb.toString(), Utils.JAVABINCONSUMER);
+ NavigableObject metrics = (NavigableObject) response._get("metrics", Collections.emptyMap());
+ keys.forEach((tag, key) -> result.put(tag, metrics._get(key, null)));
+ return result;
+ }
+
+ @Override
+ public void close() {
+ isClosed = true;
+
+ }
+}
diff --git a/solr/solrj/src/java/org/apache/solr/common/cloud/NodesSysPropsCacher.java b/solr/solrj/src/java/org/apache/solr/common/cloud/NodesSysPropsCacher.java
deleted file mode 100644
index 26ef61fef86..00000000000
--- a/solr/solrj/src/java/org/apache/solr/common/cloud/NodesSysPropsCacher.java
+++ /dev/null
@@ -1,209 +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.common.cloud;
-
-import static org.apache.solr.common.cloud.rule.ImplicitSnitch.SYSPROP;
-
-import java.lang.invoke.MethodHandles;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.concurrent.atomic.AtomicInteger;
-import java.util.stream.Collectors;
-import org.apache.solr.client.solrj.cloud.NodeStateProvider;
-import org.apache.solr.client.solrj.routing.PreferenceRule;
-import org.apache.solr.common.SolrCloseable;
-import org.apache.solr.common.params.ShardParams;
-import org.apache.solr.common.util.CommonTestInjection;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * Caching other nodes system properties. The properties that will be cached based on the value
- * define in {@link org.apache.solr.common.cloud.ZkStateReader#DEFAULT_SHARD_PREFERENCES } of {@link
- * org.apache.solr.common.cloud.ZkStateReader#CLUSTER_PROPS }. If that key does not present then
- * this cacher will do nothing.
- *
- * <p>The cache will be refresh whenever /live_nodes get changed.
- */
-public class NodesSysPropsCacher implements SolrCloseable {
- private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
- private static final int NUM_RETRY = 5;
-
- private final AtomicBoolean isRunning = new AtomicBoolean(false);
- private final NodeStateProvider nodeStateProvider;
- private Map<String, String> additionalProps = CommonTestInjection.injectAdditionalProps();
- private final String currentNode;
- private final ConcurrentHashMap<String, Map<String, Object>> cache = new ConcurrentHashMap<>();
- private final AtomicInteger fetchCounting = new AtomicInteger(0);
-
- private volatile boolean isClosed;
- private volatile Collection<String> tags = new ArrayList<>();
-
- public NodesSysPropsCacher(
- NodeStateProvider nodeStateProvider, String currentNode, ZkStateReader stateReader) {
- this.nodeStateProvider = nodeStateProvider;
- this.currentNode = currentNode;
-
- stateReader.registerClusterPropertiesListener(
- properties -> {
- Collection<String> tags = new ArrayList<>();
- String shardPreferences =
- (String) properties.getOrDefault(ZkStateReader.DEFAULT_SHARD_PREFERENCES, "");
- if (shardPreferences.contains(ShardParams.SHARDS_PREFERENCE_NODE_WITH_SAME_SYSPROP)) {
- try {
- tags =
- PreferenceRule.from(shardPreferences).stream()
- .filter(
- r -> ShardParams.SHARDS_PREFERENCE_NODE_WITH_SAME_SYSPROP.equals(r.name))
- .map(r -> r.value)
- .collect(Collectors.toSet());
- } catch (Exception e) {
- log.info("Error on parsing shards preference:{}", shardPreferences);
- }
- }
-
- if (tags.isEmpty()) {
- pause();
- } else {
- start(tags);
- // start fetching now
- fetchSysProps(stateReader.getClusterState().getLiveNodes());
- }
- return isClosed;
- });
-
- stateReader.registerLiveNodesListener(
- (oldLiveNodes, newLiveNodes) -> {
- fetchSysProps(newLiveNodes);
- return isClosed;
- });
- }
-
- private void start(Collection<String> tags) {
- if (isClosed) return;
- this.tags = tags;
- isRunning.set(true);
- }
-
- private void fetchSysProps(Set<String> newLiveNodes) {
- if (isRunning.get()) {
- int fetchRound = fetchCounting.incrementAndGet();
- // TODO smarter keeping caching entries by relying on Stat.cversion
- cache.clear();
- for (String node : newLiveNodes) {
- // this might takes some times to finish, therefore if there are a latter change in listener
- // triggering this method, skipping the old runner
- if (isClosed && fetchRound != fetchCounting.get()) return;
-
- if (currentNode.equals(node)) {
- Map<String, String> props = new HashMap<>();
- for (String tag : tags) {
- String propName = tag.substring(SYSPROP.length());
- if (additionalProps != null && additionalProps.containsKey(propName)) {
- props.put(tag, additionalProps.get(propName));
- } else {
- props.put(tag, System.getProperty(propName));
- }
- }
- cache.put(node, Collections.unmodifiableMap(props));
- } else {
- fetchRemoteProps(node, fetchRound);
- }
- }
- }
- }
-
- private void fetchRemoteProps(String node, int fetchRound) {
- for (int i = 0; i < NUM_RETRY; i++) {
- if (isClosed && fetchRound != fetchCounting.get()) return;
-
- try {
- Map<String, Object> props = nodeStateProvider.getNodeValues(node, tags);
- cache.put(node, Collections.unmodifiableMap(props));
- break;
- } catch (Exception e) {
- try {
- // 1, 4, 9
- int backOffTime = 1000 * (i + 1);
- backOffTime = backOffTime * backOffTime;
- backOffTime = Math.min(10000, backOffTime);
- Thread.sleep(backOffTime);
- } catch (InterruptedException e1) {
- Thread.currentThread().interrupt();
- log.info(
- "Exception on caching node:{} system.properties:{}, retry {}/{}",
- node,
- tags,
- i + 1,
- NUM_RETRY,
- e); // nowarn
- break;
- }
- log.info(
- "Exception on caching node:{} system.properties:{}, retry {}/{}",
- node,
- tags,
- i + 1,
- NUM_RETRY,
- e); // nowarn
- }
- }
- }
-
- public Map<String, Object> getSysProps(String node, Collection<String> tags) {
- Map<String, Object> props = cache.get(node);
- HashMap<String, Object> result = new HashMap<>();
- if (props != null) {
- for (String tag : tags) {
- if (props.containsKey(tag)) {
- result.put(tag, props.get(tag));
- }
- }
- }
- return result;
- }
-
- public int getCacheSize() {
- return cache.size();
- }
-
- public boolean isRunning() {
- return isRunning.get();
- }
-
- private void pause() {
- isRunning.set(false);
- }
-
- @Override
- public boolean isClosed() {
- return isClosed;
- }
-
- @Override
- public void close() {
- isClosed = true;
- pause();
- }
-}
diff --git a/solr/solrj/src/test/org/apache/solr/common/cloud/TestNodePropsProvider.java b/solr/solrj/src/test/org/apache/solr/common/cloud/TestNodePropsProvider.java
new file mode 100644
index 00000000000..a823a1b23ab
--- /dev/null
+++ b/solr/solrj/src/test/org/apache/solr/common/cloud/TestNodePropsProvider.java
@@ -0,0 +1,56 @@
+/*
+ * 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.common.cloud;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.solr.client.solrj.embedded.JettySolrRunner;
+import org.apache.solr.cloud.MiniSolrCloudCluster;
+import org.apache.solr.cloud.SolrCloudTestCase;
+import org.junit.Test;
+
+public class TestNodePropsProvider extends SolrCloudTestCase {
+
+ @Test
+ public void testSysProps() throws Exception {
+ System.setProperty("metricsEnabled", "true");
+ MiniSolrCloudCluster cluster =
+ configureCluster(4)
+ .withJettyConfig(jetty -> jetty.enableV2(true))
+ .addConfig("config", getFile("solrj/solr/collection1/conf").toPath())
+ .configure();
+
+ System.clearProperty("metricsEnabled");
+ NodePropsProvider nodePropsProvider = cluster.getRandomJetty(random()).getCoreContainer().getZkController().getNodePropsProvider();
+
+ try {
+ for (JettySolrRunner j : cluster.getJettySolrRunners()) {
+ List<String> tags = Arrays.asList("file.encoding", "java.vm.version");
+ Map<String, Object> props = nodePropsProvider.getSystemProperties(j.getNodeName(), tags);
+ for (String tag : tags) assertNotNull(props.get(tag));
+ tags = Arrays.asList("file.encoding", "java.vm.version","os.arch" );
+ props = nodePropsProvider.getSystemProperties(j.getNodeName(), tags);
+ for (String tag : tags) assertNotNull(props.get(tag));
+ }
+ } finally {
+ cluster.shutdown();
+ }
+ }
+}