You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lucene.apache.org by sh...@apache.org on 2015/04/15 17:05:06 UTC
svn commit: r1673813 - in /lucene/dev/trunk/solr: CHANGES.txt
core/src/java/org/apache/solr/servlet/SolrDispatchFilter.java
core/src/test/org/apache/solr/cloud/ConcurrentDeleteAndCreateCollectionTest.java
Author: shaie
Date: Wed Apr 15 15:05:06 2015
New Revision: 1673813
URL: http://svn.apache.org/r1673813
Log:
SOLR-7401: fixed NPE when concurrently creating and deleting collections
Added:
lucene/dev/trunk/solr/core/src/test/org/apache/solr/cloud/ConcurrentDeleteAndCreateCollectionTest.java (with props)
Modified:
lucene/dev/trunk/solr/CHANGES.txt
lucene/dev/trunk/solr/core/src/java/org/apache/solr/servlet/SolrDispatchFilter.java
Modified: lucene/dev/trunk/solr/CHANGES.txt
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/solr/CHANGES.txt?rev=1673813&r1=1673812&r2=1673813&view=diff
==============================================================================
--- lucene/dev/trunk/solr/CHANGES.txt (original)
+++ lucene/dev/trunk/solr/CHANGES.txt Wed Apr 15 15:05:06 2015
@@ -119,6 +119,9 @@ Bug Fixes
* SOLR-7385: The clusterstatus API now returns the config set used to create a collection
inside a 'configName' key. (Shai Erera, shalin)
+* SOLR-7401: Fixed a NullPointerException when concurrently creating and deleting collections,
+ while accessing other collections. (Shai Erera)
+
Optimizations
----------------------
Modified: lucene/dev/trunk/solr/core/src/java/org/apache/solr/servlet/SolrDispatchFilter.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/solr/core/src/java/org/apache/solr/servlet/SolrDispatchFilter.java?rev=1673813&r1=1673812&r2=1673813&view=diff
==============================================================================
--- lucene/dev/trunk/solr/core/src/java/org/apache/solr/servlet/SolrDispatchFilter.java (original)
+++ lucene/dev/trunk/solr/core/src/java/org/apache/solr/servlet/SolrDispatchFilter.java Wed Apr 15 15:05:06 2015
@@ -666,13 +666,13 @@ public class SolrDispatchFilter extends
slices = new ArrayList<>();
// look by core name
byCoreName = true;
- slices = getSlicesForCollections(clusterState, slices, true);
- if (slices == null || slices.size() == 0) {
- slices = getSlicesForCollections(clusterState, slices, false);
+ getSlicesForCollections(clusterState, slices, true);
+ if (slices.isEmpty()) {
+ getSlicesForCollections(clusterState, slices, false);
}
}
- if (slices == null || slices.size() == 0) {
+ if (slices.isEmpty()) {
return null;
}
@@ -723,17 +723,23 @@ public class SolrDispatchFilter extends
return null;
}
- private Collection<Slice> getSlicesForCollections(ClusterState clusterState,
+ private void getSlicesForCollections(ClusterState clusterState,
Collection<Slice> slices, boolean activeSlices) {
- Set<String> collections = clusterState.getCollections();
- for (String collection : collections) {
- if (activeSlices) {
- slices.addAll(clusterState.getActiveSlices(collection));
- } else {
- slices.addAll(clusterState.getSlices(collection));
+ if (activeSlices) {
+ for (String collection : clusterState.getCollections()) {
+ final Collection<Slice> activeCollectionSlices = clusterState.getActiveSlices(collection);
+ if (activeCollectionSlices != null) {
+ slices.addAll(activeCollectionSlices);
+ }
+ }
+ } else {
+ for (String collection : clusterState.getCollections()) {
+ final Collection<Slice> collectionSlices = clusterState.getSlices(collection);
+ if (collectionSlices != null) {
+ slices.addAll(collectionSlices);
+ }
}
}
- return slices;
}
private SolrCore getCoreByCollection(CoreContainer cores, String corename) {
Added: lucene/dev/trunk/solr/core/src/test/org/apache/solr/cloud/ConcurrentDeleteAndCreateCollectionTest.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/solr/core/src/test/org/apache/solr/cloud/ConcurrentDeleteAndCreateCollectionTest.java?rev=1673813&view=auto
==============================================================================
--- lucene/dev/trunk/solr/core/src/test/org/apache/solr/cloud/ConcurrentDeleteAndCreateCollectionTest.java (added)
+++ lucene/dev/trunk/solr/core/src/test/org/apache/solr/cloud/ConcurrentDeleteAndCreateCollectionTest.java Wed Apr 15 15:05:06 2015
@@ -0,0 +1,168 @@
+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.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicReference;
+
+import org.apache.solr.SolrTestCaseJ4;
+import org.apache.solr.client.solrj.SolrClient;
+import org.apache.solr.client.solrj.SolrQuery;
+import org.apache.solr.client.solrj.SolrServerException;
+import org.apache.solr.client.solrj.impl.HttpSolrClient;
+import org.apache.solr.client.solrj.request.CollectionAdminRequest;
+import org.apache.solr.client.solrj.response.CollectionAdminResponse;
+import org.apache.zookeeper.KeeperException;
+import org.junit.After;
+import org.junit.Before;
+
+public class ConcurrentDeleteAndCreateCollectionTest extends SolrTestCaseJ4 {
+
+ private MiniSolrCloudCluster solrCluster;
+
+ @Override
+ @Before
+ public void setUp() throws Exception {
+ super.setUp();
+ final File solrXml = getFile("solrj").toPath().resolve("solr/solr.xml").toFile();
+ solrCluster = new MiniSolrCloudCluster(1, createTempDir().toFile(), solrXml, buildJettyConfig("/solr"));
+ }
+
+ @Override
+ @After
+ public void tearDown() throws Exception {
+ solrCluster.shutdown();
+ super.tearDown();
+ }
+
+ public void testConcurrentCreateAndDeleteDoesNotFail() {
+ final File configDir = getFile("solrj").toPath().resolve("solr/configsets/configset-2/conf").toFile();
+ final AtomicReference<Exception> failure = new AtomicReference<>();
+ final int timeToRunSec = 30;
+ final Thread[] threads = new Thread[10];
+ for (int i = 0; i < threads.length; i++) {
+ final String collectionName = "collection" + i;
+ uploadConfig(configDir, collectionName);
+ final SolrClient solrClient = new HttpSolrClient(solrCluster.getJettySolrRunners().get(0).getBaseUrl().toString());
+ threads[i] = new CreateDeleteCollectionThread("create-delete-" + i, collectionName, timeToRunSec, solrClient, failure);
+ }
+
+ startAll(threads);
+ joinAll(threads);
+
+ assertNull("concurrent create and delete collection failed: " + failure.get(), failure.get());
+ }
+
+ private void uploadConfig(File configDir, String configName) {
+ try {
+ solrCluster.uploadConfigDir(configDir, configName);
+ } catch (IOException | KeeperException | InterruptedException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ private void joinAll(final Thread[] threads) {
+ for (Thread t : threads) {
+ try {
+ t.join();
+ } catch (InterruptedException e) {
+ Thread.interrupted();
+ throw new RuntimeException(e);
+ }
+ }
+ }
+
+ private void startAll(final Thread[] threads) {
+ for (Thread t : threads) {
+ t.start();
+ }
+ }
+
+ private static class CreateDeleteCollectionThread extends Thread {
+ private final String collectionName;
+ private final long timeToRunSec;
+ private final SolrClient solrClient;
+ private final AtomicReference<Exception> failure;
+
+ public CreateDeleteCollectionThread(String name, String collectionName,
+ long timeToRunSec, SolrClient solrClient, AtomicReference<Exception> failure) {
+ super(name);
+ this.collectionName = collectionName;
+ this.timeToRunSec = timeToRunSec;
+ this.solrClient = solrClient;
+ this.failure = failure;
+ }
+
+ @Override
+ public void run() {
+ final long timeToStop = System.currentTimeMillis() + TimeUnit.SECONDS.toMillis(timeToRunSec);
+ while (System.currentTimeMillis() < timeToStop && failure.get() == null) {
+ createCollection(collectionName);
+ deleteCollection();
+ searchNonExistingCollection();
+ }
+ }
+
+ private void searchNonExistingCollection() {
+ try {
+ solrClient.query(collectionName, new SolrQuery("*"));
+ } catch (Exception e) {
+ if (!e.getMessage().contains("not found") && !e.getMessage().contains("Can not find")) {
+ synchronized (failure) {
+ if (failure.get() != null) {
+ failure.get().addSuppressed(e);
+ } else {
+ failure.set(e);
+ }
+ }
+ }
+ }
+ }
+
+ private void createCollection(String collectionName) {
+ try {
+ final CollectionAdminRequest.Create createCollectionRequest = new CollectionAdminRequest.Create();
+ createCollectionRequest.setCollectionName(collectionName);
+ createCollectionRequest.setNumShards(1);
+ createCollectionRequest.setReplicationFactor(1);
+ createCollectionRequest.setConfigName(collectionName);
+
+ final CollectionAdminResponse response = createCollectionRequest.process(solrClient);
+ assertEquals(0, response.getStatus());
+ } catch (IOException | SolrServerException e) {
+ throw new RuntimeException(e);
+ }
+
+ }
+
+ private void deleteCollection() {
+ try {
+ final CollectionAdminRequest.Delete deleteCollectionRequest = new CollectionAdminRequest.Delete();
+ deleteCollectionRequest.setCollectionName(collectionName);
+
+ final CollectionAdminResponse response = deleteCollectionRequest.process(solrClient);
+ assertEquals(0, response.getStatus());
+ } catch (IOException | SolrServerException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ }
+
+}
\ No newline at end of file