mirror of https://github.com/apache/lucene.git
SOLR-13583: Impossible to delete a collection with the same name as an existing alias.
This commit is contained in:
parent
1c1d77a791
commit
30a5b2cd87
|
@ -216,6 +216,9 @@ Bug Fixes
|
|||
|
||||
* SOLR-13159: Fix atomic update encoding issue for UUID, enum, bool, and binary fields (Thomas Wockinger via Jason Gerlowski)
|
||||
|
||||
* SOLR-13583: Impossible to delete a collection with the same name as an existing alias. This fixes also a bug in
|
||||
REINDEXCOLLECTION when used with removeSource=true which could lead to a data loss. (ab)
|
||||
|
||||
Improvements
|
||||
----------------------
|
||||
|
||||
|
|
|
@ -27,6 +27,7 @@ import static org.apache.solr.common.cloud.ZkStateReader.PULL_REPLICAS;
|
|||
import static org.apache.solr.common.cloud.ZkStateReader.SHARD_ID_PROP;
|
||||
import static org.apache.solr.common.cloud.ZkStateReader.TLOG_REPLICAS;
|
||||
import static org.apache.solr.common.params.CollectionAdminParams.COLL_CONF;
|
||||
import static org.apache.solr.common.params.CollectionAdminParams.FOLLOW_ALIASES;
|
||||
import static org.apache.solr.common.params.CollectionAdminParams.WITH_COLLECTION;
|
||||
import static org.apache.solr.common.params.CollectionParams.CollectionAction.ADDREPLICA;
|
||||
import static org.apache.solr.common.params.CommonAdminParams.ASYNC;
|
||||
|
@ -97,9 +98,15 @@ public class AddReplicaCmd implements OverseerCollectionMessageHandler.Cmd {
|
|||
log.debug("addReplica() : {}", Utils.toJSONString(message));
|
||||
|
||||
String extCollectionName = message.getStr(COLLECTION_PROP);
|
||||
boolean followAliases = message.getBool(FOLLOW_ALIASES, false);
|
||||
String shard = message.getStr(SHARD_ID_PROP);
|
||||
|
||||
final String collectionName = ocmh.cloudManager.getClusterStateProvider().resolveSimpleAlias(extCollectionName);
|
||||
final String collectionName;
|
||||
if (followAliases) {
|
||||
collectionName = ocmh.cloudManager.getClusterStateProvider().resolveSimpleAlias(extCollectionName);
|
||||
} else {
|
||||
collectionName = extCollectionName;
|
||||
}
|
||||
|
||||
DocCollection coll = clusterState.getCollection(collectionName);
|
||||
if (coll == null) {
|
||||
|
|
|
@ -18,6 +18,7 @@ package org.apache.solr.cloud.api.collections;
|
|||
|
||||
import static org.apache.solr.common.cloud.ZkStateReader.COLLECTION_PROP;
|
||||
import static org.apache.solr.common.cloud.ZkStateReader.CORE_NAME_PROP;
|
||||
import static org.apache.solr.common.params.CollectionAdminParams.FOLLOW_ALIASES;
|
||||
import static org.apache.solr.common.params.CommonAdminParams.ASYNC;
|
||||
import static org.apache.solr.common.params.CommonParams.NAME;
|
||||
|
||||
|
@ -67,7 +68,13 @@ public class BackupCmd implements OverseerCollectionMessageHandler.Cmd {
|
|||
@Override
|
||||
public void call(ClusterState state, ZkNodeProps message, NamedList results) throws Exception {
|
||||
String extCollectionName = message.getStr(COLLECTION_PROP);
|
||||
String collectionName = ocmh.cloudManager.getClusterStateProvider().resolveSimpleAlias(extCollectionName);
|
||||
boolean followAliases = message.getBool(FOLLOW_ALIASES, false);
|
||||
String collectionName;
|
||||
if (followAliases) {
|
||||
collectionName = ocmh.cloudManager.getClusterStateProvider().resolveSimpleAlias(extCollectionName);
|
||||
} else {
|
||||
collectionName = extCollectionName;
|
||||
}
|
||||
String backupName = message.getStr(NAME);
|
||||
String repo = message.getStr(CoreAdminParams.BACKUP_REPOSITORY);
|
||||
|
||||
|
|
|
@ -112,7 +112,7 @@ public class CreateCollectionCmd implements OverseerCollectionMessageHandler.Cmd
|
|||
final boolean waitForFinalState = message.getBool(WAIT_FOR_FINAL_STATE, false);
|
||||
final String alias = message.getStr(ALIAS, collectionName);
|
||||
log.info("Create collection {}", collectionName);
|
||||
if (clusterState.hasCollection(collectionName) || aliases.hasAlias(collectionName)) {
|
||||
if (clusterState.hasCollection(collectionName)) {
|
||||
throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, "collection already exists: " + collectionName);
|
||||
}
|
||||
if (aliases.hasAlias(collectionName)) {
|
||||
|
|
|
@ -39,6 +39,7 @@ import static org.apache.solr.common.cloud.ZkStateReader.PULL_REPLICAS;
|
|||
import static org.apache.solr.common.cloud.ZkStateReader.REPLICATION_FACTOR;
|
||||
import static org.apache.solr.common.cloud.ZkStateReader.SHARD_ID_PROP;
|
||||
import static org.apache.solr.common.cloud.ZkStateReader.TLOG_REPLICAS;
|
||||
import static org.apache.solr.common.params.CollectionAdminParams.FOLLOW_ALIASES;
|
||||
import static org.apache.solr.common.params.CommonAdminParams.ASYNC;
|
||||
|
||||
public class CreateShardCmd implements OverseerCollectionMessageHandler.Cmd {
|
||||
|
@ -59,7 +60,13 @@ public class CreateShardCmd implements OverseerCollectionMessageHandler.Cmd {
|
|||
if (extCollectionName == null || sliceName == null)
|
||||
throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, "'collection' and 'shard' are required parameters");
|
||||
|
||||
String collectionName = ocmh.cloudManager.getClusterStateProvider().resolveSimpleAlias(extCollectionName);
|
||||
boolean followAliases = message.getBool(FOLLOW_ALIASES, false);
|
||||
String collectionName;
|
||||
if (followAliases) {
|
||||
collectionName = ocmh.cloudManager.getClusterStateProvider().resolveSimpleAlias(extCollectionName);
|
||||
} else {
|
||||
collectionName = extCollectionName;
|
||||
}
|
||||
DocCollection collection = clusterState.getCollection(collectionName);
|
||||
|
||||
int numNrtReplicas = message.getInt(NRT_REPLICAS, message.getInt(REPLICATION_FACTOR, collection.getInt(NRT_REPLICAS, collection.getInt(REPLICATION_FACTOR, 1))));
|
||||
|
|
|
@ -18,6 +18,7 @@ package org.apache.solr.cloud.api.collections;
|
|||
|
||||
import static org.apache.solr.common.cloud.ZkStateReader.COLLECTION_PROP;
|
||||
import static org.apache.solr.common.cloud.ZkStateReader.CORE_NAME_PROP;
|
||||
import static org.apache.solr.common.params.CollectionAdminParams.FOLLOW_ALIASES;
|
||||
import static org.apache.solr.common.params.CommonAdminParams.ASYNC;
|
||||
import static org.apache.solr.common.params.CommonParams.NAME;
|
||||
|
||||
|
@ -66,7 +67,14 @@ public class CreateSnapshotCmd implements OverseerCollectionMessageHandler.Cmd {
|
|||
@Override
|
||||
public void call(ClusterState state, ZkNodeProps message, NamedList results) throws Exception {
|
||||
String extCollectionName = message.getStr(COLLECTION_PROP);
|
||||
String collectionName = ocmh.zkStateReader.getAliases().resolveSimpleAlias(extCollectionName);
|
||||
boolean followAliases = message.getBool(FOLLOW_ALIASES, false);
|
||||
|
||||
String collectionName;
|
||||
if (followAliases) {
|
||||
collectionName = ocmh.zkStateReader.getAliases().resolveSimpleAlias(extCollectionName);
|
||||
} else {
|
||||
collectionName = extCollectionName;
|
||||
}
|
||||
|
||||
String commitName = message.getStr(CoreAdminParams.COMMIT_NAME);
|
||||
String asyncId = message.getStr(ASYNC);
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
package org.apache.solr.cloud.api.collections;
|
||||
|
||||
import static org.apache.solr.common.params.CollectionAdminParams.COLOCATED_WITH;
|
||||
import static org.apache.solr.common.params.CollectionAdminParams.FOLLOW_ALIASES;
|
||||
import static org.apache.solr.common.params.CollectionAdminParams.WITH_COLLECTION;
|
||||
import static org.apache.solr.common.params.CollectionParams.CollectionAction.DELETE;
|
||||
import static org.apache.solr.common.params.CommonAdminParams.ASYNC;
|
||||
|
@ -76,10 +77,17 @@ public class DeleteCollectionCmd implements OverseerCollectionMessageHandler.Cmd
|
|||
zkStateReader.aliasesManager.update(); // aliases may have been stale; get latest from ZK
|
||||
}
|
||||
|
||||
List<String> aliasReferences = checkAliasReference(zkStateReader, extCollection);
|
||||
boolean followAliases = message.getBool(FOLLOW_ALIASES, false);
|
||||
List<String> aliasReferences = checkAliasReference(zkStateReader, extCollection, followAliases);
|
||||
|
||||
Aliases aliases = zkStateReader.getAliases();
|
||||
String collection = aliases.resolveSimpleAlias(extCollection);
|
||||
|
||||
String collection;
|
||||
if (followAliases) {
|
||||
collection = aliases.resolveSimpleAlias(extCollection);
|
||||
} else {
|
||||
collection = extCollection;
|
||||
}
|
||||
|
||||
checkNotColocatedWith(zkStateReader, collection);
|
||||
|
||||
|
@ -118,8 +126,9 @@ public class DeleteCollectionCmd implements OverseerCollectionMessageHandler.Cmd
|
|||
|
||||
Set<String> okayExceptions = new HashSet<>(1);
|
||||
okayExceptions.add(NonExistentCoreException.class.getName());
|
||||
ZkNodeProps internalMsg = message.plus(NAME, collection);
|
||||
|
||||
List<Replica> failedReplicas = ocmh.collectionCmd(message, params, results, null, asyncId, okayExceptions);
|
||||
List<Replica> failedReplicas = ocmh.collectionCmd(internalMsg, params, results, null, asyncId, okayExceptions);
|
||||
for (Replica failedReplica : failedReplicas) {
|
||||
boolean isSharedFS = failedReplica.getBool(ZkStateReader.SHARED_STORAGE_PROP, false) && failedReplica.get("dataDir") != null;
|
||||
if (isSharedFS) {
|
||||
|
@ -185,14 +194,14 @@ public class DeleteCollectionCmd implements OverseerCollectionMessageHandler.Cmd
|
|||
}
|
||||
|
||||
// This method returns the single collection aliases to delete, if present, or null
|
||||
private List<String> checkAliasReference(ZkStateReader zkStateReader, String extCollection) throws Exception {
|
||||
private List<String> checkAliasReference(ZkStateReader zkStateReader, String extCollection, boolean followAliases) throws Exception {
|
||||
Aliases aliases = zkStateReader.getAliases();
|
||||
List<String> aliasesRefs = referencedByAlias(extCollection, aliases);
|
||||
List<String> aliasesRefs = referencedByAlias(extCollection, aliases, followAliases);
|
||||
List<String> aliasesToDelete = new ArrayList<>();
|
||||
if (aliasesRefs.size() > 0) {
|
||||
zkStateReader.aliasesManager.update(); // aliases may have been stale; get latest from ZK
|
||||
aliases = zkStateReader.getAliases();
|
||||
aliasesRefs = referencedByAlias(extCollection, aliases);
|
||||
aliasesRefs = referencedByAlias(extCollection, aliases, followAliases);
|
||||
if (aliasesRefs.size() > 0) {
|
||||
for (String alias : aliasesRefs) {
|
||||
// for back-compat in 8.x we don't automatically remove other
|
||||
|
@ -209,11 +218,12 @@ public class DeleteCollectionCmd implements OverseerCollectionMessageHandler.Cmd
|
|||
return aliasesToDelete;
|
||||
}
|
||||
|
||||
public static List<String> referencedByAlias(String extCollection, Aliases aliases) throws IllegalArgumentException {
|
||||
public static List<String> referencedByAlias(String extCollection, Aliases aliases, boolean followAliases) throws IllegalArgumentException {
|
||||
Objects.requireNonNull(aliases);
|
||||
// this quickly produces error if the name is a complex alias
|
||||
String collection = aliases.resolveSimpleAlias(extCollection);
|
||||
String collection = followAliases ? aliases.resolveSimpleAlias(extCollection) : extCollection;
|
||||
return aliases.getCollectionAliasListMap().entrySet().stream()
|
||||
.filter(e -> !e.getKey().equals(collection))
|
||||
.filter(e -> e.getValue().contains(collection) || e.getValue().contains(extCollection))
|
||||
.map(Map.Entry::getKey) // alias name
|
||||
.collect(Collectors.toList());
|
||||
|
|
|
@ -20,6 +20,7 @@ import static org.apache.solr.common.cloud.ZkStateReader.COLLECTION_PROP;
|
|||
import static org.apache.solr.common.cloud.ZkStateReader.REPLICA_PROP;
|
||||
import static org.apache.solr.common.cloud.ZkStateReader.SHARD_ID_PROP;
|
||||
import static org.apache.solr.common.params.CollectionAdminParams.COUNT_PROP;
|
||||
import static org.apache.solr.common.params.CollectionAdminParams.FOLLOW_ALIASES;
|
||||
import static org.apache.solr.common.params.CommonAdminParams.ASYNC;
|
||||
|
||||
import java.lang.invoke.MethodHandles;
|
||||
|
@ -85,7 +86,13 @@ public class DeleteReplicaCmd implements Cmd {
|
|||
String shard = message.getStr(SHARD_ID_PROP);
|
||||
String replicaName = message.getStr(REPLICA_PROP);
|
||||
|
||||
String collectionName = ocmh.cloudManager.getClusterStateProvider().resolveSimpleAlias(extCollectionName);
|
||||
boolean followAliases = message.getBool(FOLLOW_ALIASES, false);
|
||||
String collectionName;
|
||||
if (followAliases) {
|
||||
collectionName = ocmh.cloudManager.getClusterStateProvider().resolveSimpleAlias(extCollectionName);
|
||||
} else {
|
||||
collectionName = extCollectionName;
|
||||
}
|
||||
|
||||
DocCollection coll = clusterState.getCollection(collectionName);
|
||||
Slice slice = coll.getSlice(shard);
|
||||
|
|
|
@ -20,6 +20,7 @@ package org.apache.solr.cloud.api.collections;
|
|||
import static org.apache.solr.common.cloud.ZkStateReader.COLLECTION_PROP;
|
||||
import static org.apache.solr.common.cloud.ZkStateReader.NODE_NAME_PROP;
|
||||
import static org.apache.solr.common.cloud.ZkStateReader.SHARD_ID_PROP;
|
||||
import static org.apache.solr.common.params.CollectionAdminParams.FOLLOW_ALIASES;
|
||||
import static org.apache.solr.common.params.CollectionParams.CollectionAction.DELETEREPLICA;
|
||||
import static org.apache.solr.common.params.CollectionParams.CollectionAction.DELETESHARD;
|
||||
import static org.apache.solr.common.params.CommonAdminParams.ASYNC;
|
||||
|
@ -65,7 +66,13 @@ public class DeleteShardCmd implements OverseerCollectionMessageHandler.Cmd {
|
|||
String extCollectionName = message.getStr(ZkStateReader.COLLECTION_PROP);
|
||||
String sliceId = message.getStr(ZkStateReader.SHARD_ID_PROP);
|
||||
|
||||
String collectionName = ocmh.cloudManager.getClusterStateProvider().resolveSimpleAlias(extCollectionName);
|
||||
boolean followAliases = message.getBool(FOLLOW_ALIASES, false);
|
||||
String collectionName;
|
||||
if (followAliases) {
|
||||
collectionName = ocmh.cloudManager.getClusterStateProvider().resolveSimpleAlias(extCollectionName);
|
||||
} else {
|
||||
collectionName = extCollectionName;
|
||||
}
|
||||
|
||||
log.info("Delete shard invoked");
|
||||
Slice slice = clusterState.getCollection(collectionName).getSlice(sliceId);
|
||||
|
|
|
@ -18,6 +18,7 @@ package org.apache.solr.cloud.api.collections;
|
|||
|
||||
import static org.apache.solr.common.cloud.ZkStateReader.COLLECTION_PROP;
|
||||
import static org.apache.solr.common.cloud.ZkStateReader.CORE_NAME_PROP;
|
||||
import static org.apache.solr.common.params.CollectionAdminParams.FOLLOW_ALIASES;
|
||||
import static org.apache.solr.common.params.CommonAdminParams.ASYNC;
|
||||
import static org.apache.solr.common.params.CommonParams.NAME;
|
||||
|
||||
|
@ -64,7 +65,13 @@ public class DeleteSnapshotCmd implements OverseerCollectionMessageHandler.Cmd {
|
|||
@Override
|
||||
public void call(ClusterState state, ZkNodeProps message, NamedList results) throws Exception {
|
||||
String extCollectionName = message.getStr(COLLECTION_PROP);
|
||||
String collectionName = ocmh.zkStateReader.getAliases().resolveSimpleAlias(extCollectionName);
|
||||
boolean followAliases = message.getBool(FOLLOW_ALIASES, false);
|
||||
String collectionName;
|
||||
if (followAliases) {
|
||||
collectionName = ocmh.zkStateReader.getAliases().resolveSimpleAlias(extCollectionName);
|
||||
} else {
|
||||
collectionName = extCollectionName;
|
||||
}
|
||||
String commitName = message.getStr(CoreAdminParams.COMMIT_NAME);
|
||||
String asyncId = message.getStr(ASYNC);
|
||||
NamedList shardRequestResults = new NamedList();
|
||||
|
|
|
@ -54,6 +54,7 @@ import org.slf4j.LoggerFactory;
|
|||
import static org.apache.solr.common.cloud.ZkStateReader.COLLECTION_PROP;
|
||||
import static org.apache.solr.common.cloud.ZkStateReader.NRT_REPLICAS;
|
||||
import static org.apache.solr.common.cloud.ZkStateReader.SHARD_ID_PROP;
|
||||
import static org.apache.solr.common.params.CollectionAdminParams.FOLLOW_ALIASES;
|
||||
import static org.apache.solr.common.params.CollectionParams.CollectionAction.ADDREPLICA;
|
||||
import static org.apache.solr.common.params.CollectionParams.CollectionAction.CREATE;
|
||||
import static org.apache.solr.common.params.CollectionParams.CollectionAction.DELETE;
|
||||
|
@ -79,8 +80,16 @@ public class MigrateCmd implements OverseerCollectionMessageHandler.Cmd {
|
|||
String extTargetCollectionName = message.getStr("target.collection");
|
||||
int timeout = message.getInt("forward.timeout", 10 * 60) * 1000;
|
||||
|
||||
String sourceCollectionName = ocmh.cloudManager.getClusterStateProvider().resolveSimpleAlias(extSourceCollectionName);
|
||||
String targetCollectionName = ocmh.cloudManager.getClusterStateProvider().resolveSimpleAlias(extTargetCollectionName);
|
||||
boolean followAliases = message.getBool(FOLLOW_ALIASES, false);
|
||||
String sourceCollectionName;
|
||||
String targetCollectionName;
|
||||
if (followAliases) {
|
||||
sourceCollectionName = ocmh.cloudManager.getClusterStateProvider().resolveSimpleAlias(extSourceCollectionName);
|
||||
targetCollectionName = ocmh.cloudManager.getClusterStateProvider().resolveSimpleAlias(extTargetCollectionName);
|
||||
} else {
|
||||
sourceCollectionName = extSourceCollectionName;
|
||||
targetCollectionName = extTargetCollectionName;
|
||||
}
|
||||
|
||||
DocCollection sourceCollection = clusterState.getCollection(sourceCollectionName);
|
||||
if (sourceCollection == null) {
|
||||
|
|
|
@ -48,6 +48,7 @@ import static org.apache.solr.cloud.api.collections.OverseerCollectionMessageHan
|
|||
import static org.apache.solr.common.cloud.ZkStateReader.COLLECTION_PROP;
|
||||
import static org.apache.solr.common.cloud.ZkStateReader.REPLICA_PROP;
|
||||
import static org.apache.solr.common.cloud.ZkStateReader.SHARD_ID_PROP;
|
||||
import static org.apache.solr.common.params.CollectionAdminParams.FOLLOW_ALIASES;
|
||||
import static org.apache.solr.common.params.CommonAdminParams.ASYNC;
|
||||
import static org.apache.solr.common.params.CommonAdminParams.IN_PLACE_MOVE;
|
||||
import static org.apache.solr.common.params.CommonAdminParams.TIMEOUT;
|
||||
|
@ -80,7 +81,13 @@ public class MoveReplicaCmd implements OverseerCollectionMessageHandler.Cmd {
|
|||
|
||||
String async = message.getStr(ASYNC);
|
||||
|
||||
String collection = ocmh.cloudManager.getClusterStateProvider().resolveSimpleAlias(extCollection);
|
||||
boolean followAliases = message.getBool(FOLLOW_ALIASES, false);
|
||||
String collection;
|
||||
if (followAliases) {
|
||||
collection = ocmh.cloudManager.getClusterStateProvider().resolveSimpleAlias(extCollection);
|
||||
} else {
|
||||
collection = extCollection;
|
||||
}
|
||||
|
||||
DocCollection coll = clusterState.getCollection(collection);
|
||||
if (coll == null) {
|
||||
|
|
|
@ -64,6 +64,8 @@ import org.apache.zookeeper.CreateMode;
|
|||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import static org.apache.solr.common.params.CollectionAdminParams.FOLLOW_ALIASES;
|
||||
|
||||
/**
|
||||
* Reindex a collection, usually in order to change the index schema.
|
||||
* <p>WARNING: Reindexing is potentially a lossy operation - some indexed data that is not available as
|
||||
|
@ -178,7 +180,13 @@ public class ReindexCollectionCmd implements OverseerCollectionMessageHandler.Cm
|
|||
if (extCollection == null) {
|
||||
throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, "Source collection name must be specified");
|
||||
}
|
||||
String collection = ocmh.cloudManager.getClusterStateProvider().resolveSimpleAlias(extCollection);
|
||||
boolean followAliases = message.getBool(FOLLOW_ALIASES, false);
|
||||
String collection;
|
||||
if (followAliases) {
|
||||
collection = ocmh.cloudManager.getClusterStateProvider().resolveSimpleAlias(extCollection);
|
||||
} else {
|
||||
collection = extCollection;
|
||||
}
|
||||
if (!clusterState.hasCollection(collection)) {
|
||||
throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, "Source collection name must exist");
|
||||
}
|
||||
|
@ -186,8 +194,9 @@ public class ReindexCollectionCmd implements OverseerCollectionMessageHandler.Cm
|
|||
if (target == null) {
|
||||
target = collection;
|
||||
} else {
|
||||
// resolve aliases
|
||||
target = ocmh.cloudManager.getClusterStateProvider().resolveSimpleAlias(target);
|
||||
if (followAliases) {
|
||||
target = ocmh.cloudManager.getClusterStateProvider().resolveSimpleAlias(target);
|
||||
}
|
||||
}
|
||||
boolean sameTarget = target.equals(collection) || target.equals(extCollection);
|
||||
boolean removeSource = message.getBool(REMOVE_SOURCE, false);
|
||||
|
@ -466,6 +475,7 @@ public class ReindexCollectionCmd implements OverseerCollectionMessageHandler.Cm
|
|||
cmd = new ZkNodeProps(
|
||||
Overseer.QUEUE_OPERATION, CollectionParams.CollectionAction.DELETE.toLower(),
|
||||
CommonParams.NAME, collection,
|
||||
FOLLOW_ALIASES, "false",
|
||||
CoreAdminParams.DELETE_METRICS_HISTORY, "true"
|
||||
);
|
||||
cmdResults = new NamedList<>();
|
||||
|
@ -770,6 +780,7 @@ public class ReindexCollectionCmd implements OverseerCollectionMessageHandler.Cm
|
|||
ZkNodeProps cmd = new ZkNodeProps(
|
||||
Overseer.QUEUE_OPERATION, CollectionParams.CollectionAction.DELETE.toLower(),
|
||||
CommonParams.NAME, targetCollection,
|
||||
FOLLOW_ALIASES, "false",
|
||||
CoreAdminParams.DELETE_METRICS_HISTORY, "true"
|
||||
);
|
||||
ocmh.commandMap.get(CollectionParams.CollectionAction.DELETE).call(clusterState, cmd, cmdResults);
|
||||
|
@ -782,6 +793,7 @@ public class ReindexCollectionCmd implements OverseerCollectionMessageHandler.Cm
|
|||
ZkNodeProps cmd = new ZkNodeProps(
|
||||
Overseer.QUEUE_OPERATION, CollectionParams.CollectionAction.DELETE.toLower(),
|
||||
CommonParams.NAME, chkCollection,
|
||||
FOLLOW_ALIASES, "false",
|
||||
CoreAdminParams.DELETE_METRICS_HISTORY, "true"
|
||||
);
|
||||
cmdResults = new NamedList<>();
|
||||
|
|
|
@ -29,6 +29,8 @@ import org.apache.solr.common.util.NamedList;
|
|||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import static org.apache.solr.common.params.CollectionAdminParams.FOLLOW_ALIASES;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
|
@ -55,7 +57,13 @@ public class RenameCmd implements OverseerCollectionMessageHandler.Cmd {
|
|||
}
|
||||
Aliases aliases = ocmh.zkStateReader.getAliases();
|
||||
|
||||
String collectionName = aliases.resolveSimpleAlias(extCollectionName);
|
||||
boolean followAliases = message.getBool(FOLLOW_ALIASES, false);
|
||||
String collectionName;
|
||||
if (followAliases) {
|
||||
collectionName = aliases.resolveSimpleAlias(extCollectionName);
|
||||
} else {
|
||||
collectionName = extCollectionName;
|
||||
}
|
||||
if (!state.hasCollection(collectionName)) {
|
||||
throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, "source collection '" + collectionName + "' not found.");
|
||||
}
|
||||
|
@ -65,6 +73,5 @@ public class RenameCmd implements OverseerCollectionMessageHandler.Cmd {
|
|||
}
|
||||
|
||||
ocmh.zkStateReader.aliasesManager.applyModificationAndExportToZk(a -> a.cloneWithRename(extCollectionName, target));
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -73,6 +73,7 @@ import org.slf4j.LoggerFactory;
|
|||
import static org.apache.solr.common.cloud.ZkStateReader.COLLECTION_PROP;
|
||||
import static org.apache.solr.common.cloud.ZkStateReader.REPLICA_TYPE;
|
||||
import static org.apache.solr.common.cloud.ZkStateReader.SHARD_ID_PROP;
|
||||
import static org.apache.solr.common.params.CollectionAdminParams.FOLLOW_ALIASES;
|
||||
import static org.apache.solr.common.params.CollectionParams.CollectionAction.ADDREPLICA;
|
||||
import static org.apache.solr.common.params.CollectionParams.CollectionAction.CREATESHARD;
|
||||
import static org.apache.solr.common.params.CollectionParams.CollectionAction.DELETESHARD;
|
||||
|
@ -111,7 +112,13 @@ public class SplitShardCmd implements OverseerCollectionMessageHandler.Cmd {
|
|||
|
||||
String extCollectionName = message.getStr(CoreAdminParams.COLLECTION);
|
||||
|
||||
String collectionName = ocmh.cloudManager.getClusterStateProvider().resolveSimpleAlias(extCollectionName);
|
||||
boolean followAliases = message.getBool(FOLLOW_ALIASES, false);
|
||||
String collectionName;
|
||||
if (followAliases) {
|
||||
collectionName = ocmh.cloudManager.getClusterStateProvider().resolveSimpleAlias(extCollectionName);
|
||||
} else {
|
||||
collectionName = extCollectionName;
|
||||
}
|
||||
|
||||
log.debug("Split shard invoked: {}", message);
|
||||
ZkStateReader zkStateReader = ocmh.zkStateReader;
|
||||
|
|
|
@ -141,6 +141,7 @@ import static org.apache.solr.common.params.CollectionAdminParams.ALIAS;
|
|||
import static org.apache.solr.common.params.CollectionAdminParams.COLLECTION;
|
||||
import static org.apache.solr.common.params.CollectionAdminParams.COLL_CONF;
|
||||
import static org.apache.solr.common.params.CollectionAdminParams.COUNT_PROP;
|
||||
import static org.apache.solr.common.params.CollectionAdminParams.FOLLOW_ALIASES;
|
||||
import static org.apache.solr.common.params.CollectionAdminParams.PROPERTY_NAME;
|
||||
import static org.apache.solr.common.params.CollectionAdminParams.PROPERTY_VALUE;
|
||||
import static org.apache.solr.common.params.CollectionAdminParams.WITH_COLLECTION;
|
||||
|
@ -544,11 +545,20 @@ public class CollectionsHandler extends RequestHandlerBase implements Permission
|
|||
.getColStatus(rsp.getValues());
|
||||
return null;
|
||||
}),
|
||||
DELETE_OP(DELETE, (req, rsp, h) -> copy(req.getParams().required(), null, NAME)),
|
||||
DELETE_OP(DELETE, (req, rsp, h) -> {
|
||||
Map<String, Object> map = copy(req.getParams().required(), null, NAME);
|
||||
return copy(req.getParams(), map, FOLLOW_ALIASES);
|
||||
}),
|
||||
// XXX should this command support followAliases?
|
||||
RELOAD_OP(RELOAD, (req, rsp, h) -> {
|
||||
Map<String, Object> map = copy(req.getParams().required(), null, NAME);
|
||||
return copy(req.getParams(), map);
|
||||
}),
|
||||
|
||||
RELOAD_OP(RELOAD, (req, rsp, h) -> copy(req.getParams().required(), null, NAME)),
|
||||
|
||||
RENAME_OP(RENAME, (req, rsp, h) -> copy(req.getParams().required(), null, NAME, CollectionAdminParams.TARGET)),
|
||||
RENAME_OP(RENAME, (req, rsp, h) -> {
|
||||
Map<String, Object> map = copy(req.getParams().required(), null, NAME, CollectionAdminParams.TARGET);
|
||||
return copy(req.getParams(), map, FOLLOW_ALIASES);
|
||||
}),
|
||||
|
||||
REINDEXCOLLECTION_OP(REINDEXCOLLECTION, (req, rsp, h) -> {
|
||||
Map<String, Object> m = copy(req.getParams().required(), null, NAME);
|
||||
|
@ -571,7 +581,8 @@ public class CollectionsHandler extends RequestHandlerBase implements Permission
|
|||
STATE_FORMAT,
|
||||
CommonParams.ROWS,
|
||||
CommonParams.Q,
|
||||
CommonParams.FL);
|
||||
CommonParams.FL,
|
||||
FOLLOW_ALIASES);
|
||||
if (req.getParams().get("collection." + ZkStateReader.CONFIGNAME_PROP) != null) {
|
||||
m.put(ZkStateReader.CONFIGNAME_PROP, req.getParams().get("collection." + ZkStateReader.CONFIGNAME_PROP));
|
||||
}
|
||||
|
@ -748,7 +759,8 @@ public class CollectionsHandler extends RequestHandlerBase implements Permission
|
|||
TIMING,
|
||||
SPLIT_METHOD,
|
||||
NUM_SUB_SHARDS,
|
||||
SPLIT_FUZZ);
|
||||
SPLIT_FUZZ,
|
||||
FOLLOW_ALIASES);
|
||||
return copyPropertiesWithPrefix(req.getParams(), map, COLL_PROP_PREFIX);
|
||||
}),
|
||||
DELETESHARD_OP(DELETESHARD, (req, rsp, h) -> {
|
||||
|
@ -759,7 +771,8 @@ public class CollectionsHandler extends RequestHandlerBase implements Permission
|
|||
DELETE_INDEX,
|
||||
DELETE_DATA_DIR,
|
||||
DELETE_INSTANCE_DIR,
|
||||
DELETE_METRICS_HISTORY);
|
||||
DELETE_METRICS_HISTORY,
|
||||
FOLLOW_ALIASES);
|
||||
return map;
|
||||
}),
|
||||
FORCELEADER_OP(FORCELEADER, (req, rsp, h) -> {
|
||||
|
@ -772,7 +785,11 @@ public class CollectionsHandler extends RequestHandlerBase implements Permission
|
|||
SHARD_ID_PROP);
|
||||
ClusterState clusterState = h.coreContainer.getZkController().getClusterState();
|
||||
final String newShardName = SolrIdentifierValidator.validateShardName(req.getParams().get(SHARD_ID_PROP));
|
||||
if (!ImplicitDocRouter.NAME.equals(((Map) clusterState.getCollection(req.getParams().get(COLLECTION_PROP)).get(DOC_ROUTER)).get(NAME)))
|
||||
boolean followAliases = req.getParams().getBool(FOLLOW_ALIASES, false);
|
||||
String extCollectionName = req.getParams().get(COLLECTION_PROP);
|
||||
String collectionName = followAliases ? h.coreContainer.getZkController().getZkStateReader()
|
||||
.getAliases().resolveSimpleAlias(extCollectionName) : extCollectionName;
|
||||
if (!ImplicitDocRouter.NAME.equals(((Map) clusterState.getCollection(collectionName).get(DOC_ROUTER)).get(NAME)))
|
||||
throw new SolrException(ErrorCode.BAD_REQUEST, "shards can be added only to 'implicit' collections");
|
||||
copy(req.getParams(), map,
|
||||
REPLICATION_FACTOR,
|
||||
|
@ -780,7 +797,8 @@ public class CollectionsHandler extends RequestHandlerBase implements Permission
|
|||
TLOG_REPLICAS,
|
||||
PULL_REPLICAS,
|
||||
CREATE_NODE_SET,
|
||||
WAIT_FOR_FINAL_STATE);
|
||||
WAIT_FOR_FINAL_STATE,
|
||||
FOLLOW_ALIASES);
|
||||
return copyPropertiesWithPrefix(req.getParams(), map, COLL_PROP_PREFIX);
|
||||
}),
|
||||
DELETEREPLICA_OP(DELETEREPLICA, (req, rsp, h) -> {
|
||||
|
@ -794,11 +812,12 @@ public class CollectionsHandler extends RequestHandlerBase implements Permission
|
|||
DELETE_METRICS_HISTORY,
|
||||
COUNT_PROP, REPLICA_PROP,
|
||||
SHARD_ID_PROP,
|
||||
ONLY_IF_DOWN);
|
||||
ONLY_IF_DOWN,
|
||||
FOLLOW_ALIASES);
|
||||
}),
|
||||
MIGRATE_OP(MIGRATE, (req, rsp, h) -> {
|
||||
Map<String, Object> map = copy(req.getParams().required(), null, COLLECTION_PROP, "split.key", "target.collection");
|
||||
return copy(req.getParams(), map, "forward.timeout");
|
||||
return copy(req.getParams(), map, "forward.timeout", FOLLOW_ALIASES);
|
||||
}),
|
||||
ADDROLE_OP(ADDROLE, (req, rsp, h) -> {
|
||||
Map<String, Object> map = copy(req.getParams().required(), null, "role", "node");
|
||||
|
@ -918,7 +937,8 @@ public class CollectionsHandler extends RequestHandlerBase implements Permission
|
|||
NRT_REPLICAS,
|
||||
TLOG_REPLICAS,
|
||||
PULL_REPLICAS,
|
||||
CREATE_NODE_SET);
|
||||
CREATE_NODE_SET,
|
||||
FOLLOW_ALIASES);
|
||||
return copyPropertiesWithPrefix(req.getParams(), props, COLL_PROP_PREFIX);
|
||||
}),
|
||||
OVERSEERSTATUS_OP(OVERSEERSTATUS, (req, rsp, h) -> (Map) new LinkedHashMap<>()),
|
||||
|
@ -980,6 +1000,7 @@ public class CollectionsHandler extends RequestHandlerBase implements Permission
|
|||
}
|
||||
return map;
|
||||
}),
|
||||
// XXX should this command support followAliases?
|
||||
DELETEREPLICAPROP_OP(DELETEREPLICAPROP, (req, rsp, h) -> {
|
||||
Map<String, Object> map = copy(req.getParams().required(), null,
|
||||
COLLECTION_PROP,
|
||||
|
@ -988,6 +1009,7 @@ public class CollectionsHandler extends RequestHandlerBase implements Permission
|
|||
REPLICA_PROP);
|
||||
return copy(req.getParams(), map, PROPERTY_PROP);
|
||||
}),
|
||||
// XXX should this command support followAliases?
|
||||
BALANCESHARDUNIQUE_OP(BALANCESHARDUNIQUE, (req, rsp, h) -> {
|
||||
Map<String, Object> map = copy(req.getParams().required(), null,
|
||||
COLLECTION_PROP,
|
||||
|
@ -1010,6 +1032,7 @@ public class CollectionsHandler extends RequestHandlerBase implements Permission
|
|||
new RebalanceLeaders(req, rsp, h).execute();
|
||||
return null;
|
||||
}),
|
||||
// XXX should this command support followAliases?
|
||||
MODIFYCOLLECTION_OP(MODIFYCOLLECTION, (req, rsp, h) -> {
|
||||
Map<String, Object> m = copy(req.getParams(), null, CollectionAdminRequest.MODIFIABLE_COLLECTION_PROPERTIES);
|
||||
copyPropertiesWithPrefix(req.getParams(), m, COLL_PROP_PREFIX);
|
||||
|
@ -1039,8 +1062,9 @@ public class CollectionsHandler extends RequestHandlerBase implements Permission
|
|||
req.getParams().required().check(NAME, COLLECTION_PROP);
|
||||
|
||||
String extCollectionName = req.getParams().get(COLLECTION_PROP);
|
||||
String collectionName = h.coreContainer.getZkController().getZkStateReader()
|
||||
.getAliases().resolveSimpleAlias(extCollectionName);
|
||||
boolean followAliases = req.getParams().getBool(FOLLOW_ALIASES, false);
|
||||
String collectionName = followAliases ? h.coreContainer.getZkController().getZkStateReader()
|
||||
.getAliases().resolveSimpleAlias(extCollectionName) : extCollectionName;
|
||||
ClusterState clusterState = h.coreContainer.getZkController().getClusterState();
|
||||
if (!clusterState.hasCollection(collectionName)) {
|
||||
throw new SolrException(ErrorCode.BAD_REQUEST, "Collection '" + collectionName + "' does not exist, no action taken.");
|
||||
|
@ -1076,7 +1100,7 @@ public class CollectionsHandler extends RequestHandlerBase implements Permission
|
|||
throw new SolrException(ErrorCode.BAD_REQUEST, "Unknown index backup strategy " + strategy);
|
||||
}
|
||||
|
||||
Map<String, Object> params = copy(req.getParams(), null, NAME, COLLECTION_PROP, CoreAdminParams.COMMIT_NAME);
|
||||
Map<String, Object> params = copy(req.getParams(), null, NAME, COLLECTION_PROP, FOLLOW_ALIASES, CoreAdminParams.COMMIT_NAME);
|
||||
params.put(CoreAdminParams.BACKUP_LOCATION, location);
|
||||
params.put(CollectionAdminParams.INDEX_BACKUP_STRATEGY, strategy);
|
||||
return params;
|
||||
|
@ -1143,8 +1167,9 @@ public class CollectionsHandler extends RequestHandlerBase implements Permission
|
|||
req.getParams().required().check(COLLECTION_PROP, CoreAdminParams.COMMIT_NAME);
|
||||
|
||||
String extCollectionName = req.getParams().get(COLLECTION_PROP);
|
||||
String collectionName = h.coreContainer.getZkController().getZkStateReader()
|
||||
.getAliases().resolveSimpleAlias(extCollectionName);
|
||||
boolean followAliases = req.getParams().getBool(FOLLOW_ALIASES, false);
|
||||
String collectionName = followAliases ? h.coreContainer.getZkController().getZkStateReader()
|
||||
.getAliases().resolveSimpleAlias(extCollectionName) : extCollectionName;
|
||||
String commitName = req.getParams().get(CoreAdminParams.COMMIT_NAME);
|
||||
ClusterState clusterState = h.coreContainer.getZkController().getClusterState();
|
||||
if (!clusterState.hasCollection(collectionName)) {
|
||||
|
@ -1158,7 +1183,7 @@ public class CollectionsHandler extends RequestHandlerBase implements Permission
|
|||
+ collectionName + "', no action taken.");
|
||||
}
|
||||
|
||||
Map<String, Object> params = copy(req.getParams(), null, COLLECTION_PROP, CoreAdminParams.COMMIT_NAME);
|
||||
Map<String, Object> params = copy(req.getParams(), null, COLLECTION_PROP, FOLLOW_ALIASES, CoreAdminParams.COMMIT_NAME);
|
||||
return params;
|
||||
}),
|
||||
DELETESNAPSHOT_OP(DELETESNAPSHOT, (req, rsp, h) -> {
|
||||
|
@ -1172,7 +1197,7 @@ public class CollectionsHandler extends RequestHandlerBase implements Permission
|
|||
throw new SolrException(ErrorCode.BAD_REQUEST, "Collection '" + collectionName + "' does not exist, no action taken.");
|
||||
}
|
||||
|
||||
Map<String, Object> params = copy(req.getParams(), null, COLLECTION_PROP, CoreAdminParams.COMMIT_NAME);
|
||||
Map<String, Object> params = copy(req.getParams(), null, COLLECTION_PROP, FOLLOW_ALIASES, CoreAdminParams.COMMIT_NAME);
|
||||
return params;
|
||||
}),
|
||||
LISTSNAPSHOTS_OP(LISTSNAPSHOTS, (req, rsp, h) -> {
|
||||
|
@ -1215,7 +1240,8 @@ public class CollectionsHandler extends RequestHandlerBase implements Permission
|
|||
WAIT_FOR_FINAL_STATE,
|
||||
IN_PLACE_MOVE,
|
||||
"replica",
|
||||
"shard");
|
||||
"shard",
|
||||
FOLLOW_ALIASES);
|
||||
}),
|
||||
DELETENODE_OP(DELETENODE, (req, rsp, h) -> copy(req.getParams().required(), null, "node"));
|
||||
|
||||
|
|
|
@ -53,9 +53,11 @@ import org.apache.solr.client.solrj.response.CollectionAdminResponse;
|
|||
import org.apache.solr.client.solrj.response.CoreAdminResponse;
|
||||
import org.apache.solr.client.solrj.response.QueryResponse;
|
||||
import org.apache.solr.client.solrj.response.V2Response;
|
||||
import org.apache.solr.common.SolrDocument;
|
||||
import org.apache.solr.common.SolrInputDocument;
|
||||
import org.apache.solr.common.cloud.Aliases;
|
||||
import org.apache.solr.common.cloud.ClusterProperties;
|
||||
import org.apache.solr.common.cloud.ClusterState;
|
||||
import org.apache.solr.common.cloud.DocCollection;
|
||||
import org.apache.solr.common.cloud.Replica;
|
||||
import org.apache.solr.common.cloud.Slice;
|
||||
|
@ -794,8 +796,20 @@ public class CollectionsAPISolrJTest extends SolrCloudTestCase {
|
|||
|
||||
@Test
|
||||
public void testRenameCollection() throws Exception {
|
||||
String collectionName1 = "testRename_collection1";
|
||||
String collectionName2 = "testRename_collection2";
|
||||
doTestRenameCollection(true);
|
||||
CollectionAdminRequest.deleteAlias("col1").process(cluster.getSolrClient());
|
||||
CollectionAdminRequest.deleteAlias("col2").process(cluster.getSolrClient());
|
||||
CollectionAdminRequest.deleteAlias("foo").process(cluster.getSolrClient());
|
||||
CollectionAdminRequest.deleteAlias("simpleAlias").process(cluster.getSolrClient());
|
||||
CollectionAdminRequest.deleteAlias("catAlias").process(cluster.getSolrClient());
|
||||
CollectionAdminRequest.deleteAlias("compoundAlias").process(cluster.getSolrClient());
|
||||
cluster.getSolrClient().getZkStateReader().aliasesManager.update();
|
||||
doTestRenameCollection(false);
|
||||
}
|
||||
|
||||
private void doTestRenameCollection(boolean followAliases) throws Exception {
|
||||
String collectionName1 = "testRename1_" + followAliases;
|
||||
String collectionName2 = "testRename2_" + followAliases;
|
||||
CollectionAdminRequest.createCollection(collectionName1, "conf", 1, 1).setAlias("col1").process(cluster.getSolrClient());
|
||||
CollectionAdminRequest.createCollection(collectionName2, "conf", 1, 1).setAlias("col2").process(cluster.getSolrClient());
|
||||
|
||||
|
@ -810,45 +824,159 @@ public class CollectionsAPISolrJTest extends SolrCloudTestCase {
|
|||
CollectionAdminRequest.createCategoryRoutedAlias("catAlias", "field1", 100,
|
||||
CollectionAdminRequest.createCollection("_unused_", "conf", 1, 1)).process(cluster.getSolrClient());
|
||||
|
||||
CollectionAdminRequest.renameCollection("col1", "foo").process(cluster.getSolrClient());
|
||||
CollectionAdminRequest.Rename rename = CollectionAdminRequest.renameCollection("col1", "foo");
|
||||
rename.setFollowAliases(followAliases);
|
||||
ZkStateReader zkStateReader = cluster.getSolrClient().getZkStateReader();
|
||||
zkStateReader.aliasesManager.update();
|
||||
Aliases aliases;
|
||||
if (!followAliases) {
|
||||
try {
|
||||
rename.process(cluster.getSolrClient());
|
||||
} catch (Exception e) {
|
||||
assertTrue(e.toString(), e.toString().contains("source collection 'col1' not found"));
|
||||
}
|
||||
} else {
|
||||
rename.process(cluster.getSolrClient());
|
||||
zkStateReader.aliasesManager.update();
|
||||
|
||||
Aliases aliases = zkStateReader.getAliases();
|
||||
assertEquals(aliases.getCollectionAliasListMap().toString(), collectionName1, aliases.resolveSimpleAlias("foo"));
|
||||
assertEquals(aliases.getCollectionAliasListMap().toString(), collectionName1, aliases.resolveSimpleAlias("simpleAlias"));
|
||||
List<String> compoundAliases = aliases.resolveAliases("compoundAlias");
|
||||
assertEquals(compoundAliases.toString(), 2, compoundAliases.size());
|
||||
assertTrue(compoundAliases.toString(), compoundAliases.contains(collectionName1));
|
||||
assertTrue(compoundAliases.toString(), compoundAliases.contains(collectionName2));
|
||||
aliases = zkStateReader.getAliases();
|
||||
assertEquals(aliases.getCollectionAliasListMap().toString(), collectionName1, aliases.resolveSimpleAlias("foo"));
|
||||
assertEquals(aliases.getCollectionAliasListMap().toString(), collectionName1, aliases.resolveSimpleAlias("simpleAlias"));
|
||||
List<String> compoundAliases = aliases.resolveAliases("compoundAlias");
|
||||
assertEquals(compoundAliases.toString(), 2, compoundAliases.size());
|
||||
assertTrue(compoundAliases.toString(), compoundAliases.contains(collectionName1));
|
||||
assertTrue(compoundAliases.toString(), compoundAliases.contains(collectionName2));
|
||||
}
|
||||
|
||||
CollectionAdminRequest.renameCollection(collectionName1, collectionName2).process(cluster.getSolrClient());
|
||||
zkStateReader.aliasesManager.update();
|
||||
|
||||
aliases = zkStateReader.getAliases();
|
||||
assertEquals(aliases.getCollectionAliasListMap().toString(), collectionName2, aliases.resolveSimpleAlias("foo"));
|
||||
if (followAliases) {
|
||||
assertEquals(aliases.getCollectionAliasListMap().toString(), collectionName2, aliases.resolveSimpleAlias("foo"));
|
||||
}
|
||||
assertEquals(aliases.getCollectionAliasListMap().toString(), collectionName2, aliases.resolveSimpleAlias("simpleAlias"));
|
||||
assertEquals(aliases.getCollectionAliasListMap().toString(), collectionName2, aliases.resolveSimpleAlias(collectionName1));
|
||||
// we renamed col1 -> col2 so the compound alias contains only "col2,col2" which is reduced to col2
|
||||
compoundAliases = aliases.resolveAliases("compoundAlias");
|
||||
List<String> compoundAliases = aliases.resolveAliases("compoundAlias");
|
||||
assertEquals(compoundAliases.toString(), 1, compoundAliases.size());
|
||||
assertTrue(compoundAliases.toString(), compoundAliases.contains(collectionName2));
|
||||
|
||||
try {
|
||||
CollectionAdminRequest.renameCollection("catAlias", "bar").process(cluster.getSolrClient());
|
||||
rename = CollectionAdminRequest.renameCollection("catAlias", "bar");
|
||||
rename.setFollowAliases(followAliases);
|
||||
rename.process(cluster.getSolrClient());
|
||||
fail("category-based alias renaming should fail");
|
||||
} catch (Exception e) {
|
||||
assertTrue(e.toString().contains("is a routed alias"));
|
||||
if (followAliases) {
|
||||
assertTrue(e.toString(), e.toString().contains("is a routed alias"));
|
||||
} else {
|
||||
assertTrue(e.toString(), e.toString().contains("source collection 'catAlias' not found"));
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
CollectionAdminRequest.renameCollection("col2", "foo").process(cluster.getSolrClient());
|
||||
fail("shuold fail because 'foo' already exists");
|
||||
rename = CollectionAdminRequest.renameCollection("col2", "foo");
|
||||
rename.setFollowAliases(followAliases);
|
||||
rename.process(cluster.getSolrClient());
|
||||
fail("should fail because 'foo' already exists");
|
||||
} catch (Exception e) {
|
||||
assertTrue(e.toString().contains("exists"));
|
||||
if (followAliases) {
|
||||
assertTrue(e.toString(), e.toString().contains("exists"));
|
||||
} else {
|
||||
assertTrue(e.toString(), e.toString().contains("source collection 'col2' not found"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDeleteAliasedCollection() throws Exception {
|
||||
CloudSolrClient solrClient = cluster.getSolrClient();
|
||||
String collectionName1 = "aliasedCollection1";
|
||||
String collectionName2 = "aliasedCollection2";
|
||||
CollectionAdminRequest.createCollection(collectionName1, "conf", 1, 1).process(solrClient);
|
||||
CollectionAdminRequest.createCollection(collectionName2, "conf", 1, 1).process(solrClient);
|
||||
|
||||
cluster.waitForActiveCollection(collectionName1, 1, 1);
|
||||
cluster.waitForActiveCollection(collectionName2, 1, 1);
|
||||
|
||||
waitForState("Expected collection1 to be created with 1 shard and 1 replica", collectionName1, clusterShape(1, 1));
|
||||
waitForState("Expected collection2 to be created with 1 shard and 1 replica", collectionName2, clusterShape(1, 1));
|
||||
|
||||
SolrInputDocument doc = new SolrInputDocument("id", "1");
|
||||
solrClient.add(collectionName1, doc);
|
||||
doc = new SolrInputDocument("id", "2");
|
||||
solrClient.add(collectionName2, doc);
|
||||
solrClient.commit(collectionName1);
|
||||
solrClient.commit(collectionName2);
|
||||
|
||||
assertDoc(solrClient, collectionName1, "1");
|
||||
assertDoc(solrClient, collectionName2, "2");
|
||||
|
||||
CollectionAdminRequest.createAlias(collectionName1, collectionName2).process(solrClient);
|
||||
|
||||
RetryUtil.retryUntil("didn't get the new aliases", 10, 1000, TimeUnit.MILLISECONDS, () -> {
|
||||
try {
|
||||
solrClient.getZkStateReader().aliasesManager.update();
|
||||
return solrClient.getZkStateReader().getAliases()
|
||||
.resolveSimpleAlias(collectionName1).equals(collectionName2);
|
||||
} catch (Exception e) {
|
||||
fail("exception caught refreshing aliases: " + e);
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
// both results should come from collection 2
|
||||
assertDoc(solrClient, collectionName1, "2"); // aliased
|
||||
assertDoc(solrClient, collectionName2, "2"); // direct
|
||||
|
||||
// should be able to remove collection 1 when followAliases = false
|
||||
CollectionAdminRequest.Delete delete = CollectionAdminRequest.deleteCollection(collectionName1);
|
||||
delete.setFollowAliases(false);
|
||||
delete.process(solrClient);
|
||||
ClusterState state = solrClient.getClusterStateProvider().getClusterState();
|
||||
assertFalse(state.getCollectionsMap().toString(), state.hasCollection(collectionName1));
|
||||
// search should still work, returning results from collection 2
|
||||
assertDoc(solrClient, collectionName1, "2"); // aliased
|
||||
assertDoc(solrClient, collectionName2, "2"); // direct
|
||||
|
||||
// without aliases this collection doesn't exist anymore
|
||||
delete = CollectionAdminRequest.deleteCollection(collectionName1);
|
||||
delete.setFollowAliases(false);
|
||||
try {
|
||||
delete.process(solrClient);
|
||||
fail("delete of nonexistent collection 1 should have failed when followAliases=false");
|
||||
} catch (Exception e) {
|
||||
assertTrue(e.toString(), e.toString().contains(collectionName1));
|
||||
}
|
||||
|
||||
// with followAliases=true collection 2 (and the alias) should both be removed
|
||||
delete.setFollowAliases(true);
|
||||
delete.process(solrClient);
|
||||
|
||||
state = solrClient.getClusterStateProvider().getClusterState();
|
||||
// the collection is gone
|
||||
assertFalse(state.getCollectionsMap().toString(), state.hasCollection(collectionName2));
|
||||
|
||||
// and the alias is gone
|
||||
RetryUtil.retryUntil("didn't get the new aliases", 10, 1000, TimeUnit.MILLISECONDS, () -> {
|
||||
try {
|
||||
solrClient.getZkStateReader().aliasesManager.update();
|
||||
return !solrClient.getZkStateReader().getAliases().hasAlias(collectionName1);
|
||||
} catch (Exception e) {
|
||||
fail("exception caught refreshing aliases: " + e);
|
||||
return false;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void assertDoc(CloudSolrClient solrClient, String collection, String id) throws Exception {
|
||||
QueryResponse rsp = solrClient.query(collection, params(CommonParams.Q, "*:*"));
|
||||
assertEquals(rsp.toString(), 1, rsp.getResults().getNumFound());
|
||||
SolrDocument sdoc = rsp.getResults().get(0);
|
||||
assertEquals(sdoc.toString(), id, sdoc.getFieldValue("id"));
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOverseerStatus() throws IOException, SolrServerException {
|
||||
CollectionAdminResponse response = new CollectionAdminRequest.OverseerStatus().process(cluster.getSolrClient());
|
||||
|
|
|
@ -150,8 +150,16 @@ public class ReindexCollectionTest extends SolrCloudTestCase {
|
|||
assertEquals("copied num docs", NUM_DOCS, queryResponse.getResults().getNumFound());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSameTargetReindexing() throws Exception {
|
||||
final String sourceCollection = "sameTargetReindexing";
|
||||
doTestSameTargetReindexing(false, false);
|
||||
doTestSameTargetReindexing(false, true);
|
||||
doTestSameTargetReindexing(true, false);
|
||||
doTestSameTargetReindexing(true, true);
|
||||
}
|
||||
|
||||
private void doTestSameTargetReindexing(boolean sourceRemove, boolean followAliases) throws Exception {
|
||||
final String sourceCollection = "sameTargetReindexing_" + sourceRemove + "_" + followAliases;
|
||||
final String targetCollection = sourceCollection;
|
||||
|
||||
createCollection(sourceCollection, "conf1", 2, 2);
|
||||
|
@ -160,6 +168,8 @@ public class ReindexCollectionTest extends SolrCloudTestCase {
|
|||
|
||||
CollectionAdminRequest.ReindexCollection req = CollectionAdminRequest.reindexCollection(sourceCollection)
|
||||
.setTarget(targetCollection);
|
||||
req.setRemoveSource(sourceRemove);
|
||||
req.setFollowAliases(followAliases);
|
||||
req.process(solrClient);
|
||||
|
||||
String realTargetCollection = null;
|
||||
|
@ -183,11 +193,16 @@ public class ReindexCollectionTest extends SolrCloudTestCase {
|
|||
ReindexCollectionCmd.State state = ReindexCollectionCmd.State.get(coll.getStr(ReindexCollectionCmd.REINDEXING_STATE));
|
||||
return ReindexCollectionCmd.State.FINISHED == state;
|
||||
});
|
||||
solrClient.getZkStateReader().aliasesManager.update();
|
||||
SolrTestCaseJ4.Solr11035BandAid(solrClient, targetCollection, "id", NUM_DOCS, "*:*",
|
||||
"ReindexCollectionTest.testSameTargetReindex", false);
|
||||
// verify the target docs exist
|
||||
QueryResponse rsp = solrClient.query(targetCollection, params(CommonParams.Q, "*:*"));
|
||||
assertEquals("copied num docs", NUM_DOCS, rsp.getResults().getNumFound());
|
||||
ClusterState state = solrClient.getClusterStateProvider().getClusterState();
|
||||
if (sourceRemove) {
|
||||
assertFalse("source collection still present", state.hasCollection(sourceCollection));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
@ -282,9 +282,15 @@ As always, patches and pull requests are welcome!
|
|||
Starting with version 8.1 SolrCloud supports using alias names in collection commands where normally a
|
||||
collection name is expected. This works only when the following criteria are satisfied:
|
||||
|
||||
* a request parameter `followAliases=true` is used
|
||||
* an alias must not refer to more than one collection
|
||||
* an alias must not refer to a <<Routed Aliases,Routed Alias>>
|
||||
|
||||
If all criteria are satisfied then the command will resolve alias names and operate on the collections the aliases
|
||||
If all criteria are satisfied then the command will resolve all alias names and operate on the collections the aliases
|
||||
refer to as if it was invoked with the collection names instead. Otherwise the command will not be executed and
|
||||
an exception will be thrown.
|
||||
|
||||
The `followAliases=true` parameter should be used with care so that the resolved targets are indeed the intended ones.
|
||||
In case of multi-level aliases or shadow aliases (an alias with the same name as an existing collection but pointing
|
||||
to other collections) the use of this option is strongly discouraged because effects may be difficult to
|
||||
predict correctly.
|
||||
|
|
|
@ -246,6 +246,7 @@ public abstract class CollectionAdminRequest<T extends CollectionAdminResponse>
|
|||
protected abstract static class AsyncCollectionSpecificAdminRequest extends AsyncCollectionAdminRequest {
|
||||
|
||||
protected String collection;
|
||||
protected Boolean followAliases;
|
||||
|
||||
public AsyncCollectionSpecificAdminRequest(CollectionAction action, String collection) {
|
||||
super(action);
|
||||
|
@ -256,10 +257,15 @@ public abstract class CollectionAdminRequest<T extends CollectionAdminResponse>
|
|||
return collection;
|
||||
}
|
||||
|
||||
public void setFollowAliases(Boolean followAliases) {
|
||||
this.followAliases = followAliases;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SolrParams getParams() {
|
||||
ModifiableSolrParams params = new ModifiableSolrParams(super.getParams());
|
||||
params.set(CoreAdminParams.NAME, collection);
|
||||
params.setNonNull(CollectionAdminParams.FOLLOW_ALIASES, followAliases);
|
||||
return params;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -124,4 +124,7 @@ public interface CollectionAdminParams {
|
|||
* Prefix for {@link org.apache.solr.common.cloud.DocRouter} properties
|
||||
*/
|
||||
String ROUTER_PREFIX = "router.";
|
||||
|
||||
/** Option to follow aliases when deciding the target of a collection admin command. */
|
||||
String FOLLOW_ALIASES = "followAliases";
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue