package org.apache.solr.cloud; /* * 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. */ import java.io.File; import java.io.IOException; import java.util.Random; import java.util.concurrent.SynchronousQueue; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; import org.apache.solr.SolrTestCaseJ4.SuppressSSL; import org.apache.lucene.util.LuceneTestCase.Slow; import org.apache.solr.client.solrj.SolrQuery; import org.apache.solr.client.solrj.SolrServer; import org.apache.solr.client.solrj.SolrServerException; import org.apache.solr.client.solrj.impl.HttpSolrServer; import org.apache.solr.client.solrj.request.CoreAdminRequest.Create; import org.apache.solr.client.solrj.request.CoreAdminRequest.Unload; import org.apache.solr.common.SolrInputDocument; import org.apache.solr.common.cloud.ZkCoreNodeProps; import org.apache.solr.common.cloud.ZkStateReader; import org.apache.solr.common.params.ModifiableSolrParams; import org.apache.solr.update.DirectUpdateHandler2; import org.apache.solr.util.DefaultSolrThreadFactory; import org.junit.Before; import org.junit.BeforeClass; /** * This test simply does a bunch of basic things in solrcloud mode and asserts things * work as expected. */ @Slow @SuppressSSL(bugUrl = "https://issues.apache.org/jira/browse/SOLR-5776") public class UnloadDistributedZkTest extends BasicDistributedZkTest { @BeforeClass public static void beforeThisClass3() throws Exception { } @Before @Override public void setUp() throws Exception { super.setUp(); } protected String getSolrXml() { return "solr-no-core.xml"; } public UnloadDistributedZkTest() { super(); checkCreatedVsState = false; } @Override public void doTest() throws Exception { testCoreUnloadAndLeaders(); // long testUnloadLotsOfCores(); // long testUnloadShardAndCollection(); if (DEBUG) { super.printLayout(); } } private void testUnloadShardAndCollection() throws Exception{ // create one leader and one replica Create createCmd = new Create(); createCmd.setCoreName("test_unload_shard_and_collection_1"); String collection = "test_unload_shard_and_collection"; createCmd.setCollection(collection); String coreDataDir = dataDir.getAbsolutePath() + File.separator + System.currentTimeMillis() + collection + "1"; createCmd.setDataDir(getDataDir(coreDataDir)); createCmd.setNumShards(2); SolrServer client = clients.get(0); String url1 = getBaseUrl(client); HttpSolrServer server = new HttpSolrServer(url1); server.setConnectionTimeout(15000); server.setSoTimeout(60000); server.request(createCmd); createCmd = new Create(); createCmd.setCoreName("test_unload_shard_and_collection_2"); collection = "test_unload_shard_and_collection"; createCmd.setCollection(collection); coreDataDir = dataDir.getAbsolutePath() + File.separator + System.currentTimeMillis() + collection + "2"; createCmd.setDataDir(getDataDir(coreDataDir)); server.request(createCmd); // does not mean they are active and up yet :* waitForRecoveriesToFinish(collection, false); // now unload one of the two Unload unloadCmd = new Unload(false); unloadCmd.setCoreName("test_unload_shard_and_collection_2"); server.request(unloadCmd); // there should be only one shard int slices = getCommonCloudSolrServer().getZkStateReader().getClusterState().getSlices(collection).size(); long timeoutAt = System.currentTimeMillis() + 45000; while (slices != 1) { if (System.currentTimeMillis() > timeoutAt) { printLayout(); fail("Expected to find only one slice in " + collection); } Thread.sleep(1000); slices = getCommonCloudSolrServer().getZkStateReader().getClusterState().getSlices(collection).size(); } // now unload one of the other unloadCmd = new Unload(false); unloadCmd.setCoreName("test_unload_shard_and_collection_1"); server.request(unloadCmd); //printLayout(); // the collection should be gone timeoutAt = System.currentTimeMillis() + 30000; while (getCommonCloudSolrServer().getZkStateReader().getClusterState().hasCollection(collection)) { if (System.currentTimeMillis() > timeoutAt) { printLayout(); fail("Still found collection"); } Thread.sleep(50); } } /** * @throws Exception on any problem */ private void testCoreUnloadAndLeaders() throws Exception { // create a new collection collection SolrServer client = clients.get(0); String url1 = getBaseUrl(client); HttpSolrServer server = new HttpSolrServer(url1); server.setConnectionTimeout(15000); server.setSoTimeout(60000); Create createCmd = new Create(); createCmd.setCoreName("unloadcollection1"); createCmd.setCollection("unloadcollection"); createCmd.setNumShards(1); String core1DataDir = dataDir.getAbsolutePath() + File.separator + System.currentTimeMillis() + "unloadcollection1" + "_1n"; createCmd.setDataDir(getDataDir(core1DataDir)); server.request(createCmd); ZkStateReader zkStateReader = getCommonCloudSolrServer().getZkStateReader(); zkStateReader.updateClusterState(true); int slices = zkStateReader.getClusterState().getCollection("unloadcollection").getSlices().size(); assertEquals(1, slices); client = clients.get(1); String url2 = getBaseUrl(client); server = new HttpSolrServer(url2); createCmd = new Create(); createCmd.setCoreName("unloadcollection2"); createCmd.setCollection("unloadcollection"); String core2dataDir = dataDir.getAbsolutePath() + File.separator + System.currentTimeMillis() + "unloadcollection1" + "_2n"; createCmd.setDataDir(getDataDir(core2dataDir)); server.request(createCmd); zkStateReader.updateClusterState(true); slices = zkStateReader.getClusterState().getCollection("unloadcollection").getSlices().size(); assertEquals(1, slices); waitForRecoveriesToFinish("unloadcollection", zkStateReader, false); ZkCoreNodeProps leaderProps = getLeaderUrlFromZk("unloadcollection", "shard1"); Random random = random(); HttpSolrServer collectionClient; if (random.nextBoolean()) { collectionClient = new HttpSolrServer(leaderProps.getCoreUrl()); // lets try and use the solrj client to index and retrieve a couple // documents SolrInputDocument doc1 = getDoc(id, 6, i1, -600, tlong, 600, t1, "humpty dumpy sat on a wall"); SolrInputDocument doc2 = getDoc(id, 7, i1, -600, tlong, 600, t1, "humpty dumpy3 sat on a walls"); SolrInputDocument doc3 = getDoc(id, 8, i1, -600, tlong, 600, t1, "humpty dumpy2 sat on a walled"); collectionClient.add(doc1); collectionClient.add(doc2); collectionClient.add(doc3); collectionClient.commit(); } // create another replica for our collection client = clients.get(2); String url3 = getBaseUrl(client); server = new HttpSolrServer(url3); createCmd = new Create(); createCmd.setCoreName("unloadcollection3"); createCmd.setCollection("unloadcollection"); String core3dataDir = dataDir.getAbsolutePath() + File.separator + System.currentTimeMillis() + "unloadcollection" + "_3n"; createCmd.setDataDir(getDataDir(core3dataDir)); server.request(createCmd); waitForRecoveriesToFinish("unloadcollection", zkStateReader, false); // so that we start with some versions when we reload... DirectUpdateHandler2.commitOnClose = false; HttpSolrServer addClient = new HttpSolrServer(url3 + "/unloadcollection3"); addClient.setConnectionTimeout(30000); // add a few docs for (int x = 20; x < 100; x++) { SolrInputDocument doc1 = getDoc(id, x, i1, -600, tlong, 600, t1, "humpty dumpy sat on a wall"); addClient.add(doc1); } // don't commit so they remain in the tran log //collectionClient.commit(); // unload the leader collectionClient = new HttpSolrServer(leaderProps.getBaseUrl()); collectionClient.setConnectionTimeout(15000); collectionClient.setSoTimeout(30000); Unload unloadCmd = new Unload(false); unloadCmd.setCoreName(leaderProps.getCoreName()); ModifiableSolrParams p = (ModifiableSolrParams) unloadCmd.getParams(); collectionClient.request(unloadCmd); // Thread.currentThread().sleep(500); // printLayout(); int tries = 50; while (leaderProps.getCoreUrl().equals(zkStateReader.getLeaderUrl("unloadcollection", "shard1", 15000))) { Thread.sleep(100); if (tries-- == 0) { fail("Leader never changed"); } } // ensure there is a leader zkStateReader.getLeaderRetry("unloadcollection", "shard1", 15000); addClient = new HttpSolrServer(url2 + "/unloadcollection2"); addClient.setConnectionTimeout(30000); addClient.setSoTimeout(90000); // add a few docs while the leader is down for (int x = 101; x < 200; x++) { SolrInputDocument doc1 = getDoc(id, x, i1, -600, tlong, 600, t1, "humpty dumpy sat on a wall"); addClient.add(doc1); } // create another replica for our collection client = clients.get(3); String url4 = getBaseUrl(client); server = new HttpSolrServer(url4); server.setConnectionTimeout(15000); server.setSoTimeout(30000); createCmd = new Create(); createCmd.setCoreName("unloadcollection4"); createCmd.setCollection("unloadcollection"); String core4dataDir = dataDir.getAbsolutePath() + File.separator + System.currentTimeMillis() + "unloadcollection" + "_4n"; createCmd.setDataDir(getDataDir(core4dataDir)); server.request(createCmd); waitForRecoveriesToFinish("unloadcollection", zkStateReader, false); // unload the leader again leaderProps = getLeaderUrlFromZk("unloadcollection", "shard1"); collectionClient = new HttpSolrServer(leaderProps.getBaseUrl()); collectionClient.setConnectionTimeout(15000); collectionClient.setSoTimeout(30000); unloadCmd = new Unload(false); unloadCmd.setCoreName(leaderProps.getCoreName()); p = (ModifiableSolrParams) unloadCmd.getParams(); collectionClient.request(unloadCmd); tries = 50; while (leaderProps.getCoreUrl().equals(zkStateReader.getLeaderUrl("unloadcollection", "shard1", 15000))) { Thread.sleep(100); if (tries-- == 0) { fail("Leader never changed"); } } zkStateReader.getLeaderRetry("unloadcollection", "shard1", 15000); // set this back DirectUpdateHandler2.commitOnClose = true; // bring the downed leader back as replica server = new HttpSolrServer(leaderProps.getBaseUrl()); server.setConnectionTimeout(15000); server.setSoTimeout(30000); createCmd = new Create(); createCmd.setCoreName(leaderProps.getCoreName()); createCmd.setCollection("unloadcollection"); createCmd.setDataDir(getDataDir(core1DataDir)); server.request(createCmd); waitForRecoveriesToFinish("unloadcollection", zkStateReader, false); server = new HttpSolrServer(url2 + "/unloadcollection"); server.setConnectionTimeout(15000); server.setSoTimeout(30000); server.commit(); SolrQuery q = new SolrQuery("*:*"); q.set("distrib", false); long found1 = server.query(q).getResults().getNumFound(); server = new HttpSolrServer(url3 + "/unloadcollection"); server.setConnectionTimeout(15000); server.setSoTimeout(30000); server.commit(); q = new SolrQuery("*:*"); q.set("distrib", false); long found3 = server.query(q).getResults().getNumFound(); server = new HttpSolrServer(url4 + "/unloadcollection"); server.setConnectionTimeout(15000); server.setSoTimeout(30000); server.commit(); q = new SolrQuery("*:*"); q.set("distrib", false); long found4 = server.query(q).getResults().getNumFound(); // all 3 shards should now have the same number of docs assertEquals(found1, found3); assertEquals(found3, found4); } private void testUnloadLotsOfCores() throws Exception { SolrServer client = clients.get(2); String url3 = getBaseUrl(client); final HttpSolrServer server = new HttpSolrServer(url3); server.setConnectionTimeout(15000); server.setSoTimeout(60000); ThreadPoolExecutor executor = new ThreadPoolExecutor(0, Integer.MAX_VALUE, 5, TimeUnit.SECONDS, new SynchronousQueue<Runnable>(), new DefaultSolrThreadFactory("testExecutor")); int cnt = atLeast(3); // create the cores createCores(server, executor, "multiunload", 2, cnt); executor.shutdown(); executor.awaitTermination(120, TimeUnit.SECONDS); executor = new ThreadPoolExecutor(0, Integer.MAX_VALUE, 5, TimeUnit.SECONDS, new SynchronousQueue<Runnable>(), new DefaultSolrThreadFactory("testExecutor")); for (int j = 0; j < cnt; j++) { final int freezeJ = j; executor.execute(new Runnable() { @Override public void run() { Unload unloadCmd = new Unload(true); unloadCmd.setCoreName("multiunload" + freezeJ); try { server.request(unloadCmd); } catch (SolrServerException e) { throw new RuntimeException(e); } catch (IOException e) { throw new RuntimeException(e); } } }); Thread.sleep(random().nextInt(50)); } executor.shutdown(); executor.awaitTermination(120, TimeUnit.SECONDS); } @Override public void tearDown() throws Exception { super.tearDown(); } }