diff --git a/dev-tools/maven/pom.xml.template b/dev-tools/maven/pom.xml.template
index effbea39c2f..e0cb50e86f9 100644
--- a/dev-tools/maven/pom.xml.template
+++ b/dev-tools/maven/pom.xml.template
@@ -368,7 +368,8 @@
org.easymock
easymock
- 2.2
+ 3.0
+ test
org.eclipse.jetty
diff --git a/solr/core/ivy.xml b/solr/core/ivy.xml
index b740a271582..93c63170dcf 100644
--- a/solr/core/ivy.xml
+++ b/solr/core/ivy.xml
@@ -25,7 +25,9 @@
-
+
+
+
diff --git a/solr/core/src/java/org/apache/solr/cloud/OverseerCollectionProcessor.java b/solr/core/src/java/org/apache/solr/cloud/OverseerCollectionProcessor.java
index 9887549c038..6ca21d2e041 100644
--- a/solr/core/src/java/org/apache/solr/cloud/OverseerCollectionProcessor.java
+++ b/solr/core/src/java/org/apache/solr/cloud/OverseerCollectionProcessor.java
@@ -77,11 +77,15 @@ public class OverseerCollectionProcessor implements Runnable {
private boolean isClosed;
public OverseerCollectionProcessor(ZkStateReader zkStateReader, String myId, ShardHandler shardHandler, String adminPath) {
+ this(zkStateReader, myId, shardHandler, adminPath, Overseer.getCollectionQueue(zkStateReader.getZkClient()));
+ }
+
+ protected OverseerCollectionProcessor(ZkStateReader zkStateReader, String myId, ShardHandler shardHandler, String adminPath, DistributedQueue workQueue) {
this.zkStateReader = zkStateReader;
this.myId = myId;
this.shardHandler = shardHandler;
this.adminPath = adminPath;
- workQueue = Overseer.getCollectionQueue(zkStateReader.getZkClient());
+ this.workQueue = workQueue;
}
@Override
@@ -130,7 +134,7 @@ public class OverseerCollectionProcessor implements Runnable {
isClosed = true;
}
- private boolean amILeader() {
+ protected boolean amILeader() {
try {
ZkNodeProps props = ZkNodeProps.load(zkStateReader.getZkClient().getData(
"/overseer_elect/leader", null, null, true));
diff --git a/solr/core/src/java/org/apache/solr/core/SolrCore.java b/solr/core/src/java/org/apache/solr/core/SolrCore.java
index 71320818965..355b7400c4a 100644
--- a/solr/core/src/java/org/apache/solr/core/SolrCore.java
+++ b/solr/core/src/java/org/apache/solr/core/SolrCore.java
@@ -2203,6 +2203,7 @@ public final class SolrCore implements SolrInfoMBean {
lst.add("coreName", name==null ? "(null)" : name);
lst.add("startTime", new Date(startTime));
lst.add("refCount", getOpenCount());
+ lst.add("indexDir", getIndexDir());
CoreDescriptor cd = getCoreDescriptor();
if (cd != null) {
diff --git a/solr/core/src/test/org/apache/solr/cloud/BasicDistributedZkTest.java b/solr/core/src/test/org/apache/solr/cloud/BasicDistributedZkTest.java
index f41ddac5b11..fb192a3b362 100644
--- a/solr/core/src/test/org/apache/solr/cloud/BasicDistributedZkTest.java
+++ b/solr/core/src/test/org/apache/solr/cloud/BasicDistributedZkTest.java
@@ -19,11 +19,13 @@ package org.apache.solr.cloud;
import java.io.File;
import java.io.IOException;
+import java.lang.management.ManagementFactory;
import java.net.MalformedURLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
+import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
@@ -37,6 +39,10 @@ import java.util.concurrent.SynchronousQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
+import javax.management.MBeanServer;
+import javax.management.MBeanServerFactory;
+import javax.management.ObjectName;
+
import org.apache.lucene.util.LuceneTestCase.Slow;
import org.apache.lucene.util._TestUtil;
import org.apache.solr.JSONTestUtil;
@@ -71,6 +77,8 @@ import org.apache.solr.common.params.CommonParams;
import org.apache.solr.common.params.ModifiableSolrParams;
import org.apache.solr.common.params.UpdateParams;
import org.apache.solr.common.util.NamedList;
+import org.apache.solr.core.SolrCore;
+import org.apache.solr.core.SolrInfoMBean.Category;
import org.apache.solr.update.DirectUpdateHandler2;
import org.apache.solr.update.SolrCmdDistributor.Request;
import org.apache.solr.util.DefaultSolrThreadFactory;
@@ -876,8 +884,11 @@ public class BasicDistributedZkTest extends AbstractFullDistribZkTestBase {
collectionInfos = new HashMap>();
createCollection(collectionInfos, cnt, numShards, replicationFactor, maxShardsPerNode);
- // TODO: enable this check after removing the 60 second wait in it
- //checkCollectionIsNotCreated(collectionInfos.keySet().iterator().next());
+ // TODO: REMOVE THE SLEEP IN THE METHOD CALL WHEN WE HAVE COLLECTION API
+ // RESPONSES
+ checkCollectionIsNotCreated(collectionInfos.keySet().iterator().next());
+
+ checkNoTwoShardsUseTheSameIndexDir();
}
@@ -1076,8 +1087,8 @@ public class BasicDistributedZkTest extends AbstractFullDistribZkTestBase {
private void checkCollectionIsNotCreated(String collectionName)
throws Exception {
- // TODO: this method not called because of below sleep
- Thread.sleep(60000);
+ // TODO: REMOVE THIS SLEEP WHEN WE HAVE COLLECTION API RESPONSES
+ Thread.sleep(10000);
assertFalse(collectionName + " not supposed to exist", getCommonCloudSolrServer().getZkStateReader().getClusterState().getCollections().contains(collectionName));
}
@@ -1499,6 +1510,44 @@ public class BasicDistributedZkTest extends AbstractFullDistribZkTestBase {
assertEquals(collection3Docs, collection2Docs - 1);
}
+ private void checkNoTwoShardsUseTheSameIndexDir() throws Exception {
+ Map> indexDirToShardNamesMap = new HashMap>();
+
+ List servers = new LinkedList();
+ servers.add(ManagementFactory.getPlatformMBeanServer());
+ servers.addAll(MBeanServerFactory.findMBeanServer(null));
+ for (final MBeanServer server : servers) {
+ Set mbeans = new HashSet();
+ mbeans.addAll(server.queryNames(null, null));
+ for (final ObjectName mbean : mbeans) {
+ Object value;
+ Object indexDir;
+ Object name;
+ try {
+ if (((value = server.getAttribute(mbean, "category")) != null && value.toString().equals(Category.CORE.toString())) &&
+ ((value = server.getAttribute(mbean, "source")) != null && value.toString().contains(SolrCore.class.getSimpleName())) &&
+ ((indexDir = server.getAttribute(mbean, "indexDir")) != null) &&
+ ((name = server.getAttribute(mbean, "name")) != null)) {
+ if (!indexDirToShardNamesMap.containsKey(indexDir.toString())) {
+ indexDirToShardNamesMap.put(indexDir.toString(), new HashSet());
+ }
+ indexDirToShardNamesMap.get(indexDir.toString()).add(name.toString());
+ }
+ } catch (Exception e) {
+ // ignore, just continue - probably a "category" or "source" attribute not found
+ }
+ }
+ }
+
+ assertTrue("Something is broken in the assert for no shards using the same indexDir - probably something was changed in the attributes published in the MBean of " + SolrCore.class.getSimpleName(), indexDirToShardNamesMap.size() > 0);
+ for (Entry> entry : indexDirToShardNamesMap.entrySet()) {
+ if (entry.getValue().size() > 1) {
+ fail("We have shards using the same indexDir. E.g. shards " + entry.getValue().toString() + " all use indexDir " + entry.getKey());
+ }
+ }
+
+ }
+
protected SolrInputDocument getDoc(Object... fields) throws Exception {
SolrInputDocument doc = new SolrInputDocument();
addFields(doc, fields);
diff --git a/solr/core/src/test/org/apache/solr/cloud/OverseerCollectionProcessorTest.java b/solr/core/src/test/org/apache/solr/cloud/OverseerCollectionProcessorTest.java
new file mode 100644
index 00000000000..54737e3643b
--- /dev/null
+++ b/solr/core/src/test/org/apache/solr/cloud/OverseerCollectionProcessorTest.java
@@ -0,0 +1,418 @@
+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 static org.easymock.EasyMock.capture;
+import static org.easymock.EasyMock.createMock;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.expectLastCall;
+import static org.easymock.EasyMock.replay;
+import static org.easymock.EasyMock.verify;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Queue;
+import java.util.Set;
+
+import org.apache.solr.SolrTestCaseJ4;
+import org.apache.solr.common.cloud.ClusterState;
+import org.apache.solr.common.cloud.ZkNodeProps;
+import org.apache.solr.common.cloud.ZkStateReader;
+import org.apache.solr.common.params.CoreAdminParams;
+import org.apache.solr.common.params.CoreAdminParams.CoreAdminAction;
+import org.apache.solr.common.params.ModifiableSolrParams;
+import org.apache.solr.handler.component.ShardHandler;
+import org.apache.solr.handler.component.ShardRequest;
+import org.apache.solr.handler.component.ShardResponse;
+import org.easymock.Capture;
+import org.easymock.IAnswer;
+import org.eclipse.jetty.util.BlockingArrayQueue;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+public class OverseerCollectionProcessorTest extends SolrTestCaseJ4 {
+
+ private static final String ADMIN_PATH = "/admin/cores";
+ private static final String COLLECTION_NAME = "mycollection";
+ private static final String CONFIG_NAME = "myconfig";
+
+ private OverseerCollectionProcessor underTest;
+ private DistributedQueue workQueueMock;
+ private ShardHandler shardHandlerMock;
+ private ZkStateReader zkStateReaderMock;
+ private ClusterState clusterStateMock;
+
+ private Thread thread;
+ private Queue queue = new BlockingArrayQueue();
+
+ private class OverseerCollectionProcessorToBeTested extends
+ OverseerCollectionProcessor {
+
+ public OverseerCollectionProcessorToBeTested(ZkStateReader zkStateReader,
+ String myId, ShardHandler shardHandler, String adminPath,
+ DistributedQueue workQueue) {
+ super(zkStateReader, myId, shardHandler, adminPath, workQueue);
+ }
+
+ @Override
+ protected boolean amILeader() {
+ return true;
+ }
+
+ }
+
+ @Before
+ public void setUp() throws Exception {
+ super.setUp();
+ workQueueMock = createMock(DistributedQueue.class);
+ shardHandlerMock = createMock(ShardHandler.class);
+ zkStateReaderMock = createMock(ZkStateReader.class);
+ clusterStateMock = createMock(ClusterState.class);
+ underTest = new OverseerCollectionProcessorToBeTested(zkStateReaderMock,
+ "1234", shardHandlerMock, ADMIN_PATH, workQueueMock);
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ underTest.close();
+ thread.interrupt();
+ stopComponentUnderTest();
+ super.tearDown();
+ }
+
+ protected Set commonMocks(int liveNodesCount) throws Exception {
+ workQueueMock.peek(true);
+ expectLastCall().andAnswer(new IAnswer