mirror of https://github.com/apache/lucene.git
SOLR-8983: Cleanup clusterstate in case of a failed CREATE collection call
This commit is contained in:
parent
9aefe193c9
commit
84a6ff697e
|
@ -129,6 +129,9 @@ Bug Fixes
|
||||||
|
|
||||||
* SOLR-9004: Fix "name" field type definition in films example. (Alexandre Rafalovitch via Varun Thacker)
|
* SOLR-9004: Fix "name" field type definition in films example. (Alexandre Rafalovitch via Varun Thacker)
|
||||||
|
|
||||||
|
* SOLR-8983: Cleanup clusterstate and replicas for a failed create collection request
|
||||||
|
(Varun Thacker, Anshum Gupta)
|
||||||
|
|
||||||
Optimizations
|
Optimizations
|
||||||
----------------------
|
----------------------
|
||||||
* SOLR-8722: Don't force a full ZkStateReader refresh on every Overseer operation.
|
* SOLR-8722: Don't force a full ZkStateReader refresh on every Overseer operation.
|
||||||
|
|
|
@ -1961,10 +1961,16 @@ public class OverseerCollectionMessageHandler implements OverseerMessageHandler
|
||||||
}
|
}
|
||||||
|
|
||||||
processResponses(results, shardHandler, false, null, async, requestMap, Collections.emptySet());
|
processResponses(results, shardHandler, false, null, async, requestMap, Collections.emptySet());
|
||||||
|
if(results.get("failure") != null && ((SimpleOrderedMap)results.get("failure")).size() > 0) {
|
||||||
log.debug("Finished create command on all shards for collection: "
|
// Let's cleanup as we hit an exception
|
||||||
+ collectionName);
|
// We shouldn't be passing 'results' here for the cleanup as the response would then contain 'success'
|
||||||
|
// element, which may be interpreted by the user as a positive ack
|
||||||
|
cleanupCollection(collectionName, new NamedList());
|
||||||
|
log.info("Cleaned up artifacts for failed create collection for [" + collectionName + "]");
|
||||||
|
} else {
|
||||||
|
log.debug("Finished create command on all shards for collection: "
|
||||||
|
+ collectionName);
|
||||||
|
}
|
||||||
} catch (SolrException ex) {
|
} catch (SolrException ex) {
|
||||||
throw ex;
|
throw ex;
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
|
@ -1972,6 +1978,15 @@ public class OverseerCollectionMessageHandler implements OverseerMessageHandler
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void cleanupCollection(String collectionName, NamedList results) throws KeeperException, InterruptedException {
|
||||||
|
log.error("Cleaning up collection [" + collectionName + "]." );
|
||||||
|
Map<String, Object> props = makeMap(
|
||||||
|
Overseer.QUEUE_OPERATION, DELETE.toLower(),
|
||||||
|
NAME, collectionName);
|
||||||
|
deleteCollection(new ZkNodeProps(props), results);
|
||||||
|
}
|
||||||
|
|
||||||
private Map<Position, String> identifyNodes(ClusterState clusterState,
|
private Map<Position, String> identifyNodes(ClusterState clusterState,
|
||||||
List<String> nodeList,
|
List<String> nodeList,
|
||||||
ZkNodeProps message,
|
ZkNodeProps message,
|
||||||
|
|
|
@ -26,8 +26,19 @@ import java.lang.management.ManagementFactory;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.nio.file.Paths;
|
import java.nio.file.Paths;
|
||||||
import java.util.*;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
|
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;
|
import java.util.Map.Entry;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.Properties;
|
||||||
|
import java.util.Set;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
import org.apache.lucene.util.LuceneTestCase.Slow;
|
import org.apache.lucene.util.LuceneTestCase.Slow;
|
||||||
|
@ -39,7 +50,6 @@ import org.apache.solr.client.solrj.SolrServerException;
|
||||||
import org.apache.solr.client.solrj.embedded.JettySolrRunner;
|
import org.apache.solr.client.solrj.embedded.JettySolrRunner;
|
||||||
import org.apache.solr.client.solrj.impl.CloudSolrClient;
|
import org.apache.solr.client.solrj.impl.CloudSolrClient;
|
||||||
import org.apache.solr.client.solrj.impl.HttpSolrClient;
|
import org.apache.solr.client.solrj.impl.HttpSolrClient;
|
||||||
import org.apache.solr.client.solrj.impl.HttpSolrClient.RemoteSolrException;
|
|
||||||
import org.apache.solr.client.solrj.request.CollectionAdminRequest;
|
import org.apache.solr.client.solrj.request.CollectionAdminRequest;
|
||||||
import org.apache.solr.client.solrj.request.CoreAdminRequest;
|
import org.apache.solr.client.solrj.request.CoreAdminRequest;
|
||||||
import org.apache.solr.client.solrj.request.CoreAdminRequest.Create;
|
import org.apache.solr.client.solrj.request.CoreAdminRequest.Create;
|
||||||
|
@ -375,6 +385,14 @@ public class CollectionsAPIDistributedZkTest extends AbstractFullDistribZkTestBa
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private NamedList<Object> makeRequest(String baseUrl, SolrRequest request, int socketTimeout)
|
||||||
|
throws SolrServerException, IOException {
|
||||||
|
try (SolrClient client = createNewSolrClient("", baseUrl)) {
|
||||||
|
((HttpSolrClient) client).setSoTimeout(socketTimeout);
|
||||||
|
return client.request(request);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private NamedList<Object> makeRequest(String baseUrl, SolrRequest request)
|
private NamedList<Object> makeRequest(String baseUrl, SolrRequest request)
|
||||||
throws SolrServerException, IOException {
|
throws SolrServerException, IOException {
|
||||||
try (SolrClient client = createNewSolrClient("", baseUrl)) {
|
try (SolrClient client = createNewSolrClient("", baseUrl)) {
|
||||||
|
@ -525,8 +543,7 @@ public class CollectionsAPIDistributedZkTest extends AbstractFullDistribZkTestBa
|
||||||
params.set(OverseerCollectionMessageHandler.CREATE_NODE_SET, nn1 + "," + nn2);
|
params.set(OverseerCollectionMessageHandler.CREATE_NODE_SET, nn1 + "," + nn2);
|
||||||
request = new QueryRequest(params);
|
request = new QueryRequest(params);
|
||||||
request.setPath("/admin/collections");
|
request.setPath("/admin/collections");
|
||||||
gotExp = false;
|
NamedList<Object> resp = makeRequest(baseUrl, request, 60000);
|
||||||
NamedList<Object> resp = makeRequest(baseUrl, request);;
|
|
||||||
|
|
||||||
SimpleOrderedMap success = (SimpleOrderedMap) resp.get("success");
|
SimpleOrderedMap success = (SimpleOrderedMap) resp.get("success");
|
||||||
SimpleOrderedMap failure = (SimpleOrderedMap) resp.get("failure");
|
SimpleOrderedMap failure = (SimpleOrderedMap) resp.get("failure");
|
||||||
|
|
|
@ -0,0 +1,84 @@
|
||||||
|
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.util.ArrayList;
|
||||||
|
import java.util.Properties;
|
||||||
|
|
||||||
|
import org.apache.solr.client.solrj.impl.CloudSolrClient;
|
||||||
|
import org.apache.solr.client.solrj.request.CollectionAdminRequest;
|
||||||
|
import org.apache.solr.client.solrj.response.CollectionAdminResponse;
|
||||||
|
import org.apache.solr.common.params.CoreAdminParams;
|
||||||
|
import org.junit.BeforeClass;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
public class CreateCollectionCleanupTest extends SolrCloudTestCase {
|
||||||
|
|
||||||
|
protected static final String CLOUD_SOLR_XML_WITH_10S_CREATE_COLL_WAIT = "<solr>\n" +
|
||||||
|
"\n" +
|
||||||
|
" <str name=\"shareSchema\">${shareSchema:false}</str>\n" +
|
||||||
|
" <str name=\"configSetBaseDir\">${configSetBaseDir:configsets}</str>\n" +
|
||||||
|
" <str name=\"coreRootDirectory\">${coreRootDirectory:.}</str>\n" +
|
||||||
|
"\n" +
|
||||||
|
" <shardHandlerFactory name=\"shardHandlerFactory\" class=\"HttpShardHandlerFactory\">\n" +
|
||||||
|
" <str name=\"urlScheme\">${urlScheme:}</str>\n" +
|
||||||
|
" <int name=\"socketTimeout\">${socketTimeout:90000}</int>\n" +
|
||||||
|
" <int name=\"connTimeout\">${connTimeout:15000}</int>\n" +
|
||||||
|
" </shardHandlerFactory>\n" +
|
||||||
|
"\n" +
|
||||||
|
" <solrcloud>\n" +
|
||||||
|
" <str name=\"host\">127.0.0.1</str>\n" +
|
||||||
|
" <int name=\"hostPort\">${hostPort:8983}</int>\n" +
|
||||||
|
" <str name=\"hostContext\">${hostContext:solr}</str>\n" +
|
||||||
|
" <int name=\"zkClientTimeout\">${solr.zkclienttimeout:30000}</int>\n" +
|
||||||
|
" <bool name=\"genericCoreNodeNames\">${genericCoreNodeNames:true}</bool>\n" +
|
||||||
|
" <int name=\"leaderVoteWait\">10000</int>\n" +
|
||||||
|
" <int name=\"distribUpdateConnTimeout\">${distribUpdateConnTimeout:45000}</int>\n" +
|
||||||
|
" <int name=\"distribUpdateSoTimeout\">${distribUpdateSoTimeout:340000}</int>\n" +
|
||||||
|
" <int name=\"createCollectionWaitTimeTillActive\">${createCollectionWaitTimeTillActive:10}</int>\n" +
|
||||||
|
" </solrcloud>\n" +
|
||||||
|
" \n" +
|
||||||
|
"</solr>\n";
|
||||||
|
|
||||||
|
|
||||||
|
@BeforeClass
|
||||||
|
public static void createCluster() throws Exception {
|
||||||
|
configureCluster(1)
|
||||||
|
.addConfig("conf1", TEST_PATH().resolve("configsets").resolve("cloud-minimal").resolve("conf"))
|
||||||
|
.withSolrXml(CLOUD_SOLR_XML_WITH_10S_CREATE_COLL_WAIT)
|
||||||
|
.configure();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCreateCollectionCleanup() throws Exception {
|
||||||
|
final CloudSolrClient cloudClient = cluster.getSolrClient();
|
||||||
|
// Create a collection that would fail
|
||||||
|
CollectionAdminRequest.Create create = CollectionAdminRequest.createCollection("foo","conf1",1,1);
|
||||||
|
|
||||||
|
Properties properties = new Properties();
|
||||||
|
properties.put(CoreAdminParams.DATA_DIR, "/some_invalid_dir/foo");
|
||||||
|
create.setProperties(properties);
|
||||||
|
CollectionAdminResponse rsp = create.process(cloudClient);
|
||||||
|
assertFalse(rsp.isSuccess());
|
||||||
|
|
||||||
|
// Confirm using LIST that the collection does not exist
|
||||||
|
CollectionAdminRequest.List list = CollectionAdminRequest.listCollections();
|
||||||
|
rsp = list.process(cloudClient);
|
||||||
|
assertFalse(((ArrayList) rsp.getResponse().get("collections")).contains("foo"));
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue