From b9bfb853c3281fa560d05c7c00c14b13d9e6af4c Mon Sep 17 00:00:00 2001 From: Keith Laban Date: Thu, 30 Jun 2016 11:12:16 -0400 Subject: [PATCH] SOLR-9280 - make nodeName a configurable parameter in solr.xml --- .../org/apache/solr/cloud/ZkController.java | 25 ++++--- .../org/apache/solr/core/CloudConfig.java | 17 ++++- .../org/apache/solr/core/CoreContainer.java | 4 ++ .../org/apache/solr/core/SolrXmlConfig.java | 3 + solr/core/src/test-files/solr/solr.xml | 1 + .../apache/solr/cloud/HttpPartitionTest.java | 8 --- .../apache/solr/cloud/RollingRestartTest.java | 1 + .../apache/solr/cloud/ZkControllerTest.java | 30 ++++---- .../solr/common/cloud/ZkStateReader.java | 70 ++++++++++++++----- .../cloud/AbstractFullDistribZkTestBase.java | 23 ++++-- .../apache/solr/cloud/MockZkStateReader.java | 15 ++++ 11 files changed, 140 insertions(+), 57 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 9b0a90e58757..86c27d43376c 100644 --- a/solr/core/src/java/org/apache/solr/cloud/ZkController.java +++ b/solr/core/src/java/org/apache/solr/cloud/ZkController.java @@ -181,7 +181,8 @@ public boolean equals(Object obj) { private final int localHostPort; // example: 54065 private final String hostName; // example: 127.0.0.1 - private final String nodeName; // example: 127.0.0.1:54065_solr + private final String genericNodeName; // example: 127.0.0.1:54065_solr + private final String nodeName; //set in solr.xml or genericNodeName as default private String baseURL; // example: http://127.0.0.1:54065/solr private final CloudConfig cloudConfig; @@ -271,8 +272,11 @@ public ZkController(final CoreContainer cc, String zkServerAddress, int zkClient this.zkServerAddress = zkServerAddress; this.localHostPort = cloudConfig.getSolrHostPort(); this.hostName = normalizeHostName(cloudConfig.getHost()); - this.nodeName = generateNodeName(this.hostName, Integer.toString(this.localHostPort), localHostContext); - MDCLoggingContext.setNode(nodeName); + this.genericNodeName = generateNodeName(this.hostName, Integer.toString(this.localHostPort), localHostContext); + String nodeName = cloudConfig.getNodeName(); + this.nodeName = nodeName == null || nodeName.isEmpty() ? this.genericNodeName : nodeName; + String loggingContext = this.nodeName == this.genericNodeName ? this.genericNodeName : String.format("%s[%s]", this.nodeName, this.genericNodeName); + MDCLoggingContext.setNode(loggingContext); this.leaderVoteWait = cloudConfig.getLeaderVoteWait(); this.leaderConflictResolveWait = cloudConfig.getLeaderConflictResolveWait(); @@ -671,7 +675,7 @@ private void init(CurrentCoreDescriptorProvider registerOnReconnect) { try { createClusterZkNodes(zkClient); zkStateReader.createClusterStateWatchersAndUpdate(); - this.baseURL = zkStateReader.getBaseUrlForNodeName(this.nodeName); + this.baseURL = zkStateReader.getBaseUrlFromGenericNodeName(this.genericNodeName); checkForExistingEphemeralNode(); @@ -738,9 +742,10 @@ private void checkForExistingEphemeralNode() throws KeeperException, Interrupted } boolean deleted = deletedLatch.await(zkClient.getSolrZooKeeper().getSessionTimeout() * 2, TimeUnit.MILLISECONDS); + if (!deleted) { - throw new SolrException(ErrorCode.SERVER_ERROR, "A previous ephemeral live node still exists. " + - "Solr cannot continue. Please ensure that no other Solr process using the same port is running already."); + throw new SolrException(ErrorCode.SERVER_ERROR, "An ephemeral live node still exists named '" + this.nodeName + + "'. Solr cannot continue. Please ensure that no other Solr process using the same port is running already or configured with the same nodeName in solr.xml"); } } @@ -819,7 +824,11 @@ private void createEphemeralLiveNode() throws KeeperException, String nodeName = getNodeName(); String nodePath = ZkStateReader.LIVE_NODES_ZKNODE + "/" + nodeName; log.info("Register node as live in ZooKeeper:" + nodePath); - zkClient.makePath(nodePath, CreateMode.EPHEMERAL, true); + zkClient.makePath(nodePath, getGenericNodeName().getBytes(), CreateMode.EPHEMERAL, true); + } + + private String getGenericNodeName() { + return genericNodeName; } public String getNodeName() { @@ -2104,7 +2113,7 @@ public void updateLeaderInitiatedRecoveryState(String collection, String shardId stateObj.put(ZkStateReader.STATE_PROP, state.toString()); // only update the createdBy value if it's not set if (stateObj.get("createdByNodeName") == null) { - stateObj.put("createdByNodeName", this.nodeName); + stateObj.put("createdByNodeName", this.genericNodeName); } if (stateObj.get("createdByCoreNodeName") == null && leaderCoreNodeName != null) { stateObj.put("createdByCoreNodeName", leaderCoreNodeName); diff --git a/solr/core/src/java/org/apache/solr/core/CloudConfig.java b/solr/core/src/java/org/apache/solr/core/CloudConfig.java index 447dd22293b1..7ed832ae6832 100644 --- a/solr/core/src/java/org/apache/solr/core/CloudConfig.java +++ b/solr/core/src/java/org/apache/solr/core/CloudConfig.java @@ -49,11 +49,13 @@ public class CloudConfig { private final int createCollectionWaitTimeTillActive; private final boolean createCollectionCheckLeaderActive; + + private final String nodeName; CloudConfig(String zkHost, int zkClientTimeout, int hostPort, String hostName, String hostContext, boolean useGenericCoreNames, int leaderVoteWait, int leaderConflictResolveWait, int autoReplicaFailoverWaitAfterExpiration, int autoReplicaFailoverWorkLoopDelay, int autoReplicaFailoverBadNodeExpiration, String zkCredentialsProviderClass, - String zkACLProviderClass, int createCollectionWaitTimeTillActive, boolean createCollectionCheckLeaderActive) { + String zkACLProviderClass, int createCollectionWaitTimeTillActive, boolean createCollectionCheckLeaderActive, String nodeName) { this.zkHost = zkHost; this.zkClientTimeout = zkClientTimeout; this.hostPort = hostPort; @@ -69,6 +71,7 @@ public class CloudConfig { this.zkACLProviderClass = zkACLProviderClass; this.createCollectionWaitTimeTillActive = createCollectionWaitTimeTillActive; this.createCollectionCheckLeaderActive = createCollectionCheckLeaderActive; + this.nodeName = nodeName; if (this.hostPort == -1) throw new SolrException(SolrException.ErrorCode.SERVER_ERROR, "'hostPort' must be configured to run SolrCloud"); @@ -135,6 +138,10 @@ public int getCreateCollectionWaitTimeTillActive() { public boolean isCreateCollectionCheckLeaderActive() { return createCollectionCheckLeaderActive; } + + public String getNodeName() { + return nodeName; + } public static class CloudConfigBuilder { @@ -164,6 +171,7 @@ public static class CloudConfigBuilder { private String zkACLProviderClass; private int createCollectionWaitTimeTillActive = DEFAULT_CREATE_COLLECTION_ACTIVE_WAIT; private boolean createCollectionCheckLeaderActive = DEFAULT_CREATE_COLLECTION_CHECK_LEADER_ACTIVE; + private String nodeName = null; public CloudConfigBuilder(String hostName, int hostPort) { this(hostName, hostPort, null); @@ -235,11 +243,16 @@ public CloudConfigBuilder setCreateCollectionCheckLeaderActive(boolean createCol return this; } + public CloudConfigBuilder setNodeName(String nodeName) { + this.nodeName = nodeName; + return this; + } + public CloudConfig build() { return new CloudConfig(zkHost, zkClientTimeout, hostPort, hostName, hostContext, useGenericCoreNames, leaderVoteWait, leaderConflictResolveWait, autoReplicaFailoverWaitAfterExpiration, autoReplicaFailoverWorkLoopDelay, autoReplicaFailoverBadNodeExpiration, zkCredentialsProviderClass, zkACLProviderClass, createCollectionWaitTimeTillActive, - createCollectionCheckLeaderActive); + createCollectionCheckLeaderActive, nodeName); } } } 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 a020b00ff6fd..2a9fff422ecf 100644 --- a/solr/core/src/java/org/apache/solr/core/CoreContainer.java +++ b/solr/core/src/java/org/apache/solr/core/CoreContainer.java @@ -1237,6 +1237,10 @@ public ZkController getZkController() { return zkSys.getZkController(); } + public ZkStateReader getZkStateReader() { + return isZooKeeperAware() ? zkSys.getZkController().getZkStateReader() : null; + } + public NodeConfig getConfig() { return cfg; } diff --git a/solr/core/src/java/org/apache/solr/core/SolrXmlConfig.java b/solr/core/src/java/org/apache/solr/core/SolrXmlConfig.java index 65b248d62595..6d58567705a0 100644 --- a/solr/core/src/java/org/apache/solr/core/SolrXmlConfig.java +++ b/solr/core/src/java/org/apache/solr/core/SolrXmlConfig.java @@ -364,6 +364,9 @@ private static CloudConfig fillSolrCloudSection(NamedList nl) { case "genericCoreNodeNames": builder.setUseGenericCoreNames(Boolean.parseBoolean(value)); break; + case "nodeName": + builder.setNodeName(value); + break; case "zkACLProvider": builder.setZkACLProviderClass(value); break; diff --git a/solr/core/src/test-files/solr/solr.xml b/solr/core/src/test-files/solr/solr.xml index f381475ab1a5..c94638c6ae6f 100644 --- a/solr/core/src/test-files/solr/solr.xml +++ b/solr/core/src/test-files/solr/solr.xml @@ -37,6 +37,7 @@ ${hostContext:solr} ${solr.zkclienttimeout:30000} ${genericCoreNodeNames:true} + ${solr.nodeName:} ${leaderVoteWait:10000} ${distribUpdateConnTimeout:45000} ${distribUpdateSoTimeout:340000} diff --git a/solr/core/src/test/org/apache/solr/cloud/HttpPartitionTest.java b/solr/core/src/test/org/apache/solr/cloud/HttpPartitionTest.java index 82fbec0c7140..ef371518ad56 100644 --- a/solr/core/src/test/org/apache/solr/cloud/HttpPartitionTest.java +++ b/solr/core/src/test/org/apache/solr/cloud/HttpPartitionTest.java @@ -635,14 +635,6 @@ private NamedList realTimeGetDocId(HttpSolrClient solr, String docId) throws Sol return solr.request(qr); } - protected int getReplicaPort(Replica replica) { - String replicaNode = replica.getNodeName(); - String tmp = replicaNode.substring(replicaNode.indexOf(':')+1); - if (tmp.indexOf('_') != -1) - tmp = tmp.substring(0,tmp.indexOf('_')); - return Integer.parseInt(tmp); - } - protected void waitToSeeReplicasActive(String testCollectionName, String shardId, Set replicasToCheck, int maxWaitSecs) throws Exception { final RTimer timer = new RTimer(); diff --git a/solr/core/src/test/org/apache/solr/cloud/RollingRestartTest.java b/solr/core/src/test/org/apache/solr/cloud/RollingRestartTest.java index 6a906bbc0199..d6254b308e87 100644 --- a/solr/core/src/test/org/apache/solr/cloud/RollingRestartTest.java +++ b/solr/core/src/test/org/apache/solr/cloud/RollingRestartTest.java @@ -66,6 +66,7 @@ public void restartWithRolesTest() throws Exception { numDesignateOverseers = Math.max(getShardCount(), numDesignateOverseers); List designates = new ArrayList<>(); List designateJettys = new ArrayList<>(); + for (int i = 0; i < numDesignateOverseers; i++) { int n = random().nextInt(getShardCount()); String nodeName = cloudJettys.get(n).nodeName; diff --git a/solr/core/src/test/org/apache/solr/cloud/ZkControllerTest.java b/solr/core/src/test/org/apache/solr/cloud/ZkControllerTest.java index d92577475846..422d7a3e406a 100644 --- a/solr/core/src/test/org/apache/solr/cloud/ZkControllerTest.java +++ b/solr/core/src/test/org/apache/solr/cloud/ZkControllerTest.java @@ -97,41 +97,41 @@ public void testNodeNameUrlConversion() throws Exception { // getBaseUrlForNodeName assertEquals("http://zzz.xxx:1234/solr", - zkStateReader.getBaseUrlForNodeName("zzz.xxx:1234_solr")); + zkStateReader.getBaseUrlFromGenericNodeName("zzz.xxx:1234_solr")); assertEquals("http://xxx:99", - zkStateReader.getBaseUrlForNodeName("xxx:99_")); + zkStateReader.getBaseUrlFromGenericNodeName("xxx:99_")); assertEquals("http://foo-bar.baz.org:9999/some_dir", - zkStateReader.getBaseUrlForNodeName("foo-bar.baz.org:9999_some_dir")); + zkStateReader.getBaseUrlFromGenericNodeName("foo-bar.baz.org:9999_some_dir")); assertEquals("http://foo-bar.baz.org:9999/solr/sub_dir", - zkStateReader.getBaseUrlForNodeName("foo-bar.baz.org:9999_solr%2Fsub_dir")); + zkStateReader.getBaseUrlFromGenericNodeName("foo-bar.baz.org:9999_solr%2Fsub_dir")); // generateNodeName + getBaseUrlForNodeName assertEquals("http://foo:9876/solr", - zkStateReader.getBaseUrlForNodeName + zkStateReader.getBaseUrlFromGenericNodeName (ZkController.generateNodeName("foo", "9876", "solr"))); assertEquals("http://foo:9876/solr", - zkStateReader.getBaseUrlForNodeName + zkStateReader.getBaseUrlFromGenericNodeName (ZkController.generateNodeName("foo", "9876", "/solr"))); assertEquals("http://foo:9876/solr", - zkStateReader.getBaseUrlForNodeName + zkStateReader.getBaseUrlFromGenericNodeName (ZkController.generateNodeName("foo", "9876", "/solr/"))); assertEquals("http://foo.bar.com:9876/solr/sub_dir", - zkStateReader.getBaseUrlForNodeName + zkStateReader.getBaseUrlFromGenericNodeName (ZkController.generateNodeName("foo.bar.com", "9876", "solr/sub_dir"))); assertEquals("http://foo.bar.com:9876/solr/sub_dir", - zkStateReader.getBaseUrlForNodeName + zkStateReader.getBaseUrlFromGenericNodeName (ZkController.generateNodeName("foo.bar.com", "9876", "/solr/sub_dir/"))); assertEquals("http://foo-bar:9876", - zkStateReader.getBaseUrlForNodeName + zkStateReader.getBaseUrlFromGenericNodeName (ZkController.generateNodeName("foo-bar", "9876", ""))); assertEquals("http://foo-bar:9876", - zkStateReader.getBaseUrlForNodeName + zkStateReader.getBaseUrlFromGenericNodeName (ZkController.generateNodeName("foo-bar", "9876", "/"))); assertEquals("http://foo-bar.com:80/some_dir", - zkStateReader.getBaseUrlForNodeName + zkStateReader.getBaseUrlFromGenericNodeName (ZkController.generateNodeName("foo-bar.com", "80", "some_dir"))); assertEquals("http://foo-bar.com:80/some_dir", - zkStateReader.getBaseUrlForNodeName + zkStateReader.getBaseUrlFromGenericNodeName (ZkController.generateNodeName("foo-bar.com", "80", "/some_dir"))); } @@ -146,10 +146,10 @@ public void testNodeNameUrlConversion() throws Exception { zkStateReader.createClusterStateWatchersAndUpdate(); assertEquals("https://zzz.xxx:1234/solr", - zkStateReader.getBaseUrlForNodeName("zzz.xxx:1234_solr")); + zkStateReader.getBaseUrlFromGenericNodeName("zzz.xxx:1234_solr")); assertEquals("https://foo-bar.com:80/some_dir", - zkStateReader.getBaseUrlForNodeName + zkStateReader.getBaseUrlFromGenericNodeName (ZkController.generateNodeName("foo-bar.com", "80", "/some_dir"))); } diff --git a/solr/solrj/src/java/org/apache/solr/common/cloud/ZkStateReader.java b/solr/solrj/src/java/org/apache/solr/common/cloud/ZkStateReader.java index a858f340f6b5..b5b8d374c5e5 100644 --- a/solr/solrj/src/java/org/apache/solr/common/cloud/ZkStateReader.java +++ b/solr/solrj/src/java/org/apache/solr/common/cloud/ZkStateReader.java @@ -23,6 +23,7 @@ import java.util.ArrayList; import java.util.Collection; import java.util.Collections; +import java.util.HashMap; import java.util.HashSet; import java.util.LinkedHashMap; import java.util.List; @@ -30,7 +31,7 @@ import java.util.Map.Entry; import java.util.Objects; import java.util.Set; -import java.util.TreeSet; +import java.util.TreeMap; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutorService; @@ -130,7 +131,8 @@ public class ZkStateReader implements Closeable { /** Collections with format2 state.json, not "interesting" and not actively watched. */ private final ConcurrentHashMap lazyCollectionStates = new ConcurrentHashMap<>(); - private volatile Set liveNodes = emptySet(); + /** visibility relaxed for testing **/ + protected volatile Map liveNodes = emptyMap(); private volatile Map clusterProperties = Collections.emptyMap(); @@ -483,7 +485,7 @@ public void process(WatchedEvent event) { */ private void constructState(Set changedCollections) { - Set liveNodes = this.liveNodes; // volatile read + Set liveNodes = this.liveNodes.keySet(); // volatile read // Legacy clusterstate is authoritative, for backwards compatibility. // To move a collection's state to format2, first create the new state2 format node, then remove legacy entry. @@ -651,25 +653,35 @@ public String toString() { // We don't get a Stat or track versions on getChildren() calls, so force linearization. private final Object refreshLiveNodesLock = new Object(); // Ensures that only the latest getChildren fetch gets applied. - private final AtomicReference> lastFetchedLiveNodes = new AtomicReference<>(); + private final AtomicReference> lastFetchedLiveNodes = new AtomicReference<>(); /** * Refresh live_nodes. */ private void refreshLiveNodes(Watcher watcher) throws KeeperException, InterruptedException { synchronized (refreshLiveNodesLock) { - Set newLiveNodes; + Map newLiveNodes; try { List nodeList = zkClient.getChildren(LIVE_NODES_ZKNODE, watcher, true); - newLiveNodes = new HashSet<>(nodeList); + newLiveNodes = new HashMap(); + for(String c: nodeList) { + byte[] ndb = zkClient.getData(LIVE_NODES_ZKNODE + "/" + c , null, null, false); + String nodeData; + if(null == ndb || ndb.length == 0) { + nodeData = c; + } else { + nodeData = new String(ndb); + } + newLiveNodes.put(c, nodeData); + } } catch (KeeperException.NoNodeException e) { - newLiveNodes = emptySet(); + newLiveNodes = emptyMap(); } lastFetchedLiveNodes.set(newLiveNodes); } // Can't lock getUpdateLock() until we release the other, it would cause deadlock. - Set oldLiveNodes, newLiveNodes; + Map oldLiveNodes, newLiveNodes; synchronized (getUpdateLock()) { newLiveNodes = lastFetchedLiveNodes.getAndSet(null); if (newLiveNodes == null) { @@ -680,14 +692,14 @@ private void refreshLiveNodes(Watcher watcher) throws KeeperException, Interrupt oldLiveNodes = this.liveNodes; this.liveNodes = newLiveNodes; if (clusterState != null) { - clusterState.setLiveNodes(newLiveNodes); + clusterState.setLiveNodes(newLiveNodes.keySet()); } } if (oldLiveNodes.size() != newLiveNodes.size()) { LOG.info("Updated live nodes from ZooKeeper... ({}) -> ({})", oldLiveNodes.size(), newLiveNodes.size()); } if (LOG.isDebugEnabled()) { - LOG.debug("Updated live nodes from ZooKeeper... {} -> {}", new TreeSet<>(oldLiveNodes), new TreeSet<>(newLiveNodes)); + LOG.debug("Updated live nodes from ZooKeeper... {} -> {}", new TreeMap<>(oldLiveNodes), new TreeMap<>(newLiveNodes)); } } @@ -916,20 +928,43 @@ public ConfigData getSecurityProps(boolean getFresh) { return null; } + /** + * Returns the baseURL corresponding to a given node's nodeName -- + * NOTE: THIS NOW REQUIRES THAT THE nodeName EXISTS in liveNodes in the cluster. + * @lucene.experimental + */ + public String getBaseUrlForNodeName(final String nodeName) { + final String genericNodeName = this.liveNodes.get(nodeName); //volatile read + + if(null == genericNodeName) { + //TODO how to handle this? + //In here means that someone might be using this method to convert + //:_ url to a base url as this method used to do + // + //should we fallback to original behavior or throw an exception? + //when parsing the liveNodes map the key will still be + //genericNodeName -> genericNodeName if no data value is found in liveNodes + //return getBaseUrlFromGenericNodeName(nodeName); + throw new IllegalArgumentException(String.format("nodeName: '%s' is not one of %s", nodeName, this.liveNodes.keySet())); + } + + return getBaseUrlFromGenericNodeName(genericNodeName); + } + /** * Returns the baseURL corresponding to a given node's nodeName -- * NOTE: does not (currently) imply that the nodeName (or resulting * baseURL) exists in the cluster. * @lucene.experimental */ - public String getBaseUrlForNodeName(final String nodeName) { - final int _offset = nodeName.indexOf("_"); + public String getBaseUrlFromGenericNodeName(final String genericNodeName) { + final int _offset = genericNodeName.indexOf("_"); if (_offset < 0) { - throw new IllegalArgumentException("nodeName does not contain expected '_' seperator: " + nodeName); + throw new IllegalArgumentException("nodeName does not contain expected '_' seperator: " + genericNodeName); } - final String hostAndPort = nodeName.substring(0,_offset); + final String hostAndPort = genericNodeName.substring(0,_offset); try { - final String path = URLDecoder.decode(nodeName.substring(1+_offset), "UTF-8"); + final String path = URLDecoder.decode(genericNodeName.substring(1+_offset), "UTF-8"); String urlScheme = getClusterProperty(URL_SCHEME, "http"); return urlScheme + "://" + hostAndPort + (path.isEmpty() ? "" : ("/" + path)); } catch (UnsupportedEncodingException e) { @@ -958,7 +993,7 @@ public void process(WatchedEvent event) { return; } - Set liveNodes = ZkStateReader.this.liveNodes; + Set liveNodes = ZkStateReader.this.liveNodes.keySet(); LOG.info("A cluster state change: [{}] for collection [{}] has occurred - updating... (live nodes size: [{}])", event, coll, liveNodes.size()); @@ -1210,7 +1245,7 @@ public void registerCollectionStateWatcher(String collection, CollectionStateWat } DocCollection state = clusterState.getCollectionOrNull(collection); - if (stateWatcher.onStateChanged(liveNodes, state) == true) { + if (stateWatcher.onStateChanged(liveNodes.keySet(), state) == true) { removeCollectionStateWatcher(collection, stateWatcher); } } @@ -1286,7 +1321,6 @@ Set getStateWatchers(String collection) { // returns true if the state has changed private boolean updateWatchedCollection(String coll, DocCollection newState) { - if (newState == null) { LOG.debug("Removing cached collection state for [{}]", coll); watchedCollectionStates.remove(coll); diff --git a/solr/test-framework/src/java/org/apache/solr/cloud/AbstractFullDistribZkTestBase.java b/solr/test-framework/src/java/org/apache/solr/cloud/AbstractFullDistribZkTestBase.java index 4b0f7abbe73c..ad25f3fef29d 100644 --- a/solr/test-framework/src/java/org/apache/solr/cloud/AbstractFullDistribZkTestBase.java +++ b/solr/test-framework/src/java/org/apache/solr/cloud/AbstractFullDistribZkTestBase.java @@ -19,6 +19,7 @@ import java.io.File; import java.io.IOException; import java.lang.invoke.MethodHandles; +import java.net.MalformedURLException; import java.net.ServerSocket; import java.net.URI; import java.net.URL; @@ -369,6 +370,8 @@ protected String getStateFormat() { } return defaultStateFormat; // random } + + protected boolean randomNameNodes = true; protected List createJettys(int numJettys) throws Exception { List jettys = new ArrayList<>(); @@ -394,6 +397,11 @@ protected List createJettys(int numJettys) throws Exception { File jettyDir = createTempDir("shard-" + i).toFile(); jettyDir.mkdirs(); + + if(randomNameNodes && random().nextBoolean()) { + System.setProperty("solr.nodeName", "node"+cnt); + } + setupJettySolrHome(jettyDir); log.info("create jetty {} in directory {}", i, jettyDir); JettySolrRunner j = createJetty(jettyDir, useJettyDataDir ? getDataDir(testDir + "/jetty" @@ -401,6 +409,8 @@ protected List createJettys(int numJettys) throws Exception { jettys.add(j); SolrClient client = createNewSolrClient(j.getLocalPort()); clients.add(client); + + System.clearProperty("solr.nodeName"); } this.jettys.addAll(jettys); @@ -506,6 +516,10 @@ public JettySolrRunner createJetty(File solrHome, String dataDir, String shardLi props.setProperty("solr.data.dir", getDataDir(dataDir)); props.setProperty("coreRootDirectory", solrHome.toPath().resolve("cores").toAbsolutePath().toString()); + if(null != System.getProperty("solr.nodeName")){ + props.setProperty("solr.nodeName", System.getProperty("solr.nodeName")); + } + JettySolrRunner jetty = new JettySolrRunner(solrHome.getPath(), props, jettyconfig); jetty.start(); @@ -550,12 +564,9 @@ public JettySolrRunner createProxiedJetty(File solrHome, String dataDir, return jetty; } - protected int getReplicaPort(Replica replica) { - String replicaNode = replica.getNodeName(); - String tmp = replicaNode.substring(replicaNode.indexOf(':')+1); - if (tmp.indexOf('_') != -1) - tmp = tmp.substring(0,tmp.indexOf('_')); - return Integer.parseInt(tmp); + protected int getReplicaPort(Replica replica) throws MalformedURLException { + URL replicaNode = new URL(replica.getCoreUrl()); + return replicaNode.getPort(); } protected JettySolrRunner getJettyOnPort(int port) { diff --git a/solr/test-framework/src/java/org/apache/solr/cloud/MockZkStateReader.java b/solr/test-framework/src/java/org/apache/solr/cloud/MockZkStateReader.java index b0ba518f2bf7..dbfe02ad9cfb 100644 --- a/solr/test-framework/src/java/org/apache/solr/cloud/MockZkStateReader.java +++ b/solr/test-framework/src/java/org/apache/solr/cloud/MockZkStateReader.java @@ -16,6 +16,8 @@ */ package org.apache.solr.cloud; +import java.util.HashMap; +import java.util.Map; import java.util.Set; import org.apache.solr.common.cloud.ClusterState; @@ -27,9 +29,22 @@ public class MockZkStateReader extends ZkStateReader { private Set collections; public MockZkStateReader(ClusterState clusterState, Set collections) { + this(clusterState, collections, null); + } + + public MockZkStateReader(ClusterState clusterState, Set collections, Map liveNodes) { super(new MockSolrZkClient()); this.clusterState = clusterState; this.collections = collections; + + if(liveNodes == null && clusterState != null) { + liveNodes = new HashMap(); + for(String n: clusterState.getLiveNodes()) { + liveNodes.put(n, n); + } + } + + this.liveNodes = liveNodes; } public Set getAllCollections(){