diff --git a/solr/core/src/java/org/apache/solr/cloud/api/collections/SplitShardCmd.java b/solr/core/src/java/org/apache/solr/cloud/api/collections/SplitShardCmd.java index 1922843934bb..96604b347ee0 100644 --- a/solr/core/src/java/org/apache/solr/cloud/api/collections/SplitShardCmd.java +++ b/solr/core/src/java/org/apache/solr/cloud/api/collections/SplitShardCmd.java @@ -61,7 +61,10 @@ import static org.apache.solr.common.params.CommonAdminParams.ASYNC; import static org.apache.solr.common.params.CommonAdminParams.NUM_SUB_SHARDS; - +/** + * Index split request processed by Overseer. Requests from here go to the host of the parent shard, + * and are processed by SplitOp. + */ public class SplitShardCmd implements CollApiCmds.CollectionApiCommand { private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass()); private static final int MIN_NUM_SUB_SHARDS = 2; @@ -81,16 +84,35 @@ public void call(ClusterState state, ZkNodeProps message, @SuppressWarnings({"ra split(state, message,(NamedList) results); } + /** + * Shard splits start here and make additional requests to the host of the parent shard. + * + * The sequence of requests is as follows: + * + */ @SuppressWarnings({"rawtypes"}) public boolean split(ClusterState clusterState, ZkNodeProps message, NamedList results) throws Exception { final String asyncId = message.getStr(ASYNC); + // get split method, or default to LINK if unspecified boolean waitForFinalState = message.getBool(CommonAdminParams.WAIT_FOR_FINAL_STATE, false); - String methodStr = message.getStr(CommonAdminParams.SPLIT_METHOD, SolrIndexSplitter.SplitMethod.REWRITE.toLower()); + String methodStr = message.getStr(CommonAdminParams.SPLIT_METHOD, SolrIndexSplitter.SplitMethod.LINK.toLower()); SolrIndexSplitter.SplitMethod splitMethod = SolrIndexSplitter.SplitMethod.get(methodStr); if (splitMethod == null) { throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, "Unknown value '" + CommonAdminParams.SPLIT_METHOD + - ": " + methodStr); + "': " + methodStr); } boolean withTiming = message.getBool(CommonParams.TIMING, false); @@ -115,7 +137,7 @@ public boolean split(ClusterState clusterState, ZkNodeProps message, NamedList nodes = clusterState.getLiveNodes(); - List nodeList = new ArrayList<>(nodes.size()); - nodeList.addAll(nodes); - - // Remove the node that hosts the parent shard for replica creation. - nodeList.remove(nodeName); - // TODO: change this to handle sharding a slice into > 2 sub-shards. // we have already created one subReplica for each subShard on the parent node. @@ -550,6 +566,7 @@ public boolean split(ClusterState clusterState, ZkNodeProps message, NamedList 1, set shard state for sub-shards to RECOVERY; otherwise mark ACTIVE if (repFactor == 1) { // A commit is needed so that documents are visible when the sub-shard replicas come up // (Note: This commit used to be after the state switch, but was brought here before the state switch @@ -619,6 +636,10 @@ public boolean split(ClusterState clusterState, ZkNodeProps message, NamedList + *
  • No override specified. Verify that LINK method is used.
  • + *
  • REWRITE method specified. Verify that LINK steps are skipped.
  • + *
  • Invalid override specified. Verify that split fails.
  • + * + */ + @Test + public void testSplitMethods() throws Exception { + CollectionAdminRequest + .createCollection(COLLECTION_NAME, "conf", 3, 1) + .process(cluster.getSolrClient()); + + cluster.waitForActiveCollection(COLLECTION_NAME, 3, 3); + + CollectionAdminRequest.SplitShard splitShard = CollectionAdminRequest.splitShard(COLLECTION_NAME) + .setShardName("shard1"); + SolrResponse response = splitShard.process(cluster.getSolrClient()); + MatcherAssert.assertThat("LINK split method is default, so split response should contain link timings.", + response.getResponse().toString().contains("hardLinkCopy"), Matchers.equalTo(true)); + + waitForState("Timed out waiting for sub shards to be active. Number of active shards=" + + cluster.getSolrClient().getZkStateReader().getClusterState().getCollection(COLLECTION_NAME).getActiveSlices().size(), + COLLECTION_NAME, activeClusterShape(4, 5)); + + splitShard = CollectionAdminRequest.splitShard(COLLECTION_NAME) + .setNumSubShards(2) + .setShardName("shard2") + .setSplitMethod(SolrIndexSplitter.SplitMethod.REWRITE.name()); + response = splitShard.process(cluster.getSolrClient()); + MatcherAssert.assertThat("REWRITE split method was specified, so split response should NOT contain link timings.", + response.getResponse().toString().contains("hardLinkCopy"), Matchers.equalTo(false)); + + waitForState("Timed out waiting for sub shards to be active. Number of active shards=" + + cluster.getSolrClient().getZkStateReader().getClusterState().getCollection(COLLECTION_NAME).getActiveSlices().size(), + COLLECTION_NAME, activeClusterShape(5, 7)); + + try { + splitShard = CollectionAdminRequest.splitShard(COLLECTION_NAME) + .setShardName("shard3") + .setSplitMethod("HELLO"); + splitShard.process(cluster.getSolrClient()); + fail("SplitShard should throw an exception when splitMethod is anything other than LINK or REWRITE"); + } catch (BaseHttpSolrClient.RemoteSolrException ex) { + MatcherAssert.assertThat("Invalid split method HELLO was specified, so split should fail.", + ex.getMessage().contains("Unknown value 'splitMethod': HELLO"), Matchers.equalTo(true)); + } + } + @Test public void multipleOptionsSplitTest() throws IOException, SolrServerException { CollectionAdminRequest.SplitShard splitShard = CollectionAdminRequest.splitShard(COLLECTION_NAME)