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.IOException; 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.ConcurrentUpdateSolrServer; import org.apache.solr.client.solrj.impl.HttpSolrServer; import org.apache.solr.client.solrj.request.UpdateRequest; import org.apache.solr.client.solrj.response.QueryResponse; import org.apache.solr.common.SolrDocument; import org.apache.solr.common.SolrException; import org.apache.solr.common.SolrInputDocument; import org.apache.solr.common.cloud.SolrZkClient; import org.apache.solr.common.cloud.ZkNodeProps; import org.apache.solr.common.cloud.ZkStateReader; import org.apache.solr.common.params.ModifiableSolrParams; import org.apache.solr.update.VersionInfo; import org.apache.solr.update.processor.DistributedUpdateProcessor; import org.apache.zookeeper.CreateMode; import org.junit.BeforeClass; /** * Super basic testing, no shard restarting or anything. */ @Slow public class FullSolrCloudDistribCmdsTest extends AbstractFullDistribZkTestBase { @BeforeClass public static void beforeSuperClass() { } public FullSolrCloudDistribCmdsTest() { super(); shardCount = 4; sliceCount = 2; } @Override public void doTest() throws Exception { handle.clear(); handle.put("QTime", SKIPVAL); handle.put("timestamp", SKIPVAL); waitForRecoveriesToFinish(false); // add a doc, update it, and delete it QueryResponse results; UpdateRequest uReq; long docId = addUpdateDelete(); // add 2 docs in a request SolrInputDocument doc1; SolrInputDocument doc2; docId = addTwoDocsInOneRequest(docId); // two deletes uReq = new UpdateRequest(); uReq.deleteById(Long.toString(docId-1)); uReq.deleteById(Long.toString(docId-2)).process(cloudClient); controlClient.deleteById(Long.toString(docId-1)); controlClient.deleteById(Long.toString(docId-2)); commit(); results = query(cloudClient); assertEquals(0, results.getResults().getNumFound()); results = query(controlClient); assertEquals(0, results.getResults().getNumFound()); // add two docs together, a 3rd doc and a delete indexr("id", docId++, t1, "originalcontent"); uReq = new UpdateRequest(); doc1 = new SolrInputDocument(); addFields(doc1, "id", docId++); uReq.add(doc1); doc2 = new SolrInputDocument(); addFields(doc2, "id", docId++); uReq.add(doc2); uReq.process(cloudClient); uReq.process(controlClient); uReq = new UpdateRequest(); uReq.deleteById(Long.toString(docId - 2)).process(cloudClient); controlClient.deleteById(Long.toString(docId - 2)); commit(); assertDocCounts(VERBOSE); checkShardConsistency(); results = query(controlClient); assertEquals(2, results.getResults().getNumFound()); results = query(cloudClient); assertEquals(2, results.getResults().getNumFound()); testIndexingWithSuss(); // TODO: testOptimisticUpdate(results); testDeleteByQueryDistrib(); testThatCantForwardToLeaderFails(); } private void testThatCantForwardToLeaderFails() throws Exception { ZkNodeProps props = zkStateReader.getLeaderProps(DEFAULT_COLLECTION, "shard1"); chaosMonkey.stopShard("shard1"); // fake that the leader is still advertised String leaderPath = ZkStateReader.getShardLeadersPath(DEFAULT_COLLECTION, "shard1"); SolrZkClient zkClient = new SolrZkClient(zkServer.getZkAddress(), 10000); int fails = 0; try { zkClient.makePath(leaderPath, ZkStateReader.toJSON(props), CreateMode.EPHEMERAL, true); for (int i = 200; i < 210; i++) { try { index_specific(cloudClient, id, i); } catch (SolrException e) { // expected fails++; break; } catch (SolrServerException e) { // expected fails++; break; } } } finally { zkClient.close(); } assertTrue("A whole shard is down - some of these should fail", fails > 0); } private long addTwoDocsInOneRequest(long docId) throws Exception { QueryResponse results; UpdateRequest uReq; uReq = new UpdateRequest(); //uReq.setParam(UpdateParams.UPDATE_CHAIN, DISTRIB_UPDATE_CHAIN); SolrInputDocument doc1 = new SolrInputDocument(); addFields(doc1, "id", docId++); uReq.add(doc1); SolrInputDocument doc2 = new SolrInputDocument(); addFields(doc2, "id", docId++); uReq.add(doc2); uReq.process(cloudClient); uReq.process(controlClient); commit(); checkShardConsistency(); assertDocCounts(VERBOSE); results = query(cloudClient); assertEquals(2, results.getResults().getNumFound()); return docId; } private long addUpdateDelete() throws Exception, IOException { long docId = 99999999L; indexr("id", docId, t1, "originalcontent"); commit(); ModifiableSolrParams params = new ModifiableSolrParams(); params.add("q", t1 + ":originalcontent"); QueryResponse results = clients.get(0).query(params); assertEquals(1, results.getResults().getNumFound()); // update doc indexr("id", docId, t1, "updatedcontent"); commit(); assertDocCounts(VERBOSE); results = clients.get(0).query(params); assertEquals(0, results.getResults().getNumFound()); params.set("q", t1 + ":updatedcontent"); results = clients.get(0).query(params); assertEquals(1, results.getResults().getNumFound()); UpdateRequest uReq = new UpdateRequest(); //uReq.setParam(UpdateParams.UPDATE_CHAIN, DISTRIB_UPDATE_CHAIN); uReq.deleteById(Long.toString(docId)).process(clients.get(0)); commit(); results = clients.get(0).query(params); assertEquals(0, results.getResults().getNumFound()); return docId; } private void testDeleteByQueryDistrib() throws Exception { del("*:*"); commit(); assertEquals(0, query(cloudClient).getResults().getNumFound()); } private void testIndexingWithSuss() throws Exception { ConcurrentUpdateSolrServer suss = new ConcurrentUpdateSolrServer( ((HttpSolrServer) clients.get(0)).getBaseURL(), 3, 1); for (int i=100; i<150; i++) { index_specific(suss, id, i); } suss.blockUntilFinished(); commit(); checkShardConsistency(); } private void testOptimisticUpdate(QueryResponse results) throws Exception { SolrDocument doc = results.getResults().get(0); System.out.println("version:" + doc.getFieldValue(VersionInfo.VERSION_FIELD)); Long version = (Long) doc.getFieldValue(VersionInfo.VERSION_FIELD); Integer theDoc = (Integer) doc.getFieldValue("id"); UpdateRequest uReq = new UpdateRequest(); SolrInputDocument doc1 = new SolrInputDocument(); uReq.setParams(new ModifiableSolrParams()); uReq.getParams().set(DistributedUpdateProcessor.VERSION_FIELD, Long.toString(version)); addFields(doc1, "id", theDoc, t1, "theupdatestuff"); uReq.add(doc1); uReq.process(cloudClient); uReq.process(controlClient); commit(); // updating the old version should fail... SolrInputDocument doc2 = new SolrInputDocument(); uReq = new UpdateRequest(); uReq.setParams(new ModifiableSolrParams()); uReq.getParams().set(DistributedUpdateProcessor.VERSION_FIELD, Long.toString(version)); addFields(doc2, "id", theDoc, t1, "thenewupdatestuff"); uReq.add(doc2); uReq.process(cloudClient); uReq.process(controlClient); commit(); ModifiableSolrParams params = new ModifiableSolrParams(); params.add("q", t1 + ":thenewupdatestuff"); QueryResponse res = clients.get(0).query(params); assertEquals(0, res.getResults().getNumFound()); params = new ModifiableSolrParams(); params.add("q", t1 + ":theupdatestuff"); res = clients.get(0).query(params); assertEquals(1, res.getResults().getNumFound()); } private QueryResponse query(SolrServer server) throws SolrServerException { SolrQuery query = new SolrQuery("*:*"); return server.query(query); } @Override public void tearDown() throws Exception { super.tearDown(); } }