You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lucene.apache.org by an...@apache.org on 2014/08/13 09:41:54 UTC

svn commit: r1617673 - in /lucene/dev/trunk/solr: CHANGES.txt core/src/java/org/apache/solr/cloud/OverseerCollectionProcessor.java core/src/test/org/apache/solr/cloud/DeleteLastCustomShardedReplicaTest.java

Author: anshum
Date: Wed Aug 13 07:41:54 2014
New Revision: 1617673

URL: http://svn.apache.org/r1617673
Log:
SOLR-6347: Fix NPE during last replica deletion for custom sharded collections using DELETEREPLICA

Added:
    lucene/dev/trunk/solr/core/src/test/org/apache/solr/cloud/DeleteLastCustomShardedReplicaTest.java   (with props)
Modified:
    lucene/dev/trunk/solr/CHANGES.txt
    lucene/dev/trunk/solr/core/src/java/org/apache/solr/cloud/OverseerCollectionProcessor.java

Modified: lucene/dev/trunk/solr/CHANGES.txt
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/solr/CHANGES.txt?rev=1617673&r1=1617672&r2=1617673&view=diff
==============================================================================
--- lucene/dev/trunk/solr/CHANGES.txt (original)
+++ lucene/dev/trunk/solr/CHANGES.txt Wed Aug 13 07:41:54 2014
@@ -260,6 +260,8 @@ Bug Fixes
 * SOLR-6336: DistributedQueue can easily create too many ZooKeeper Watches.
   (Ramkumar Aiyengar via Mark Miller)
 
+* SOLR-6347: DELETEREPLICA throws a NPE while removing the last Replica in a Custom sharded collection.
+
 Optimizations
 ---------------------
 

Modified: lucene/dev/trunk/solr/core/src/java/org/apache/solr/cloud/OverseerCollectionProcessor.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/solr/core/src/java/org/apache/solr/cloud/OverseerCollectionProcessor.java?rev=1617673&r1=1617672&r2=1617673&view=diff
==============================================================================
--- lucene/dev/trunk/solr/core/src/java/org/apache/solr/cloud/OverseerCollectionProcessor.java (original)
+++ lucene/dev/trunk/solr/core/src/java/org/apache/solr/cloud/OverseerCollectionProcessor.java Wed Aug 13 07:41:54 2014
@@ -907,8 +907,15 @@ public class OverseerCollectionProcessor
     boolean deleted = false;
     while (System.nanoTime() < waitUntil) {
       Thread.sleep(100);
-      deleted = zkStateReader.getClusterState().getCollection(collectionName).getSlice(shard).getReplica(replicaName) == null;
-      if (deleted) break;
+      DocCollection docCollection = zkStateReader.getClusterState().getCollection(collectionName);
+      if(docCollection != null) {
+        Slice slice = docCollection.getSlice(shard);
+        if(slice == null || slice.getReplica(replicaName) == null) {
+          deleted =  true;
+        }
+      }
+      // Return true if either someone already deleted the collection/slice/replica.
+      if (docCollection == null || deleted) break;
     }
     return deleted;
   }

Added: lucene/dev/trunk/solr/core/src/test/org/apache/solr/cloud/DeleteLastCustomShardedReplicaTest.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/solr/core/src/test/org/apache/solr/cloud/DeleteLastCustomShardedReplicaTest.java?rev=1617673&view=auto
==============================================================================
--- lucene/dev/trunk/solr/core/src/test/org/apache/solr/cloud/DeleteLastCustomShardedReplicaTest.java (added)
+++ lucene/dev/trunk/solr/core/src/test/org/apache/solr/cloud/DeleteLastCustomShardedReplicaTest.java Wed Aug 13 07:41:54 2014
@@ -0,0 +1,138 @@
+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 org.apache.solr.client.solrj.SolrRequest;
+import org.apache.solr.client.solrj.SolrServerException;
+import org.apache.solr.client.solrj.impl.CloudSolrServer;
+import org.apache.solr.client.solrj.request.QueryRequest;
+import org.apache.solr.common.cloud.DocCollection;
+import org.apache.solr.common.cloud.ImplicitDocRouter;
+import org.apache.solr.common.cloud.Replica;
+import org.apache.solr.common.cloud.ZkNodeProps;
+import org.apache.solr.common.params.MapSolrParams;
+import org.apache.solr.common.params.SolrParams;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.BeforeClass;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import static org.apache.solr.cloud.OverseerCollectionProcessor.DELETEREPLICA;
+import static org.apache.solr.cloud.OverseerCollectionProcessor.MAX_SHARDS_PER_NODE;
+import static org.apache.solr.cloud.OverseerCollectionProcessor.NUM_SLICES;
+import static org.apache.solr.cloud.OverseerCollectionProcessor.REPLICATION_FACTOR;
+import static org.apache.solr.cloud.OverseerCollectionProcessor.SHARDS_PROP;
+import static org.apache.solr.common.cloud.ZkNodeProps.makeMap;
+
+public class DeleteLastCustomShardedReplicaTest extends AbstractFullDistribZkTestBase {
+  private CloudSolrServer client;
+
+  @BeforeClass
+  public static void beforeThisClass2() throws Exception {
+
+  }
+
+  @Before
+  @Override
+  public void setUp() throws Exception {
+    super.setUp();
+    System.setProperty("numShards", Integer.toString(sliceCount));
+    System.setProperty("solr.xml.persist", "true");
+    client = createCloudClient(null);
+  }
+
+  @After
+  public void tearDown() throws Exception {
+    super.tearDown();
+    client.shutdown();
+  }
+
+  protected String getSolrXml() {
+    return "solr-no-core.xml";
+  }
+
+  public DeleteLastCustomShardedReplicaTest() {
+    fixShardCount = true;
+
+    sliceCount = 2;
+    shardCount = 2;
+
+    checkCreatedVsState = false;
+  }
+
+  @Override
+  public void doTest() throws Exception {
+    int replicationFactor = 1;
+    int maxShardsPerNode = 5;
+
+    Map<String, Object> props = ZkNodeProps.makeMap(
+        "router.name", ImplicitDocRouter.NAME,
+        REPLICATION_FACTOR, replicationFactor,
+        MAX_SHARDS_PER_NODE, maxShardsPerNode,
+        NUM_SLICES, 1,
+        SHARDS_PROP,"a,b");
+
+    Map<String,List<Integer>> collectionInfos = new HashMap<>();
+
+    String collectionName = "customcollreplicadeletion";
+
+    createCollection(collectionInfos, collectionName, props, client);
+
+    waitForRecoveriesToFinish(collectionName, false);
+
+    DocCollection testcoll = getCommonCloudSolrServer().getZkStateReader()
+        .getClusterState().getCollection(collectionName);
+    Replica replica = testcoll.getSlice("a").getReplicas().iterator().next();
+
+    removeAndWaitForLastReplicaGone(collectionName, replica, "a");
+  }
+
+  protected void removeAndWaitForLastReplicaGone(String COLL_NAME, Replica replica, String shard)
+      throws SolrServerException, IOException, InterruptedException {
+    Map m = makeMap("collection", COLL_NAME, "action", DELETEREPLICA, "shard",
+        shard, "replica", replica.getName());
+    SolrParams params = new MapSolrParams(m);
+    SolrRequest request = new QueryRequest(params);
+    request.setPath("/admin/collections");
+    this.client.request(request);
+    long endAt = System.currentTimeMillis() + 3000;
+    boolean success = false;
+    DocCollection testcoll = null;
+    while (System.currentTimeMillis() < endAt) {
+      testcoll = getCommonCloudSolrServer().getZkStateReader()
+          .getClusterState().getCollection(COLL_NAME);
+      // In case of a custom sharded collection, the last replica deletion would also lead to
+      // the deletion of the slice.
+      success = testcoll.getSlice(shard) == null;
+      if (success) {
+        log.info("replica cleaned up {}/{} core {}",
+            shard + "/" + replica.getName(), replica.getStr("core"));
+        log.info("current state {}", testcoll);
+        break;
+      }
+      Thread.sleep(100);
+    }
+    assertTrue("Replica not cleaned up", success);
+  }
+
+}
+