diff --git a/solr/CHANGES.txt b/solr/CHANGES.txt index 9b94c44a917..60162707857 100644 --- a/solr/CHANGES.txt +++ b/solr/CHANGES.txt @@ -505,6 +505,8 @@ Bug Fixes to take advantage of it's "Workload Identity" and other role-based access feature. (Jacek Kikiewicz, Martin Stocker via Jason Gerlowski) +* SOLR-15919: Replace File with Path for many ZK operations (Mike Drob) + ================== 8.11.2 ================== Bug Fixes diff --git a/solr/core/build.gradle b/solr/core/build.gradle index a40b83df4fb..2ff7ebab592 100644 --- a/solr/core/build.gradle +++ b/solr/core/build.gradle @@ -83,6 +83,7 @@ dependencies { // ZooKeeper & Curator implementation 'org.apache.zookeeper:zookeeper' + testImplementation 'org.apache.zookeeper:zookeeper:3.7.0:tests' // required for instantiating a Zookeeper server (for embedding ZK or running tests) runtimeOnly ('org.xerial.snappy:snappy-java') implementation ('org.apache.curator:curator-client') 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 05635692b7b..0922ac456fa 100644 --- a/solr/core/src/java/org/apache/solr/cloud/Overseer.java +++ b/solr/core/src/java/org/apache/solr/cloud/Overseer.java @@ -51,7 +51,6 @@ import org.apache.solr.common.SolrCloseable; import org.apache.solr.common.SolrException; import org.apache.solr.common.cloud.ClusterState; -import org.apache.solr.common.cloud.ConnectionManager; import org.apache.solr.common.cloud.DocCollection; import org.apache.solr.common.cloud.Slice; import org.apache.solr.common.cloud.SolrZkClient; @@ -905,11 +904,8 @@ ZkDistributedQueue getOverseerQuitNotificationQueue() { * @return a {@link ZkDistributedQueue} object */ ZkDistributedQueue getStateUpdateQueue(Stats zkStats) { - return new ZkDistributedQueue(reader.getZkClient(), "/overseer/queue", zkStats, STATE_UPDATE_MAX_QUEUE, new ConnectionManager.IsClosed(){ - public boolean isClosed() { - return Overseer.this.isClosed() || zkController.getCoreContainer().isShutDown(); - } - }); + return new ZkDistributedQueue(reader.getZkClient(), "/overseer/queue", zkStats, STATE_UPDATE_MAX_QUEUE, () -> + Overseer.this.isClosed() || zkController.getCoreContainer().isShutDown()); } /** 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 723a49fedc1..4f980444e95 100644 --- a/solr/core/src/java/org/apache/solr/cloud/ZkController.java +++ b/solr/core/src/java/org/apache/solr/cloud/ZkController.java @@ -448,12 +448,7 @@ public void command() { closeOutstandingElections(descriptorsSupplier); markAllAsNotLeader(descriptorsSupplier); } - }, zkACLProvider, new ConnectionManager.IsClosed() { - - @Override - public boolean isClosed() { - return cc.isShutDown(); - }}); + }, zkACLProvider, cc::isShutDown); // Refuse to start if ZK has a non empty /clusterstate.json checkNoOldClusterstate(zkClient); 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 b915330427a..59c00932c4b 100644 --- a/solr/core/src/java/org/apache/solr/core/CoreContainer.java +++ b/solr/core/src/java/org/apache/solr/core/CoreContainer.java @@ -1752,7 +1752,7 @@ public void reload(String name, UUID coreId) { if (docCollection != null) { Replica replica = docCollection.getReplica(cd.getCloudDescriptor().getCoreNodeName()); - assert replica != null; + assert replica != null : cd.getCloudDescriptor().getCoreNodeName() + " had no replica"; if (replica.getType() == Replica.Type.TLOG) { // TODO: needed here? getZkController().stopReplicationFromLeader(core.getName()); if (!cd.getCloudDescriptor().isLeader()) { diff --git a/solr/core/src/test-files/log4j2.xml b/solr/core/src/test-files/log4j2.xml index 0e8f08c0c61..aa4cfe9afbb 100644 --- a/solr/core/src/test-files/log4j2.xml +++ b/solr/core/src/test-files/log4j2.xml @@ -30,6 +30,7 @@ + diff --git a/solr/core/src/test/org/apache/solr/client/solrj/embedded/TestEmbeddedSolrServerConstructors.java b/solr/core/src/test/org/apache/solr/client/solrj/embedded/TestEmbeddedSolrServerConstructors.java index 912a35c802e..20aaa797e70 100644 --- a/solr/core/src/test/org/apache/solr/client/solrj/embedded/TestEmbeddedSolrServerConstructors.java +++ b/solr/core/src/test/org/apache/solr/client/solrj/embedded/TestEmbeddedSolrServerConstructors.java @@ -18,7 +18,6 @@ import java.io.IOException; import java.nio.file.Path; -import java.nio.file.Paths; import org.apache.solr.SolrTestCaseJ4; import org.apache.solr.client.solrj.SolrQuery; @@ -32,8 +31,7 @@ public class TestEmbeddedSolrServerConstructors extends SolrTestCaseJ4 { @Test @SuppressWarnings({"try"}) public void testPathConstructor() throws IOException { - Path path = Paths.get(TEST_HOME()); - try (EmbeddedSolrServer server = new EmbeddedSolrServer(path, "collection1")) { + try (EmbeddedSolrServer server = new EmbeddedSolrServer(TEST_PATH(), "collection1")) { } } @@ -43,7 +41,7 @@ public void testNodeConfigConstructor() throws Exception { Path path = createTempDir(); NodeConfig config = new NodeConfig.NodeConfigBuilder("testnode", path) - .setConfigSetBaseDirectory(Paths.get(TEST_HOME()).resolve("configsets").toString()) + .setConfigSetBaseDirectory(TEST_PATH().resolve("configsets").toString()) .build(); try (EmbeddedSolrServer server = new EmbeddedSolrServer(config, "newcore")) { diff --git a/solr/core/src/test/org/apache/solr/client/solrj/embedded/TestJettySolrRunner.java b/solr/core/src/test/org/apache/solr/client/solrj/embedded/TestJettySolrRunner.java index ae8312e5f18..ead3b0926e5 100644 --- a/solr/core/src/test/org/apache/solr/client/solrj/embedded/TestJettySolrRunner.java +++ b/solr/core/src/test/org/apache/solr/client/solrj/embedded/TestJettySolrRunner.java @@ -28,7 +28,6 @@ import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; -import java.nio.file.Paths; import java.util.Properties; public class TestJettySolrRunner extends SolrTestCaseJ4 { @@ -42,7 +41,7 @@ public void testPassSolrHomeToRunner() throws Exception { Path solrHome = createTempDir(); Path coresDir = createTempDir("crazy_path_to_cores"); - Path configsets = Paths.get(TEST_HOME()).resolve("configsets"); + Path configsets = TEST_PATH().resolve("configsets"); String solrxml = "CONFIGSETSCOREROOT" diff --git a/solr/core/src/test/org/apache/solr/cloud/ConnectionManagerTest.java b/solr/core/src/test/org/apache/solr/cloud/ConnectionManagerTest.java index 76f0c54e8f0..cfc88f6db4e 100644 --- a/solr/core/src/test/org/apache/solr/cloud/ConnectionManagerTest.java +++ b/solr/core/src/test/org/apache/solr/cloud/ConnectionManagerTest.java @@ -25,13 +25,14 @@ import org.apache.lucene.util.LuceneTestCase.Slow; import org.apache.solr.SolrTestCaseJ4; import org.apache.solr.common.cloud.ConnectionManager; -import org.apache.solr.common.cloud.DefaultConnectionStrategy; import org.apache.solr.common.cloud.SolrZkClient; import org.apache.solr.common.util.SolrNamedThreadFactory; +import org.apache.zookeeper.TestableZooKeeper; import org.apache.zookeeper.WatchedEvent; import org.apache.zookeeper.Watcher; import org.apache.zookeeper.Watcher.Event.EventType; import org.apache.zookeeper.Watcher.Event.KeeperState; +import org.apache.zookeeper.ZooKeeper; import org.junit.Ignore; import org.junit.Test; @@ -54,12 +55,11 @@ public void testConnectionManager() throws Exception { try { assertFalse(cm.isLikelyExpired()); - zkClient.getSolrZooKeeper().closeCnxn(); - - long sessionId = zkClient.getSolrZooKeeper().getSessionId(); - server.expire(sessionId); - Thread.sleep(TIMEOUT); - + ZooKeeper zk = zkClient.getZooKeeper(); + assertTrue(zk instanceof TestableZooKeeper); + ((TestableZooKeeper) zk).testableConnloss(); + zk.getTestable().injectSessionExpiration(); + assertTrue(cm.isLikelyExpired()); } finally { cm.close(); @@ -122,7 +122,7 @@ public void testReconnectWhenZkDisappeared() throws Exception { server.run(); MockZkClientConnectionStrategy strat = new MockZkClientConnectionStrategy(); - SolrZkClient zkClient = new SolrZkClient(server.getZkAddress(), TIMEOUT, strat , null); + SolrZkClient zkClient = new SolrZkClient(server.getZkAddress(), TIMEOUT, strat, null); ConnectionManager cm = zkClient.getConnectionManager(); try { @@ -144,7 +144,7 @@ public void testReconnectWhenZkDisappeared() throws Exception { } } - private static class MockZkClientConnectionStrategy extends DefaultConnectionStrategy { + private static class MockZkClientConnectionStrategy extends TestConnectionStrategy { int called = 0; boolean exceptionThrown = false; diff --git a/solr/core/src/test/org/apache/solr/cloud/DistribJoinFromCollectionTest.java b/solr/core/src/test/org/apache/solr/cloud/DistribJoinFromCollectionTest.java index 805e013b8e2..4dccffdacd7 100644 --- a/solr/core/src/test/org/apache/solr/cloud/DistribJoinFromCollectionTest.java +++ b/solr/core/src/test/org/apache/solr/cloud/DistribJoinFromCollectionTest.java @@ -19,7 +19,6 @@ import java.io.IOException; import java.lang.invoke.MethodHandles; import java.nio.file.Path; -import java.nio.file.Paths; import java.util.HashMap; import java.util.HashSet; import java.util.Map; @@ -65,7 +64,7 @@ public class DistribJoinFromCollectionTest extends SolrCloudTestCase{ @BeforeClass public static void setupCluster() throws Exception { - final Path configDir = Paths.get(TEST_HOME(), "collection1", "conf"); + final Path configDir = TEST_COLL1_CONF(); String configName = "solrCloudCollectionConfig"; int nodeCount = 5; diff --git a/solr/core/src/test/org/apache/solr/cloud/DistributedQueueTest.java b/solr/core/src/test/org/apache/solr/cloud/DistributedQueueTest.java index 7929ed674c4..38917971090 100644 --- a/solr/core/src/test/org/apache/solr/cloud/DistributedQueueTest.java +++ b/solr/core/src/test/org/apache/solr/cloud/DistributedQueueTest.java @@ -280,7 +280,7 @@ public void testPeekElements() throws Exception { private void forceSessionExpire() throws InterruptedException, TimeoutException { long sessionId = zkClient.getSolrZooKeeper().getSessionId(); - zkServer.expire(sessionId); + zkClient.getZooKeeper().getTestable().injectSessionExpiration(); zkClient.getConnectionManager().waitForDisconnected(10000); zkClient.getConnectionManager().waitForConnected(10000); for (int i = 0; i < 100; ++i) { diff --git a/solr/core/src/test/org/apache/solr/cloud/LeaderElectionIntegrationTest.java b/solr/core/src/test/org/apache/solr/cloud/LeaderElectionIntegrationTest.java index 35ffa6951ea..bf182e28258 100644 --- a/solr/core/src/test/org/apache/solr/cloud/LeaderElectionIntegrationTest.java +++ b/solr/core/src/test/org/apache/solr/cloud/LeaderElectionIntegrationTest.java @@ -98,8 +98,8 @@ public void testSimpleSliceLeaderElection() throws Exception { JettySolrRunner jetty = getRunner(leader); ZkController zkController = jetty.getCoreContainer().getZkController(); - zkController.getZkClient().getSolrZooKeeper().closeCnxn(); - cluster.getZkServer().expire(zkController.getZkClient().getSolrZooKeeper().getSessionId()); + ChaosMonkey.causeConnectionLoss(zkController.getZkClient().getZooKeeper()); + zkController.getZkClient().getZooKeeper().getTestable().injectSessionExpiration(); for (int i = 0; i < 60; i++) { // wait till leader is changed if (jetty != getRunner(getLeader(collection))) { diff --git a/solr/core/src/test/org/apache/solr/cloud/LeaderElectionTest.java b/solr/core/src/test/org/apache/solr/cloud/LeaderElectionTest.java index 294f7c2a218..e38390c3004 100644 --- a/solr/core/src/test/org/apache/solr/cloud/LeaderElectionTest.java +++ b/solr/core/src/test/org/apache/solr/cloud/LeaderElectionTest.java @@ -40,6 +40,8 @@ import org.apache.zookeeper.KeeperException; import org.apache.zookeeper.KeeperException.NoNodeException; import org.apache.zookeeper.KeeperException.SessionExpiredException; +import org.apache.zookeeper.TestableZooKeeper; +import org.apache.zookeeper.ZooKeeper; import org.junit.AfterClass; import org.junit.BeforeClass; import org.junit.Test; @@ -493,20 +495,17 @@ public void run() { } }; - Thread connLossThread = new Thread() { - @Override - public void run() { - + Thread connLossThread = new Thread(() -> { while (!stopStress) { try { Thread.sleep(50); int j; j = random().nextInt(threads.size()); try { - threads.get(j).es.zkClient.getSolrZooKeeper().closeCnxn(); + ZooKeeper zk = threads.get(j).es.zkClient.getZooKeeper(); + ((TestableZooKeeper) zk).testableConnloss(); if (random().nextBoolean()) { - long sessionId = zkClient.getSolrZooKeeper().getSessionId(); - server.expire(sessionId); + zk.getTestable().injectSessionExpiration(); } } catch (Exception e) { e.printStackTrace(); @@ -517,8 +516,7 @@ public void run() { } } - } - }; + }); scheduleThread.start(); connLossThread.start(); diff --git a/solr/core/src/test/org/apache/solr/cloud/NestedShardedAtomicUpdateTest.java b/solr/core/src/test/org/apache/solr/cloud/NestedShardedAtomicUpdateTest.java index 464fcdc4682..7e2ed1b7275 100644 --- a/solr/core/src/test/org/apache/solr/cloud/NestedShardedAtomicUpdateTest.java +++ b/solr/core/src/test/org/apache/solr/cloud/NestedShardedAtomicUpdateTest.java @@ -19,7 +19,6 @@ import java.io.IOException; import java.nio.file.Path; -import java.nio.file.Paths; import java.util.ArrayList; import java.util.List; @@ -52,8 +51,8 @@ public static void beforeClass() throws Exception { .addConfig("_default", configset("cloud-minimal")) .configure(); // replace schema.xml with schema-test.xml - Path schemaPath = Paths.get(TEST_HOME()).resolve("collection1").resolve("conf").resolve("schema-nest.xml"); - cluster.getZkClient().setData("/configs/_default/schema.xml", schemaPath.toFile(),true); + Path schemaPath = TEST_COLL1_CONF().resolve("schema-nest.xml"); + cluster.getZkClient().setData("/configs/_default/schema.xml", schemaPath, true); cloudClient = cluster.getSolrClient(); cloudClient.setDefaultCollection(DEFAULT_COLLECTION); diff --git a/solr/core/src/test/org/apache/solr/cloud/SaslZkACLProviderTest.java b/solr/core/src/test/org/apache/solr/cloud/SaslZkACLProviderTest.java index c8a7fdaf6d2..64617a92bdf 100644 --- a/solr/core/src/test/org/apache/solr/cloud/SaslZkACLProviderTest.java +++ b/solr/core/src/test/org/apache/solr/cloud/SaslZkACLProviderTest.java @@ -87,7 +87,7 @@ public void setUp() throws Exception { System.setProperty("zkHost", zkServer.getZkAddress()); try (SolrZkClient zkClient = new SolrZkClientWithACLs(zkServer.getZkHost(), AbstractZkTestCase.TIMEOUT)) { - ZooKeeperSaslClient saslClient = zkClient.getSolrZooKeeper().getConnection().zooKeeperSaslClient; + ZooKeeperSaslClient saslClient = zkClient.getZooKeeper().getSaslClient(); assumeFalse("Could not set up ZK with SASL", saslClient.isFailed()); zkClient.makePath("/solr", false, true); } catch (KeeperException e) { diff --git a/solr/core/src/test/org/apache/solr/cloud/TestCloudDeleteByQuery.java b/solr/core/src/test/org/apache/solr/cloud/TestCloudDeleteByQuery.java index e895fe31de2..7db38db4737 100644 --- a/solr/core/src/test/org/apache/solr/cloud/TestCloudDeleteByQuery.java +++ b/solr/core/src/test/org/apache/solr/cloud/TestCloudDeleteByQuery.java @@ -19,7 +19,6 @@ import java.lang.invoke.MethodHandles; import java.net.URL; import java.nio.file.Path; -import java.nio.file.Paths; import java.util.Arrays; import java.util.HashMap; import java.util.Map; @@ -113,7 +112,7 @@ private static void afterClass() throws Exception { private static void createMiniSolrCloudCluster() throws Exception { final String configName = "solrCloudCollectionConfig"; - final Path configDir = Paths.get(TEST_HOME(), "collection1", "conf"); + final Path configDir = TEST_COLL1_CONF(); configureCluster(NUM_SERVERS) .addConfig(configName, configDir) diff --git a/solr/core/src/test/org/apache/solr/cloud/TestCloudPhrasesIdentificationComponent.java b/solr/core/src/test/org/apache/solr/cloud/TestCloudPhrasesIdentificationComponent.java index ff2af57a328..7170da849fe 100644 --- a/solr/core/src/test/org/apache/solr/cloud/TestCloudPhrasesIdentificationComponent.java +++ b/solr/core/src/test/org/apache/solr/cloud/TestCloudPhrasesIdentificationComponent.java @@ -18,7 +18,6 @@ import java.lang.invoke.MethodHandles; import java.nio.file.Path; -import java.nio.file.Paths; import java.util.Arrays; import java.util.ArrayList; import java.util.LinkedHashMap; @@ -68,8 +67,8 @@ private static void createMiniSolrCloudCluster() throws Exception { final int numNodes = (numShards * repFactor); final String configName = DEBUG_LABEL + "_config-set"; - final Path configDir = Paths.get(TEST_HOME(), "collection1", "conf"); - + final Path configDir = TEST_COLL1_CONF(); + configureCluster(numNodes).addConfig(configName, configDir).configure(); Map collectionProperties = new LinkedHashMap<>(); diff --git a/solr/core/src/test/org/apache/solr/cloud/TestCloudPseudoReturnFields.java b/solr/core/src/test/org/apache/solr/cloud/TestCloudPseudoReturnFields.java index aa1a6e5efc3..23d2f93cdc8 100644 --- a/solr/core/src/test/org/apache/solr/cloud/TestCloudPseudoReturnFields.java +++ b/solr/core/src/test/org/apache/solr/cloud/TestCloudPseudoReturnFields.java @@ -18,7 +18,6 @@ import java.lang.invoke.MethodHandles; import java.nio.file.Path; -import java.nio.file.Paths; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; @@ -70,8 +69,8 @@ private static void createMiniSolrCloudCluster() throws Exception { final int numNodes = 1 + (numShards * repFactor); final String configName = DEBUG_LABEL + "_config-set"; - final Path configDir = Paths.get(TEST_HOME(), "collection1", "conf"); - + final Path configDir = TEST_COLL1_CONF(); + configureCluster(numNodes).addConfig(configName, configDir).configure(); Map collectionProperties = new HashMap<>(); diff --git a/solr/core/src/test/org/apache/solr/cloud/TestLeaderElectionZkExpiry.java b/solr/core/src/test/org/apache/solr/cloud/TestLeaderElectionZkExpiry.java index 83fba71d869..6e5e1716073 100644 --- a/solr/core/src/test/org/apache/solr/cloud/TestLeaderElectionZkExpiry.java +++ b/solr/core/src/test/org/apache/solr/cloud/TestLeaderElectionZkExpiry.java @@ -62,8 +62,7 @@ public void testLeaderElectionWithZkExpiry() throws Exception { public void run() { long timeout = System.nanoTime() + TimeUnit.NANOSECONDS.convert(10, TimeUnit.SECONDS); while (System.nanoTime() < timeout) { - long sessionId = zkController.getZkClient().getSolrZooKeeper().getSessionId(); - server.expire(sessionId); + zkController.getZkClient().getZooKeeper().getTestable().injectSessionExpiration(); try { Thread.sleep(10); } catch (InterruptedException e) { diff --git a/solr/core/src/test/org/apache/solr/cloud/TestRandomFlRTGCloud.java b/solr/core/src/test/org/apache/solr/cloud/TestRandomFlRTGCloud.java index af586d8581c..34b02793b3c 100644 --- a/solr/core/src/test/org/apache/solr/cloud/TestRandomFlRTGCloud.java +++ b/solr/core/src/test/org/apache/solr/cloud/TestRandomFlRTGCloud.java @@ -19,7 +19,6 @@ import java.io.IOException; import java.lang.invoke.MethodHandles; import java.nio.file.Path; -import java.nio.file.Paths; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; @@ -133,7 +132,7 @@ public static void createMiniSolrCloudCluster() throws Exception { final int numNodes = 1 + (singleCoreMode ? 0 : (numShards * repFactor)); final String configName = DEBUG_LABEL + "_config-set"; - final Path configDir = Paths.get(TEST_HOME(), "collection1", "conf"); + final Path configDir = TEST_COLL1_CONF(); configureCluster(numNodes).addConfig(configName, configDir).configure(); diff --git a/solr/core/src/test/org/apache/solr/cloud/TestStressCloudBlindAtomicUpdates.java b/solr/core/src/test/org/apache/solr/cloud/TestStressCloudBlindAtomicUpdates.java index 789136e22d1..4e2a0274c2b 100644 --- a/solr/core/src/test/org/apache/solr/cloud/TestStressCloudBlindAtomicUpdates.java +++ b/solr/core/src/test/org/apache/solr/cloud/TestStressCloudBlindAtomicUpdates.java @@ -19,7 +19,6 @@ import java.lang.invoke.MethodHandles; import java.net.URL; import java.nio.file.Path; -import java.nio.file.Paths; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; @@ -123,8 +122,8 @@ private static void createMiniSolrCloudCluster() throws Exception { final int numNodes = numShards * repFactor; final String configName = DEBUG_LABEL + "_config-set"; - final Path configDir = Paths.get(TEST_HOME(), "collection1", "conf"); - + final Path configDir = TEST_COLL1_CONF(); + configureCluster(numNodes).addConfig(configName, configDir).configure(); CLOUD_CLIENT = cluster.getSolrClient(); diff --git a/solr/core/src/test/org/apache/solr/cloud/ZkSolrClientTest.java b/solr/core/src/test/org/apache/solr/cloud/ZkSolrClientTest.java index 3f86835128c..53efdfe978b 100644 --- a/solr/core/src/test/org/apache/solr/cloud/ZkSolrClientTest.java +++ b/solr/core/src/test/org/apache/solr/cloud/ZkSolrClientTest.java @@ -179,9 +179,8 @@ public void run() { // simulate session expiration // one option - long sessionId = zkClient.getSolrZooKeeper().getSessionId(); - server.expire(sessionId); - + zkClient.getZooKeeper().getTestable().injectSessionExpiration(); + // another option //zkClient.getSolrZooKeeper().getConnection().disconnect(); diff --git a/solr/core/src/test/org/apache/solr/core/TestShardHandlerFactory.java b/solr/core/src/test/org/apache/solr/core/TestShardHandlerFactory.java index 4ca31efbf03..cb18e6a6219 100644 --- a/solr/core/src/test/org/apache/solr/core/TestShardHandlerFactory.java +++ b/solr/core/src/test/org/apache/solr/core/TestShardHandlerFactory.java @@ -17,7 +17,6 @@ package org.apache.solr.core; import java.nio.file.Path; -import java.nio.file.Paths; import org.apache.solr.SolrTestCaseJ4; import org.apache.solr.common.util.NamedList; @@ -29,7 +28,7 @@ public class TestShardHandlerFactory extends SolrTestCaseJ4 { public void testXML() throws Exception { - Path home = Paths.get(TEST_HOME()); + Path home = TEST_PATH(); CoreContainer cc = CoreContainer.createAndLoad(home, home.resolve("solr-shardhandler.xml")); ShardHandlerFactory factory = cc.getShardHandlerFactory(); assertTrue(factory instanceof MockShardHandlerFactory); diff --git a/solr/core/src/test/org/apache/solr/handler/component/TestHttpShardHandlerFactory.java b/solr/core/src/test/org/apache/solr/handler/component/TestHttpShardHandlerFactory.java index db2313dcbbc..822a09f0a44 100644 --- a/solr/core/src/test/org/apache/solr/handler/component/TestHttpShardHandlerFactory.java +++ b/solr/core/src/test/org/apache/solr/handler/component/TestHttpShardHandlerFactory.java @@ -17,7 +17,6 @@ package org.apache.solr.handler.component; import java.nio.file.Path; -import java.nio.file.Paths; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; @@ -65,7 +64,7 @@ public static void afterTests() { } public void testLoadBalancerRequestsMinMax() throws Exception { - final Path home = Paths.get(TEST_HOME()); + final Path home = TEST_PATH(); CoreContainer cc = null; ShardHandlerFactory factory = null; try { @@ -114,7 +113,7 @@ public void getShardsAllowList() throws Exception { CoreContainer cc = null; ShardHandlerFactory factory = null; try { - final Path home = Paths.get(TEST_HOME()); + final Path home = TEST_PATH(); cc = CoreContainer.createAndLoad(home, home.resolve("solr.xml")); factory = cc.getShardHandlerFactory(); assertTrue(factory instanceof HttpShardHandlerFactory); diff --git a/solr/core/src/test/org/apache/solr/metrics/JvmMetricsTest.java b/solr/core/src/test/org/apache/solr/metrics/JvmMetricsTest.java index 7c007cb00d0..786261210f4 100644 --- a/solr/core/src/test/org/apache/solr/metrics/JvmMetricsTest.java +++ b/solr/core/src/test/org/apache/solr/metrics/JvmMetricsTest.java @@ -16,14 +16,14 @@ */ package org.apache.solr.metrics; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; import java.nio.file.Path; -import java.nio.file.Paths; import java.util.Arrays; import java.util.Map; import com.codahale.metrics.Gauge; import com.codahale.metrics.Metric; -import org.apache.commons.io.FileUtils; import org.apache.solr.SolrJettyTestBase; import org.apache.solr.core.NodeConfig; import org.apache.solr.core.SolrXmlConfig; @@ -116,17 +116,17 @@ public void testSystemProperties() throws Exception { @Test public void testHiddenSysProps() throws Exception { - Path home = Paths.get(TEST_HOME()); + Path home = TEST_PATH(); // default config - String solrXml = FileUtils.readFileToString(Paths.get(home.toString(), "solr.xml").toFile(), "UTF-8"); + String solrXml = Files.readString(home.resolve("solr.xml"), StandardCharsets.UTF_8); NodeConfig config = SolrXmlConfig.fromString(home, solrXml); NodeConfig.NodeConfigBuilder.DEFAULT_HIDDEN_SYS_PROPS.forEach(s -> { assertTrue(s, config.getMetricsConfig().getHiddenSysProps().contains(s)); }); // custom config - solrXml = FileUtils.readFileToString(home.resolve("solr-hiddensysprops.xml").toFile(), "UTF-8"); + solrXml = Files.readString(home.resolve("solr-hiddensysprops.xml"), StandardCharsets.UTF_8); NodeConfig config2 = SolrXmlConfig.fromString(home, solrXml); Arrays.asList("foo", "bar", "baz").forEach(s -> { assertTrue(s, config2.getMetricsConfig().getHiddenSysProps().contains(s)); diff --git a/solr/core/src/test/org/apache/solr/metrics/SolrMetricsIntegrationTest.java b/solr/core/src/test/org/apache/solr/metrics/SolrMetricsIntegrationTest.java index e0c9e110e2b..f527cc858b1 100644 --- a/solr/core/src/test/org/apache/solr/metrics/SolrMetricsIntegrationTest.java +++ b/solr/core/src/test/org/apache/solr/metrics/SolrMetricsIntegrationTest.java @@ -17,8 +17,9 @@ package org.apache.solr.metrics; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; import java.nio.file.Path; -import java.nio.file.Paths; import java.util.Map; import java.util.Random; @@ -26,7 +27,6 @@ import com.codahale.metrics.Metric; import com.codahale.metrics.MetricRegistry; import com.codahale.metrics.Timer; -import org.apache.commons.io.FileUtils; import org.apache.lucene.util.TestUtil; import org.apache.solr.SolrTestCaseJ4; import org.apache.solr.core.CoreContainer; @@ -66,11 +66,11 @@ private void assertTagged(Map reporters, String name @Before public void beforeTest() throws Exception { - Path home = Paths.get(TEST_HOME()); + Path home = TEST_PATH(); // define these properties, they are used in solrconfig.xml System.setProperty("solr.test.sys.prop1", "propone"); System.setProperty("solr.test.sys.prop2", "proptwo"); - String solrXml = FileUtils.readFileToString(Paths.get(home.toString(), "solr-metricreporter.xml").toFile(), "UTF-8"); + String solrXml = Files.readString(home.resolve("solr-metricreporter.xml"), StandardCharsets.UTF_8); NodeConfig cfg = SolrXmlConfig.fromString(home, solrXml); cc = createCoreContainer(cfg, new TestHarness.TestCoresLocator (DEFAULT_TEST_CORENAME, initAndGetDataDir().getAbsolutePath(), diff --git a/solr/core/src/test/org/apache/solr/response/transform/TestSubQueryTransformerDistrib.java b/solr/core/src/test/org/apache/solr/response/transform/TestSubQueryTransformerDistrib.java index 6047df48fb8..e85afe685f0 100644 --- a/solr/core/src/test/org/apache/solr/response/transform/TestSubQueryTransformerDistrib.java +++ b/solr/core/src/test/org/apache/solr/response/transform/TestSubQueryTransformerDistrib.java @@ -22,7 +22,6 @@ import java.net.URL; import java.nio.charset.StandardCharsets; import java.nio.file.Path; -import java.nio.file.Paths; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; @@ -60,8 +59,8 @@ public class TestSubQueryTransformerDistrib extends SolrCloudTestCase { public static void setupCluster() throws Exception { differentUniqueId = random().nextBoolean(); - - final Path configDir = Paths.get(TEST_HOME(), "collection1", "conf"); + + final Path configDir = TEST_COLL1_CONF(); String configName = "solrCloudCollectionConfig"; int nodeCount = 5; diff --git a/solr/core/src/test/org/apache/solr/search/facet/TestCloudJSONFacetJoinDomain.java b/solr/core/src/test/org/apache/solr/search/facet/TestCloudJSONFacetJoinDomain.java index c67c9d3c01c..7b2c277a110 100644 --- a/solr/core/src/test/org/apache/solr/search/facet/TestCloudJSONFacetJoinDomain.java +++ b/solr/core/src/test/org/apache/solr/search/facet/TestCloudJSONFacetJoinDomain.java @@ -19,7 +19,6 @@ import java.io.IOException; import java.lang.invoke.MethodHandles; import java.nio.file.Path; -import java.nio.file.Paths; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; @@ -101,7 +100,7 @@ private static void createMiniSolrCloudCluster() throws Exception { final int numNodes = (numShards * repFactor); final String configName = DEBUG_LABEL + "_config-set"; - final Path configDir = Paths.get(TEST_HOME(), "collection1", "conf"); + final Path configDir = TEST_COLL1_CONF(); configureCluster(numNodes).addConfig(configName, configDir).configure(); diff --git a/solr/core/src/test/org/apache/solr/search/facet/TestCloudJSONFacetSKG.java b/solr/core/src/test/org/apache/solr/search/facet/TestCloudJSONFacetSKG.java index 6f245192605..9c93420442c 100644 --- a/solr/core/src/test/org/apache/solr/search/facet/TestCloudJSONFacetSKG.java +++ b/solr/core/src/test/org/apache/solr/search/facet/TestCloudJSONFacetSKG.java @@ -19,7 +19,6 @@ import java.io.IOException; import java.lang.invoke.MethodHandles; import java.nio.file.Path; -import java.nio.file.Paths; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; @@ -130,7 +129,7 @@ private static void createMiniSolrCloudCluster() throws Exception { final int numNodes = (numShards * repFactor); final String configName = DEBUG_LABEL + "_config-set"; - final Path configDir = Paths.get(TEST_HOME(), "collection1", "conf"); + final Path configDir = TEST_COLL1_CONF(); configureCluster(numNodes).addConfig(configName, configDir).configure(); diff --git a/solr/core/src/test/org/apache/solr/search/facet/TestCloudJSONFacetSKGEquiv.java b/solr/core/src/test/org/apache/solr/search/facet/TestCloudJSONFacetSKGEquiv.java index c0d60354a6a..b3ec3ea2ea8 100644 --- a/solr/core/src/test/org/apache/solr/search/facet/TestCloudJSONFacetSKGEquiv.java +++ b/solr/core/src/test/org/apache/solr/search/facet/TestCloudJSONFacetSKGEquiv.java @@ -19,7 +19,6 @@ import java.io.IOException; import java.lang.invoke.MethodHandles; import java.nio.file.Path; -import java.nio.file.Paths; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; @@ -124,7 +123,7 @@ private static void createMiniSolrCloudCluster() throws Exception { final int numNodes = (numShards * repFactor); final String configName = DEBUG_LABEL + "_config-set"; - final Path configDir = Paths.get(TEST_HOME(), "collection1", "conf"); + final Path configDir = TEST_COLL1_CONF(); configureCluster(numNodes).addConfig(configName, configDir).configure(); diff --git a/solr/core/src/test/org/apache/solr/search/join/TestCloudNestedDocsSort.java b/solr/core/src/test/org/apache/solr/search/join/TestCloudNestedDocsSort.java index 8ecd19867b4..f01e73d599e 100644 --- a/solr/core/src/test/org/apache/solr/search/join/TestCloudNestedDocsSort.java +++ b/solr/core/src/test/org/apache/solr/search/join/TestCloudNestedDocsSort.java @@ -18,7 +18,6 @@ import java.io.IOException; import java.nio.file.Path; -import java.nio.file.Paths; import java.util.ArrayList; import java.util.Collections; import java.util.Iterator; @@ -55,7 +54,7 @@ public static void setupCluster() throws Exception { vals.add(""+Integer.toString(random().nextInt(1000000), Character.MAX_RADIX)); } - final Path configDir = Paths.get(TEST_HOME(), "collection1", "conf"); + final Path configDir = TEST_COLL1_CONF(); String configName = "solrCloudCollectionConfig"; int nodeCount = 5; diff --git a/solr/core/src/test/org/apache/solr/update/TestInPlaceUpdateWithRouteField.java b/solr/core/src/test/org/apache/solr/update/TestInPlaceUpdateWithRouteField.java index 6a0ec281997..41e6aa2e7f0 100644 --- a/solr/core/src/test/org/apache/solr/update/TestInPlaceUpdateWithRouteField.java +++ b/solr/core/src/test/org/apache/solr/update/TestInPlaceUpdateWithRouteField.java @@ -21,7 +21,6 @@ import java.io.IOException; import java.nio.file.Path; -import java.nio.file.Paths; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; @@ -58,7 +57,7 @@ public class TestInPlaceUpdateWithRouteField extends SolrCloudTestCase { @BeforeClass public static void setupCluster() throws Exception { - final Path configDir = Paths.get(TEST_HOME(), "collection1", "conf"); + final Path configDir = TEST_COLL1_CONF(); String configName = "solrCloudCollectionConfig"; int nodeCount = TestUtil.nextInt(random(), 1, 3); diff --git a/solr/licenses/zookeeper-3.7.0-tests.jar.sha1 b/solr/licenses/zookeeper-3.7.0-tests.jar.sha1 new file mode 100644 index 00000000000..ec7eff71132 --- /dev/null +++ b/solr/licenses/zookeeper-3.7.0-tests.jar.sha1 @@ -0,0 +1 @@ +093f2c34c33ee16f9ff3f9352c79eafd3cd9040a diff --git a/solr/solrj/src/java/org/apache/solr/common/cloud/ConnectionManager.java b/solr/solrj/src/java/org/apache/solr/common/cloud/ConnectionManager.java index 1bd16cfafc3..9af77a3d527 100644 --- a/solr/solrj/src/java/org/apache/solr/common/cloud/ConnectionManager.java +++ b/solr/solrj/src/java/org/apache/solr/common/cloud/ConnectionManager.java @@ -24,6 +24,7 @@ import org.apache.zookeeper.WatchedEvent; import org.apache.zookeeper.Watcher; import org.apache.zookeeper.Watcher.Event.KeeperState; +import org.apache.zookeeper.ZooKeeper; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -73,8 +74,8 @@ public boolean isLikelyExpired(long timeToExpire) { } } - public static abstract class IsClosed { - public abstract boolean isClosed(); + public interface IsClosed { + boolean isClosed(); } private volatile LikelyExpiredState likelyExpiredState = LikelyExpiredState.EXPIRED; @@ -153,7 +154,7 @@ public void process(WatchedEvent event) { client.getZkClientTimeout(), this, new ZkClientConnectionStrategy.ZkUpdate() { @Override - public void update(SolrZooKeeper keeper) { + public void update(ZooKeeper keeper) { try { waitForConnected(Long.MAX_VALUE); @@ -178,6 +179,18 @@ public void update(SolrZooKeeper keeper) { throw new RuntimeException(e1); } } + + private void closeKeeper(ZooKeeper keeper) { + try { + keeper.close(); + } catch (InterruptedException e) { + // Restore the interrupted status + Thread.currentThread().interrupt(); + log.error("", e); + throw new ZooKeeperException(SolrException.ErrorCode.SERVER_ERROR, + "", e); + } + } }); break; @@ -269,16 +282,4 @@ public synchronized void waitForDisconnected(long timeout) throw new TimeoutException("Did not disconnect"); } } - - private void closeKeeper(SolrZooKeeper keeper) { - try { - keeper.close(); - } catch (InterruptedException e) { - // Restore the interrupted status - Thread.currentThread().interrupt(); - log.error("", e); - throw new ZooKeeperException(SolrException.ErrorCode.SERVER_ERROR, - "", e); - } - } } diff --git a/solr/solrj/src/java/org/apache/solr/common/cloud/DefaultConnectionStrategy.java b/solr/solrj/src/java/org/apache/solr/common/cloud/DefaultConnectionStrategy.java index 85c4b11a9e0..10795aa1be8 100644 --- a/solr/solrj/src/java/org/apache/solr/common/cloud/DefaultConnectionStrategy.java +++ b/solr/solrj/src/java/org/apache/solr/common/cloud/DefaultConnectionStrategy.java @@ -22,6 +22,7 @@ import org.apache.solr.common.AlreadyClosedException; import org.apache.zookeeper.Watcher; +import org.apache.zookeeper.ZooKeeper; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -34,7 +35,7 @@ public class DefaultConnectionStrategy extends ZkClientConnectionStrategy { @Override public void connect(String serverAddress, int timeout, Watcher watcher, ZkUpdate updater) throws IOException, InterruptedException, TimeoutException { - SolrZooKeeper zk = createSolrZooKeeper(serverAddress, timeout, watcher); + ZooKeeper zk = createZooKeeper(serverAddress, timeout, watcher); boolean success = false; try { updater.update(zk); @@ -50,7 +51,7 @@ public void connect(String serverAddress, int timeout, Watcher watcher, ZkUpdate public void reconnect(final String serverAddress, final int zkClientTimeout, final Watcher watcher, final ZkUpdate updater) throws IOException, InterruptedException, TimeoutException { log.warn("Connection expired - starting a new one..."); - SolrZooKeeper zk = createSolrZooKeeper(serverAddress, zkClientTimeout, watcher); + ZooKeeper zk = createZooKeeper(serverAddress, zkClientTimeout, watcher); boolean success = false; try { updater diff --git a/solr/solrj/src/java/org/apache/solr/common/cloud/SolrZkClient.java b/solr/solrj/src/java/org/apache/solr/common/cloud/SolrZkClient.java index a9d981f92ca..5fa67f6c73d 100644 --- a/solr/solrj/src/java/org/apache/solr/common/cloud/SolrZkClient.java +++ b/solr/solrj/src/java/org/apache/solr/common/cloud/SolrZkClient.java @@ -17,7 +17,6 @@ package org.apache.solr.common.cloud; import java.io.Closeable; -import java.io.File; import java.io.IOException; import java.io.PrintStream; import java.lang.invoke.MethodHandles; @@ -61,6 +60,7 @@ * ZooKeeper. This class handles synchronous connects and reconnections. * */ +// The constructor overloads are a little awkward, in a major version it might be nice to move this to a builder public class SolrZkClient implements Closeable { static final String NEWL = System.getProperty("line.separator"); @@ -71,7 +71,7 @@ public class SolrZkClient implements Closeable { private ConnectionManager connManager; - private volatile SolrZooKeeper keeper; + private volatile ZooKeeper keeper; private ZkCmdExecutor zkCmdExecutor; @@ -98,15 +98,15 @@ public SolrZkClient() { } public SolrZkClient(String zkServerAddress, int zkClientTimeout) { - this(zkServerAddress, zkClientTimeout, new DefaultConnectionStrategy(), null); + this(zkServerAddress, zkClientTimeout, DEFAULT_CLIENT_CONNECT_TIMEOUT); } public SolrZkClient(String zkServerAddress, int zkClientTimeout, int zkClientConnectTimeout) { - this(zkServerAddress, zkClientTimeout, zkClientConnectTimeout, new DefaultConnectionStrategy(), null); + this(zkServerAddress, zkClientTimeout, zkClientConnectTimeout, null); } - public SolrZkClient(String zkServerAddress, int zkClientTimeout, int zkClientConnectTimeout, OnReconnect onReonnect) { - this(zkServerAddress, zkClientTimeout, zkClientConnectTimeout, new DefaultConnectionStrategy(), onReonnect); + public SolrZkClient(String zkServerAddress, int zkClientTimeout, int zkClientConnectTimeout, OnReconnect onReconnect) { + this(zkServerAddress, zkClientTimeout, zkClientConnectTimeout, null, onReconnect); } public SolrZkClient(String zkServerAddress, int zkClientTimeout, @@ -116,7 +116,7 @@ public SolrZkClient(String zkServerAddress, int zkClientTimeout, public SolrZkClient(String zkServerAddress, int zkClientTimeout, int clientConnectTimeout, ZkClientConnectionStrategy strat, final OnReconnect onReconnect) { - this(zkServerAddress, zkClientTimeout, clientConnectTimeout, strat, onReconnect, null, null, null); + this(zkServerAddress, zkClientTimeout, clientConnectTimeout, strat, onReconnect, null ); } public SolrZkClient(String zkServerAddress, int zkClientTimeout, int clientConnectTimeout, @@ -129,7 +129,22 @@ public SolrZkClient(String zkServerAddress, int zkClientTimeout, int clientConne this.zkServerAddress = zkServerAddress; this.higherLevelIsClosed = higherLevelIsClosed; if (strat == null) { - strat = new DefaultConnectionStrategy(); + // Typically unset but useful for testing + String connectionStrategy = System.getProperty("solr.zookeeper.connectionStrategy"); + if (connectionStrategy != null) { + try { + strat = Class.forName(connectionStrategy) + .asSubclass(ZkClientConnectionStrategy.class) + .getConstructor() + .newInstance(); + } catch (Exception e) { + log.warn("Exception when loading '{}' ZK connection strategy class.", connectionStrategy, e); + } + } + if (strat == null) { + // fall back to the default strategy even if we encountered errors earlier + strat = new DefaultConnectionStrategy(); + } } this.zkClientConnectionStrategy = strat; @@ -140,26 +155,14 @@ public SolrZkClient(String zkServerAddress, int zkClientTimeout, int clientConne this.zkClientTimeout = zkClientTimeout; // we must retry at least as long as the session timeout - zkCmdExecutor = new ZkCmdExecutor(zkClientTimeout, new IsClosed() { - - @Override - public boolean isClosed() { - return SolrZkClient.this.isClosed(); - } - }); + zkCmdExecutor = new ZkCmdExecutor(zkClientTimeout, SolrZkClient.this::isClosed); connManager = new ConnectionManager("ZooKeeperConnection Watcher:" - + zkServerAddress, this, zkServerAddress, strat, onReconnect, beforeReconnect, new IsClosed() { - - @Override - public boolean isClosed() { - return SolrZkClient.this.isClosed(); - } - }); + + zkServerAddress, this, zkServerAddress, strat, onReconnect, beforeReconnect, SolrZkClient.this::isClosed); try { strat.connect(zkServerAddress, zkClientTimeout, wrapWatcher(connManager), zooKeeper -> { - SolrZooKeeper oldKeeper = keeper; + ZooKeeper oldKeeper = keeper; keeper = zooKeeper; try { closeKeeper(oldKeeper); @@ -425,15 +428,15 @@ public void makePath(String path, boolean failOnExists, boolean retryOnConnLoss) makePath(path, null, CreateMode.PERSISTENT, null, failOnExists, retryOnConnLoss, 0); } - public void makePath(String path, File file, boolean failOnExists, boolean retryOnConnLoss) + public void makePath(String path, Path data, boolean failOnExists, boolean retryOnConnLoss) throws IOException, KeeperException, InterruptedException { - makePath(path, Files.readAllBytes(file.toPath()), + makePath(path, Files.readAllBytes(data), CreateMode.PERSISTENT, null, failOnExists, retryOnConnLoss, 0); } - public void makePath(String path, File file, boolean retryOnConnLoss) throws IOException, + public void makePath(String path, Path data, boolean retryOnConnLoss) throws IOException, KeeperException, InterruptedException { - makePath(path, Files.readAllBytes(file.toPath()), retryOnConnLoss); + makePath(path, Files.readAllBytes(data), retryOnConnLoss); } public void makePath(String path, CreateMode createMode, boolean retryOnConnLoss) throws KeeperException, @@ -579,15 +582,14 @@ public Stat setData(String path, byte[] data, boolean retryOnConnLoss) throws Ke * Write file to ZooKeeper - default system encoding used. * * @param path path to upload file to e.g. /solr/conf/solrconfig.xml - * @param file path to file to be uploaded + * @param data a filepath to read data from */ - public Stat setData(String path, File file, boolean retryOnConnLoss) throws IOException, + public Stat setData(String path, Path data, boolean retryOnConnLoss) throws IOException, KeeperException, InterruptedException { if (log.isDebugEnabled()) { - log.debug("Write to ZooKeeper: {} to {}", file.getAbsolutePath(), path); + log.debug("Write to ZooKeeper: {} to {}", data.toAbsolutePath(), path); } - byte[] data = Files.readAllBytes(file.toPath()); - return setData(path, data, retryOnConnLoss); + return setData(path, Files.readAllBytes(data), retryOnConnLoss); } public List multi(final Iterable ops, boolean retryOnConnLoss) throws InterruptedException, KeeperException { @@ -658,8 +660,8 @@ public boolean isClosed() { /** * Allows package private classes to update volatile ZooKeeper. */ - void updateKeeper(SolrZooKeeper keeper) throws InterruptedException { - SolrZooKeeper oldKeeper = this.keeper; + void updateKeeper(ZooKeeper keeper) throws InterruptedException { + ZooKeeper oldKeeper = this.keeper; this.keeper = keeper; if (oldKeeper != null) { oldKeeper.close(); @@ -668,11 +670,16 @@ void updateKeeper(SolrZooKeeper keeper) throws InterruptedException { if (isClosed) this.keeper.close(); } - public SolrZooKeeper getSolrZooKeeper() { + public ZooKeeper getZooKeeper() { + return keeper; + } + + @Deprecated + public ZooKeeper getSolrZooKeeper() { return keeper; } - private void closeKeeper(SolrZooKeeper keeper) { + private void closeKeeper(ZooKeeper keeper) { if (keeper != null) { try { keeper.close(); diff --git a/solr/solrj/src/java/org/apache/solr/common/cloud/SolrZooKeeper.java b/solr/solrj/src/java/org/apache/solr/common/cloud/SolrZooKeeper.java deleted file mode 100644 index 04fab5dbc66..00000000000 --- a/solr/solrj/src/java/org/apache/solr/common/cloud/SolrZooKeeper.java +++ /dev/null @@ -1,109 +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 java.io.IOException; -import java.lang.reflect.Field; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.net.SocketAddress; -import java.security.AccessController; -import java.security.PrivilegedAction; -import java.util.Set; -import java.util.concurrent.CopyOnWriteArraySet; - -import org.apache.solr.common.util.SuppressForbidden; -import org.apache.zookeeper.ClientCnxn; -import org.apache.zookeeper.Watcher; -import org.apache.zookeeper.ZooKeeper; - -// we use this class to expose nasty stuff for tests -@SuppressWarnings({"try"}) -public class SolrZooKeeper extends ZooKeeper { - final Set spawnedThreads = new CopyOnWriteArraySet<>(); - - // for test debug - //static Map clients = new ConcurrentHashMap(); - - public SolrZooKeeper(String connectString, int sessionTimeout, - Watcher watcher) throws IOException { - super(connectString, sessionTimeout, watcher); - //clients.put(this, new RuntimeException()); - } - - public ClientCnxn getConnection() { - return cnxn; - } - - public SocketAddress getSocketAddress() { - return testableLocalSocketAddress(); - } - - public void closeCnxn() { - final Thread t = new Thread(new Runnable() { - @Override - public void run() { - try { - AccessController.doPrivileged((PrivilegedAction) this::closeZookeeperChannel); - } finally { - spawnedThreads.remove(Thread.currentThread()); - } - } - - @SuppressForbidden(reason = "Hack for Zookeeper needs access to private methods.") - private Void closeZookeeperChannel() { - final ClientCnxn cnxn = getConnection(); - synchronized (cnxn) { - try { - final Field sendThreadFld = cnxn.getClass().getDeclaredField("sendThread"); - sendThreadFld.setAccessible(true); - Object sendThread = sendThreadFld.get(cnxn); - if (sendThread != null) { - Method method = sendThread.getClass().getDeclaredMethod("testableCloseSocket"); - method.setAccessible(true); - try { - method.invoke(sendThread); - } catch (InvocationTargetException e) { - // is fine - } - } - } catch (Exception e) { - throw new RuntimeException("Closing Zookeeper send channel failed.", e); - } - } - return null; // Void - } - }, "closeCnxn"); - spawnedThreads.add(t); - t.start(); - } - - @Override - public synchronized void close() throws InterruptedException { - super.close(); - } - -// public static void assertCloses() { -// if (clients.size() > 0) { -// Iterator stacktraces = clients.values().iterator(); -// Exception cause = null; -// cause = stacktraces.next(); -// throw new RuntimeException("Found a bad one!", cause); -// } -// } - -} diff --git a/solr/solrj/src/java/org/apache/solr/common/cloud/ZkClientConnectionStrategy.java b/solr/solrj/src/java/org/apache/solr/common/cloud/ZkClientConnectionStrategy.java index d77d15e54de..280a5fd2121 100644 --- a/solr/solrj/src/java/org/apache/solr/common/cloud/ZkClientConnectionStrategy.java +++ b/solr/solrj/src/java/org/apache/solr/common/cloud/ZkClientConnectionStrategy.java @@ -25,6 +25,7 @@ import org.apache.solr.common.SolrException; import org.apache.solr.common.cloud.ZkCredentialsProvider.ZkCredentials; import org.apache.zookeeper.Watcher; +import org.apache.zookeeper.ZooKeeper; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -89,7 +90,7 @@ public synchronized void addConnectedListener(ConnectedListener listener) { } public interface ZkUpdate { - void update(SolrZooKeeper zooKeeper) throws InterruptedException, TimeoutException, IOException; + void update(ZooKeeper zooKeeper) throws InterruptedException, TimeoutException, IOException; } public void setZkCredentialsToAddAutomatically(ZkCredentialsProvider zkCredentialsToAddAutomatically) { @@ -104,16 +105,19 @@ public boolean hasZkCredentialsToAddAutomatically() { public ZkCredentialsProvider getZkCredentialsToAddAutomatically() { return zkCredentialsToAddAutomatically; } - protected SolrZooKeeper createSolrZooKeeper(final String serverAddress, final int zkClientTimeout, - final Watcher watcher) throws IOException { - SolrZooKeeper result = new SolrZooKeeper(serverAddress, zkClientTimeout, watcher); + protected ZooKeeper createZooKeeper(String serverAddress, int zkClientTimeout, Watcher watcher) throws IOException { + ZooKeeper zk = newZooKeeperInstance(serverAddress, zkClientTimeout, watcher); zkCredentialsToAddAutomaticallyUsed = true; for (ZkCredentials zkCredentials : zkCredentialsToAddAutomatically.getCredentials()) { - result.addAuthInfo(zkCredentials.getScheme(), zkCredentials.getAuth()); + zk.addAuthInfo(zkCredentials.getScheme(), zkCredentials.getAuth()); } - return result; + return zk; } + protected ZooKeeper newZooKeeperInstance(String serverAddress, int zkClientTimeout, Watcher watcher) + throws IOException { + return new ZooKeeper(serverAddress, zkClientTimeout, watcher); + } } diff --git a/solr/solrj/src/java/org/apache/solr/common/cloud/ZkMaintenanceUtils.java b/solr/solrj/src/java/org/apache/solr/common/cloud/ZkMaintenanceUtils.java index 645b80dea83..aff7fdeb2fd 100644 --- a/solr/solrj/src/java/org/apache/solr/common/cloud/ZkMaintenanceUtils.java +++ b/solr/solrj/src/java/org/apache/solr/common/cloud/ZkMaintenanceUtils.java @@ -295,12 +295,12 @@ public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IO try { // if the path exists (and presumably we're uploading data to it) just set its data if (file.toFile().getName().equals(ZKNODE_DATA_FILE) && zkClient.exists(zkNode, true)) { - zkClient.setData(zkNode, file.toFile(), true); + zkClient.setData(zkNode, file, true); } else { - zkClient.makePath(zkNode, file.toFile(), false, true); + zkClient.makePath(zkNode, file, false, true); } } catch (KeeperException | InterruptedException e) { - throw new IOException("Error uploading file " + file.toString() + " to zookeeper path " + zkNode, + throw new IOException("Error uploading file " + file + " to zookeeper path " + zkNode, SolrZkClient.checkInterrupted(e)); } return FileVisitResult.CONTINUE; @@ -320,11 +320,11 @@ private static boolean isEphemeral(SolrZkClient zkClient, String zkPath) throws return znodeStat.getEphemeralOwner() != 0; } - private static int copyDataDown(SolrZkClient zkClient, String zkPath, File file) throws IOException, KeeperException, InterruptedException { + private static int copyDataDown(SolrZkClient zkClient, String zkPath, Path file) throws IOException, KeeperException, InterruptedException { byte[] data = zkClient.getData(zkPath, null, null, true); if (data != null && data.length > 0) { // There are apparently basically empty ZNodes. log.info("Writing file {}", file); - Files.write(file.toPath(), data); + Files.write(file, data); return data.length; } return 0; @@ -338,14 +338,14 @@ public static void downloadFromZK(SolrZkClient zkClient, String zkPath, Path fil if (children.size() == 0) { // If we didn't copy data down, then we also didn't create the file. But we still need a marker on the local // disk so create an empty file. - if (copyDataDown(zkClient, zkPath, file.toFile()) == 0) { + if (copyDataDown(zkClient, zkPath, file) == 0) { Files.createFile(file); } } else { Files.createDirectories(file); // Make parent dir. // ZK nodes, whether leaf or not can have data. If it's a non-leaf node and // has associated data write it into the special file. - copyDataDown(zkClient, zkPath, new File(file.toFile(), ZKNODE_DATA_FILE)); + copyDataDown(zkClient, zkPath, file.resolve(ZKNODE_DATA_FILE)); for (String child : children) { String zkChild = zkPath; diff --git a/solr/test-framework/build.gradle b/solr/test-framework/build.gradle index 066790fde7e..dd4159fa724 100644 --- a/solr/test-framework/build.gradle +++ b/solr/test-framework/build.gradle @@ -26,11 +26,15 @@ dependencies { api "org.apache.lucene:lucene-test-framework" api "org.apache.lucene:lucene-analysis-common" - implementation('org.apache.zookeeper:zookeeper', { + var zkExcludes = { exclude group: "org.apache.yetus", module: "audience-annotations" exclude group: "log4j", module: "log4j" exclude group: "org.slf4j", module: "slf4j-log4j12" - }) + } + + implementation('org.apache.zookeeper:zookeeper', zkExcludes) + // TODO investigate java-test-fixtures plugin? + implementation('org.apache.zookeeper:zookeeper:3.7.0:tests', zkExcludes) implementation 'commons-io:commons-io' implementation 'org.apache.logging.log4j:log4j-core' diff --git a/solr/test-framework/src/java/org/apache/solr/SolrTestCaseJ4.java b/solr/test-framework/src/java/org/apache/solr/SolrTestCaseJ4.java index 5a1bb262549..f0787d9bb06 100644 --- a/solr/test-framework/src/java/org/apache/solr/SolrTestCaseJ4.java +++ b/solr/test-framework/src/java/org/apache/solr/SolrTestCaseJ4.java @@ -100,6 +100,7 @@ import org.apache.solr.client.solrj.util.ClientUtils; import org.apache.solr.cloud.IpTables; import org.apache.solr.cloud.MiniSolrCloudCluster; +import org.apache.solr.cloud.TestConnectionStrategy; import org.apache.solr.common.SolrDocument; import org.apache.solr.common.SolrDocumentList; import org.apache.solr.common.SolrException; @@ -294,6 +295,7 @@ public static void setupTestCases() { System.setProperty("solr.v2RealPath", "true"); System.setProperty("zookeeper.forceSync", "no"); System.setProperty("jetty.testMode", "true"); + System.setProperty("solr.zookeeper.connectionStrategy", TestConnectionStrategy.class.getName()); System.setProperty("enable.update.log", Boolean.toString(usually())); System.setProperty("tests.shardhandler.randomSeed", Long.toString(random().nextLong())); System.setProperty("solr.clustering.enabled", "false"); @@ -2130,6 +2132,8 @@ public static String TEST_HOME() { public static Path TEST_PATH() { return getFile("solr/collection1").getParentFile().toPath(); } + public static Path TEST_COLL1_CONF() { return TEST_PATH().resolve("collection1").resolve("conf"); } + public static Path configset(String name) { return TEST_PATH().resolve("configsets").resolve(name).resolve("conf"); } diff --git a/solr/test-framework/src/java/org/apache/solr/cloud/AbstractZkTestCase.java b/solr/test-framework/src/java/org/apache/solr/cloud/AbstractZkTestCase.java index f27525ee05e..646270be9f0 100644 --- a/solr/test-framework/src/java/org/apache/solr/cloud/AbstractZkTestCase.java +++ b/solr/test-framework/src/java/org/apache/solr/cloud/AbstractZkTestCase.java @@ -16,7 +16,6 @@ */ package org.apache.solr.cloud; -import java.io.File; import java.lang.invoke.MethodHandles; import java.nio.file.Path; @@ -36,12 +35,12 @@ public abstract class AbstractZkTestCase extends SolrTestCaseJ4 { private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass()); - public static File SOLRHOME; + public static Path SOLRHOME; static { try { - SOLRHOME = new File(SolrTestCaseJ4.TEST_HOME()); + SOLRHOME = SolrTestCaseJ4.TEST_PATH(); } catch (RuntimeException e) { - log.warn("TEST_HOME() does not exist - solrj test?"); + log.warn("TEST_PATH() does not exist - solrj test?"); // solrj tests not working with TEST_HOME() // must override getSolrHome } diff --git a/solr/test-framework/src/java/org/apache/solr/cloud/ChaosMonkey.java b/solr/test-framework/src/java/org/apache/solr/cloud/ChaosMonkey.java index 60b4ec02925..0967ab56c49 100644 --- a/solr/test-framework/src/java/org/apache/solr/cloud/ChaosMonkey.java +++ b/solr/test-framework/src/java/org/apache/solr/cloud/ChaosMonkey.java @@ -16,6 +16,7 @@ */ package org.apache.solr.cloud; +import java.io.IOException; import java.lang.invoke.MethodHandles; import java.util.ArrayList; import java.util.List; @@ -48,6 +49,8 @@ import org.apache.solr.util.TestInjection; import org.apache.solr.util.TimeOut; import org.apache.zookeeper.KeeperException; +import org.apache.zookeeper.TestableZooKeeper; +import org.apache.zookeeper.ZooKeeper; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -137,9 +140,8 @@ public void expireSession(final JettySolrRunner jetty) { if (cores != null) { monkeyLog("expire session for " + jetty.getLocalPort() + " !"); causeConnectionLoss(jetty); - long sessionId = cores.getZkController().getZkClient() - .getSolrZooKeeper().getSessionId(); - zkServer.expire(sessionId); + cores.getZkController().getZkClient() + .getSolrZooKeeper().getTestable().injectSessionExpiration(); } } @@ -164,13 +166,25 @@ public void randomConnectionLoss() throws KeeperException, InterruptedException connloss.incrementAndGet(); } } - + public static void causeConnectionLoss(JettySolrRunner jetty) { CoreContainer cores = jetty.getCoreContainer(); if (cores != null) { monkeyLog("Will cause connection loss on " + jetty.getLocalPort()); SolrZkClient zkClient = cores.getZkController().getZkClient(); - zkClient.getSolrZooKeeper().closeCnxn(); + causeConnectionLoss(zkClient.getSolrZooKeeper()); + } + } + + public static void causeConnectionLoss(ZooKeeper zooKeeper) { + if (zooKeeper instanceof TestableZooKeeper) { + try { + ((TestableZooKeeper) zooKeeper).testableConnloss(); + } catch (IOException ignored) { + // best effort + } + } else { + // TODO? } } diff --git a/solr/test-framework/src/java/org/apache/solr/cloud/MiniSolrCloudCluster.java b/solr/test-framework/src/java/org/apache/solr/cloud/MiniSolrCloudCluster.java index 677bf0a4cbf..b3c6ac352e1 100644 --- a/solr/test-framework/src/java/org/apache/solr/cloud/MiniSolrCloudCluster.java +++ b/solr/test-framework/src/java/org/apache/solr/cloud/MiniSolrCloudCluster.java @@ -694,14 +694,13 @@ public JettySolrRunner getReplicaJetty(Replica replica) { * Make the zookeeper session on a particular jetty expire */ public void expireZkSession(JettySolrRunner jetty) { + ChaosMonkey.causeConnectionLoss(jetty); + CoreContainer cores = jetty.getCoreContainer(); if (cores != null) { - SolrZkClient zkClient = cores.getZkController().getZkClient(); - zkClient.getSolrZooKeeper().closeCnxn(); - long sessionId = zkClient.getSolrZooKeeper().getSessionId(); - zkServer.expire(sessionId); + cores.getZkController().getZkClient().getZooKeeper().getTestable().injectSessionExpiration(); if (log.isInfoEnabled()) { - log.info("Expired zookeeper session {} from node {}", sessionId, jetty.getBaseUrl()); + log.info("Expired zookeeper session from node {}", jetty.getBaseUrl()); } } } diff --git a/solr/test-framework/src/java/org/apache/solr/cloud/TestConnectionStrategy.java b/solr/test-framework/src/java/org/apache/solr/cloud/TestConnectionStrategy.java new file mode 100644 index 00000000000..8cd5a096628 --- /dev/null +++ b/solr/test-framework/src/java/org/apache/solr/cloud/TestConnectionStrategy.java @@ -0,0 +1,33 @@ +/* + * 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.cloud; + +import org.apache.solr.common.cloud.DefaultConnectionStrategy; +import org.apache.zookeeper.TestableZooKeeper; +import org.apache.zookeeper.Watcher; +import org.apache.zookeeper.ZooKeeper; + +import java.io.IOException; + +public class TestConnectionStrategy extends DefaultConnectionStrategy { + @Override + protected ZooKeeper newZooKeeperInstance(String serverAddress, int zkClientTimeout, Watcher watcher) + throws IOException { + return new TestableZooKeeper(serverAddress, zkClientTimeout, watcher); + } +} diff --git a/solr/test-framework/src/java/org/apache/solr/cloud/ZkTestServer.java b/solr/test-framework/src/java/org/apache/solr/cloud/ZkTestServer.java index d5eee2d61d0..39a9f205a28 100644 --- a/solr/test-framework/src/java/org/apache/solr/cloud/ZkTestServer.java +++ b/solr/test-framework/src/java/org/apache/solr/cloud/ZkTestServer.java @@ -23,40 +23,36 @@ import org.apache.solr.common.cloud.ZkNodeProps; import org.apache.solr.common.util.IOUtils; import org.apache.solr.common.util.ObjectReleaseTracker; -import org.apache.solr.common.util.TimeSource; +import org.apache.solr.common.util.SuppressForbidden; import org.apache.solr.common.util.Utils; -import org.apache.solr.util.TimeOut; import org.apache.zookeeper.CreateMode; import org.apache.zookeeper.KeeperException; import org.apache.zookeeper.Op; -import org.apache.zookeeper.WatchedEvent; +import org.apache.zookeeper.PortAssignment; import org.apache.zookeeper.Watcher; import org.apache.zookeeper.data.Stat; -import org.apache.zookeeper.jmx.ManagedUtil; import org.apache.zookeeper.server.NIOServerCnxnFactory; import org.apache.zookeeper.server.ServerCnxn; import org.apache.zookeeper.server.ServerCnxnFactory; import org.apache.zookeeper.server.ServerConfig; -import org.apache.zookeeper.server.SessionTracker.Session; import org.apache.zookeeper.server.ZKDatabase; import org.apache.zookeeper.server.ZooKeeperServer; +import org.apache.zookeeper.server.embedded.ExitHandler; +import org.apache.zookeeper.server.embedded.ZooKeeperServerEmbedded; import org.apache.zookeeper.server.persistence.FileTxnSnapLog; -import org.apache.zookeeper.server.quorum.QuorumPeerConfig.ConfigException; +import org.apache.zookeeper.test.ClientBase; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import javax.management.JMException; import java.io.BufferedReader; -import java.io.File; import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStream; import java.lang.invoke.MethodHandles; -import java.net.InetAddress; -import java.net.InetSocketAddress; +import java.lang.reflect.Method; import java.net.Socket; -import java.net.UnknownHostException; import java.nio.charset.StandardCharsets; +import java.nio.file.Files; import java.nio.file.Path; import java.util.ArrayList; import java.util.Arrays; @@ -64,21 +60,22 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Properties; import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicReference; +import java.util.regex.Matcher; +import java.util.regex.Pattern; public class ZkTestServer { private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass()); - public static File SOLRHOME; + public static Path SOLRHOME; static { try { - SOLRHOME = new File(SolrTestCaseJ4.TEST_HOME()); + SOLRHOME = SolrTestCaseJ4.TEST_PATH(); } catch (RuntimeException e) { - log.warn("TEST_HOME() does not exist - solrj test?"); - // solrj tests not working with TEST_HOME() + log.warn("TEST_PATH() does not exist - solrj test?"); + // solrj tests not working with TEST_PATH() // must override getSolrHome } } @@ -86,14 +83,12 @@ public class ZkTestServer { public static final int TIMEOUT = 45000; public static final int TICK_TIME = 1000; - protected final ZKServerMain zkServer = new ZKServerMain(); + ZooKeeperServerEmbedded zkse; private volatile Path zkDir; private volatile int clientPort; - private volatile Thread zooThread; - private volatile int theTickTime = TICK_TIME; // SOLR-12101 - provide defaults to avoid max timeout 20 enforced by our server instance when tick time is 1000 private volatile int maxSessionTimeout = 90000; @@ -104,7 +99,7 @@ public class ZkTestServer { private volatile ZKDatabase zkDb; - static public enum LimitViolationAction { + public enum LimitViolationAction { IGNORE, REPORT, FAIL, @@ -117,24 +112,6 @@ class ZKServerMain { private volatile LimitViolationAction violationReportAction = LimitViolationAction.REPORT; private volatile WatchLimiter limiter = new WatchLimiter(1, LimitViolationAction.IGNORE); - protected void initializeAndRun(String[] args) throws ConfigException, - IOException { - try { - ManagedUtil.registerLog4jMBeans(); - } catch (JMException e) { - log.warn("Unable to register log4j JMX control", e); - } - - ServerConfig config = new ServerConfig(); - if (args.length == 1) { - config.parse(args[0]); - } else { - config.parse(args); - } - - runFromConfig(config); - } - private class WatchLimit { private long limit; private final String desc; @@ -174,13 +151,6 @@ public void updateForWatch(String key, Watcher watcher) { } } - public void updateForFire(WatchedEvent event) { - if (log.isDebugEnabled()) { - log.debug("Watch fired: {}: {}", desc, event.getPath()); - } - counters.decrementAndGet(event.getPath()); - } - private String reportLimitViolations() { String[] maxKeys = maxCounters.keySet().toArray(new String[maxCounters.size()]); Arrays.sort(maxKeys, new Comparator() { @@ -234,29 +204,6 @@ public String reportLimitViolations() { dataLimit.reportLimitViolations() + childrenLimit.reportLimitViolations(); } - - private void updateForFire(WatchedEvent event) { - switch (event.getType()) { - case None: - break; - case NodeCreated: - case NodeDeleted: - statLimit.updateForFire(event); - break; - case NodeDataChanged: - dataLimit.updateForFire(event); - break; - case NodeChildrenChanged: - childrenLimit.updateForFire(event); - break; - case ChildWatchRemoved: - break; - case DataWatchRemoved: - break; - case PersistentWatchRemoved: - break; - } - } } private class TestZKDatabase extends ZKDatabase { @@ -363,7 +310,7 @@ protected void shutdown() throws IOException { try { int port = cnxnFactory.getLocalPort(); if (port > 0) { - waitForServerDown(getZkHost(), 30000); + ClientBase.waitForServerDown(getZkHost(), 30_000); } } catch (NullPointerException ignored) { // server never successfully started @@ -409,12 +356,12 @@ public ZkTestServer(Path zkDir, int port) throws KeeperException, InterruptedExc String reportAction = System.getProperty("tests.zk.violationReportAction"); if (reportAction != null) { log.info("Overriding violation report action to: {}", reportAction); - setViolationReportAction(LimitViolationAction.valueOf(reportAction)); + // setViolationReportAction(LimitViolationAction.valueOf(reportAction)); } String limiterAction = System.getProperty("tests.zk.limiterAction"); if (limiterAction != null) { log.info("Overriding limiter action to: {}", limiterAction); - getLimiter().setAction(LimitViolationAction.valueOf(limiterAction)); + // getLimiter().setAction(LimitViolationAction.valueOf(limiterAction)); } ObjectReleaseTracker.track(this); @@ -438,7 +385,7 @@ private void init(boolean solrFormat) throws Exception { public String getZkHost() { String hostName = System.getProperty("hostName", "127.0.0.1"); - return hostName + ":" + zkServer.getLocalPort(); + return hostName + ":" + clientPort; } public String getZkAddress() { @@ -472,35 +419,17 @@ public void ensurePathExists(String path) throws IOException { } public int getPort() { - return zkServer.getLocalPort(); - } - - public void expire(final long sessionId) { - zkServer.zooKeeperServer.expire(new Session() { - @Override - public long getSessionId() { - return sessionId; - } - - @Override - public int getTimeout() { - return 4000; - } - - @Override - public boolean isClosing() { - return false; - } - }); + return clientPort; } public ZKDatabase getZKDatabase() { - return zkServer.zooKeeperServer.getZKDatabase(); + return null; +// return zkServer.zooKeeperServer.getZKDatabase(); } public void setZKDatabase(ZKDatabase zkDb) { this.zkDb = zkDb; - zkServer.zooKeeperServer.setZKDatabase(zkDb); +// zkServer.zooKeeperServer.setZKDatabase(zkDb); } public void run() throws InterruptedException, IOException { @@ -509,191 +438,67 @@ public void run() throws InterruptedException, IOException { public void run(boolean solrFormat) throws InterruptedException, IOException { log.info("STARTING ZK TEST SERVER"); - AtomicReference zooError = new AtomicReference<>(); - try { - if (zooThread != null) { - throw new IllegalStateException("ZK TEST SERVER IS ALREADY RUNNING"); - } - Thread parentThread = Thread.currentThread(); - // we don't call super.distribSetUp - zooThread = new Thread("ZkTestServer Run Thread") { - - @Override - public void run() { - ServerConfig config = new ServerConfig() { - - { - setClientPort(ZkTestServer.this.clientPort); - this.dataDir = zkDir.toFile(); - this.dataLogDir = zkDir.toFile(); - this.tickTime = theTickTime; - this.maxSessionTimeout = ZkTestServer.this.maxSessionTimeout; - this.minSessionTimeout = ZkTestServer.this.minSessionTimeout; - } - - public void setClientPort(int clientPort) { - if (clientPortAddress != null) { - try { - this.clientPortAddress = new InetSocketAddress( - InetAddress.getByName(clientPortAddress.getHostName()), clientPort); - } catch (UnknownHostException e) { - throw new RuntimeException(e); - } - } else { - this.clientPortAddress = new InetSocketAddress(clientPort); - } - log.info("client port: {}", this.clientPortAddress); - } - }; - try { - zkServer.runFromConfig(config); - } catch (Throwable t) { - zooError.set(t); - parentThread.interrupt(); - } - } - }; - ObjectReleaseTracker.track(zooThread); - zooThread.start(); + if (clientPort == 0) { + // Hacks to get PortAssignment to work with our test runner partitioning +/* + String processCount = System.getProperty("tests.jvms", "1"); + System.setProperty("test.junit.threads", processCount); - int cnt = 0; - int port = -1; - try { - port = getPort(); - } catch (IllegalStateException ignored) { - // Possibly fix this API to return null instead of throwing + String cmdLine = System.getProperty("sun.java.command"); // worker.org.gradle.process.internal.worker.GradleWorkerMain 'Gradle Test Executor 2' + System.getProperties().forEach((k,v) -> log.info("{}={}", k, v)); + Matcher m = Pattern.compile("Executor (\\d+)").matcher(cmdLine); + if (m.find()) { + System.setProperty("zookeeper.junit.threadid", m.group(1)); } - while (port < 1) { - Thread.sleep(100); - try { - port = getPort(); - } catch (IllegalStateException ignored) { - // Possibly fix this API to return null instead of throwing - } - if (cnt == 500) { - throw new RuntimeException("Could not get the port for ZooKeeper server"); - } - cnt++; - } - log.info("start zk server on port: {}", port); +*/ + + clientPort = PortAssignment.unique(); + } - waitForServerUp(getZkHost(), 30000); + Properties configuration = new Properties(); + configuration.setProperty("clientPort", String.valueOf(clientPort)); + configuration.setProperty("tickTime", String.valueOf(theTickTime)); + configuration.setProperty("maxSessionTimeout", String.valueOf(maxSessionTimeout)); + configuration.setProperty("minSessionTimeout", String.valueOf(minSessionTimeout)); + configuration.setProperty("admin.enableServer", Boolean.FALSE.toString()); + Files.createDirectories(zkDir); + try { + zkse = ZooKeeperServerEmbedded.builder() + .baseDir(zkDir) + .configuration(configuration) + .exitHandler(ExitHandler.LOG_ONLY) + .build(); + zkse.start(); + } catch (Exception e) { + throw new RuntimeException("Failed to start embedded ZK Server", e); + } + + ClientBase.waitForServerUp(getZkHost(), 30_000); + try { init(solrFormat); } catch (Exception e) { - RuntimeException toThrow = new RuntimeException("Could not get ZK port"); - Throwable t = zooError.get(); - if (t != null) { - toThrow.initCause(t); - toThrow.addSuppressed(e); - } else { - toThrow.initCause(e); - } - throw toThrow; + throw new RuntimeException(e); } } public void shutdown() throws IOException, InterruptedException { log.info("Shutting down ZkTestServer."); - try { - IOUtils.closeQuietly(rootClient); - IOUtils.closeQuietly(chRootClient); - } finally { - - // TODO: this can log an exception while trying to unregister a JMX MBean - try { - zkServer.shutdown(); - } catch (Exception e) { - log.error("Exception shutting down ZooKeeper Test Server",e); - } - - if (zkDb != null) { - zkDb.close(); - } - - while (true) { - try { - if (zooThread != null) { - zooThread.join(); - ObjectReleaseTracker.release(zooThread); - } - zooThread = null; - break; - } catch (InterruptedException e) { - // don't keep interrupted status - } catch (NullPointerException e) { - // okay - break; - } - } + if (zkse != null) { // if there were problems during startup + zkse.close(); } + IOUtils.closeQuietly(rootClient); + IOUtils.closeQuietly(chRootClient); ObjectReleaseTracker.release(this); } - public static boolean waitForServerDown(String hp, long timeoutMs) { - log.info("waitForServerDown: {}", hp); - final TimeOut timeout = new TimeOut(timeoutMs, TimeUnit.MILLISECONDS, TimeSource.NANO_TIME); - while (true) { - try { - HostPort hpobj = parseHostPortList(hp).get(0); - send4LetterWord(hpobj.host, hpobj.port, "stat"); - } catch (IOException e) { - return true; - } - - if (timeout.hasTimedOut()) { - throw new RuntimeException("Time out waiting for ZooKeeper shutdown!"); - } - try { - Thread.sleep(250); - } catch (InterruptedException e) { - // ignore - } - } - } - - public static boolean waitForServerUp(String hp, long timeoutMs) { - log.info("waitForServerUp: {}", hp); - final TimeOut timeout = new TimeOut(timeoutMs, TimeUnit.MILLISECONDS, TimeSource.NANO_TIME); - while (true) { - try { - HostPort hpobj = parseHostPortList(hp).get(0); - send4LetterWord(hpobj.host, hpobj.port, "stat"); - return true; - } catch (IOException e) { - e.printStackTrace(); - } - - if (timeout.hasTimedOut()) { - throw new RuntimeException("Time out waiting for ZooKeeper to startup!"); - } - try { - Thread.sleep(250); - } catch (InterruptedException e) { - // ignore - } - } - } - - public static class HostPort { - String host; - int port; - - HostPort(String host, int port) { - assert !host.contains(":") : host; - this.host = host; - this.port = port; - } - } - /** * Send the 4letterword * @param host the destination host * @param port the destination port * @param cmd the 4letterword * @return server response - */ public static String send4LetterWord(String host, int port, String cmd) throws IOException @@ -722,23 +527,6 @@ public static String send4LetterWord(String host, int port, String cmd) } } - public static List parseHostPortList(String hplist) { - log.info("parse host and port list: {}", hplist); - ArrayList alist = new ArrayList<>(); - for (String hp : hplist.split(",")) { - int idx = hp.lastIndexOf(':'); - String host = hp.substring(0, idx); - int port; - try { - port = Integer.parseInt(hp.substring(idx + 1)); - } catch (RuntimeException e) { - throw new RuntimeException("Problem parsing " + hp + e.toString()); - } - alist.add(new HostPort(host, port)); - } - return alist; - } - public int getTheTickTime() { return theTickTime; } @@ -751,14 +539,6 @@ public Path getZkDir() { return zkDir; } - public void setViolationReportAction(LimitViolationAction violationReportAction) { - zkServer.setViolationReportAction(violationReportAction); - } - - public ZKServerMain.WatchLimiter getLimiter() { - return zkServer.getLimiter(); - } - public int getMaxSessionTimeout() { return maxSessionTimeout; } @@ -780,24 +560,23 @@ void buildZooKeeper(String config, buildZooKeeper(SOLRHOME, config, schema); } - public static void putConfig(String confName, SolrZkClient zkClient, File solrhome, final String name) + public static void putConfig(String confName, SolrZkClient zkClient, Path solrhome, final String name) throws Exception { putConfig(confName, zkClient, null, solrhome, name, name); } - public static void putConfig(String confName, SolrZkClient zkClient, File solrhome, final String srcName, + public static void putConfig(String confName, SolrZkClient zkClient, Path solrhome, final String srcName, String destName) throws Exception { putConfig(confName, zkClient, null, solrhome, srcName, destName); } - public static void putConfig(String confName, SolrZkClient zkClient, String zkChroot, File solrhome, + public static void putConfig(String confName, SolrZkClient zkClient, String zkChroot, Path solrhome, final String srcName, String destName) throws Exception { - File file = new File(solrhome, "collection1" - + File.separator + "conf" + File.separator + srcName); - if (!file.exists()) { + Path file = solrhome.resolve("collection1").resolve("conf").resolve(srcName); + if (!Files.exists(file)) { if (log.isInfoEnabled()) { - log.info("skipping {} because it doesn't exist", file.getAbsolutePath()); + log.info("skipping {} because it doesn't exist", file.toAbsolutePath()); } return; } @@ -807,13 +586,13 @@ public static void putConfig(String confName, SolrZkClient zkClient, String zkCh destPath = zkChroot + destPath; } if (log.isInfoEnabled()) { - log.info("put {} to {}", file.getAbsolutePath(), destPath); + log.info("put {} to {}", file.toAbsolutePath(), destPath); } zkClient.makePath(destPath, file, false, true); } // static to share with distrib test - public void buildZooKeeper(File solrhome, String config, String schema) throws Exception { + public void buildZooKeeper(Path solrhome, String config, String schema) throws Exception { Map props = new HashMap<>(); props.put("configName", "conf1"); diff --git a/solr/test-framework/src/test/org/apache/solr/cloud/MiniSolrCloudClusterTest.java b/solr/test-framework/src/test/org/apache/solr/cloud/MiniSolrCloudClusterTest.java index 193e9ec2553..4a58106ab19 100644 --- a/solr/test-framework/src/test/org/apache/solr/cloud/MiniSolrCloudClusterTest.java +++ b/solr/test-framework/src/test/org/apache/solr/cloud/MiniSolrCloudClusterTest.java @@ -65,9 +65,9 @@ public JettySolrRunner startJettySolrRunner(String name, String context, JettyCo fail("Expected an exception to be thrown from MiniSolrCloudCluster"); } catch (Exception e) { - assertEquals("Error starting up MiniSolrCloudCluster", e.getMessage()); + assertEquals("Incorrect exception", "Error starting up MiniSolrCloudCluster", e.getMessage()); assertEquals("Expected one suppressed exception", 1, e.getSuppressed().length); - assertEquals("Fake exception on startup!", e.getSuppressed()[0].getMessage()); + assertEquals("Incorrect supressed exception", "Fake exception on startup!", e.getSuppressed()[0].getMessage()); } finally { if (cluster != null)