mirror of https://github.com/apache/lucene.git
SOLR-13475: Null Pointer Exception when querying collection through collection alias.
This commit is contained in:
parent
62f969403a
commit
93e57e63cd
|
@ -93,6 +93,11 @@ New Features
|
||||||
* SOLR-12304: The MoreLikeThisComponent now supports the mlt.interestingTerms parameter. Previously this option was
|
* SOLR-12304: The MoreLikeThisComponent now supports the mlt.interestingTerms parameter. Previously this option was
|
||||||
unique to the MLT handler. (Alessandro Benedetti via David Smiley)
|
unique to the MLT handler. (Alessandro Benedetti via David Smiley)
|
||||||
|
|
||||||
|
Bug Fixes
|
||||||
|
----------------------
|
||||||
|
|
||||||
|
* SOLR-13475: Null Pointer Exception when querying collection through collection alias. (Jörn Franke, ab)
|
||||||
|
|
||||||
Other Changes
|
Other Changes
|
||||||
----------------------
|
----------------------
|
||||||
|
|
||||||
|
|
|
@ -85,6 +85,9 @@ public class CreateAliasCmd extends AliasCmd {
|
||||||
|
|
||||||
private void callCreatePlainAlias(ZkNodeProps message, String aliasName, ZkStateReader zkStateReader) {
|
private void callCreatePlainAlias(ZkNodeProps message, String aliasName, ZkStateReader zkStateReader) {
|
||||||
final List<String> canonicalCollectionList = parseCollectionsParameter(message.get("collections"));
|
final List<String> canonicalCollectionList = parseCollectionsParameter(message.get("collections"));
|
||||||
|
if (canonicalCollectionList.isEmpty()) {
|
||||||
|
throw new SolrException(BAD_REQUEST, "'collections' parameter doesn't contain any collection names.");
|
||||||
|
}
|
||||||
final String canonicalCollectionsString = StrUtils.join(canonicalCollectionList, ',');
|
final String canonicalCollectionsString = StrUtils.join(canonicalCollectionList, ',');
|
||||||
validateAllCollectionsExistAndNoDuplicates(canonicalCollectionList, zkStateReader);
|
validateAllCollectionsExistAndNoDuplicates(canonicalCollectionList, zkStateReader);
|
||||||
zkStateReader.aliasesManager
|
zkStateReader.aliasesManager
|
||||||
|
@ -101,6 +104,7 @@ public class CreateAliasCmd extends AliasCmd {
|
||||||
if (colls instanceof List) return (List<String>) colls;
|
if (colls instanceof List) return (List<String>) colls;
|
||||||
return StrUtils.splitSmart(colls.toString(), ",", true).stream()
|
return StrUtils.splitSmart(colls.toString(), ",", true).stream()
|
||||||
.map(String::trim)
|
.map(String::trim)
|
||||||
|
.filter(s -> !s.isEmpty())
|
||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -329,8 +329,10 @@ public class CreateCollectionCmd implements OverseerCollectionMessageHandler.Cmd
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// create an alias pointing to the new collection
|
// create an alias pointing to the new collection, if different from the collectionName
|
||||||
ocmh.zkStateReader.aliasesManager.applyModificationAndExportToZk(a -> a.cloneWithCollectionAlias(alias, collectionName));
|
if (!alias.equals(collectionName)) {
|
||||||
|
ocmh.zkStateReader.aliasesManager.applyModificationAndExportToZk(a -> a.cloneWithCollectionAlias(alias, collectionName));
|
||||||
|
}
|
||||||
|
|
||||||
} catch (SolrException ex) {
|
} catch (SolrException ex) {
|
||||||
throw ex;
|
throw ex;
|
||||||
|
|
|
@ -25,6 +25,7 @@ import static org.apache.solr.common.params.CommonAdminParams.ASYNC;
|
||||||
import static org.apache.solr.common.params.CommonParams.NAME;
|
import static org.apache.solr.common.params.CommonParams.NAME;
|
||||||
|
|
||||||
import java.lang.invoke.MethodHandles;
|
import java.lang.invoke.MethodHandles;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
@ -75,7 +76,7 @@ public class DeleteCollectionCmd implements OverseerCollectionMessageHandler.Cmd
|
||||||
zkStateReader.aliasesManager.update(); // aliases may have been stale; get latest from ZK
|
zkStateReader.aliasesManager.update(); // aliases may have been stale; get latest from ZK
|
||||||
}
|
}
|
||||||
|
|
||||||
String aliasReference = checkAliasReference(zkStateReader, extCollection);
|
List<String> aliasReferences = checkAliasReference(zkStateReader, extCollection);
|
||||||
|
|
||||||
Aliases aliases = zkStateReader.getAliases();
|
Aliases aliases = zkStateReader.getAliases();
|
||||||
String collection = aliases.resolveSimpleAlias(extCollection);
|
String collection = aliases.resolveSimpleAlias(extCollection);
|
||||||
|
@ -135,9 +136,14 @@ public class DeleteCollectionCmd implements OverseerCollectionMessageHandler.Cmd
|
||||||
// wait for a while until we don't see the collection
|
// wait for a while until we don't see the collection
|
||||||
zkStateReader.waitForState(collection, 60, TimeUnit.SECONDS, (liveNodes, collectionState) -> collectionState == null);
|
zkStateReader.waitForState(collection, 60, TimeUnit.SECONDS, (liveNodes, collectionState) -> collectionState == null);
|
||||||
|
|
||||||
// we can delete any remaining unique alias
|
// we can delete any remaining unique aliases
|
||||||
if (aliasReference != null) {
|
if (!aliasReferences.isEmpty()) {
|
||||||
ocmh.zkStateReader.aliasesManager.applyModificationAndExportToZk(a -> a.cloneWithCollectionAlias(aliasReference, null));
|
ocmh.zkStateReader.aliasesManager.applyModificationAndExportToZk(a -> {
|
||||||
|
for (String alias : aliasReferences) {
|
||||||
|
a = a.cloneWithCollectionAlias(alias, null);
|
||||||
|
}
|
||||||
|
return a;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// TimeOut timeout = new TimeOut(60, TimeUnit.SECONDS, timeSource);
|
// TimeOut timeout = new TimeOut(60, TimeUnit.SECONDS, timeSource);
|
||||||
|
@ -178,23 +184,29 @@ public class DeleteCollectionCmd implements OverseerCollectionMessageHandler.Cmd
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// it's ok if a collection is referenced either by none or exactly by a single alias.
|
// This method returns the single collection aliases to delete, if present, or null
|
||||||
// This method returns the single alias to delete, if present, or null
|
private List<String> checkAliasReference(ZkStateReader zkStateReader, String extCollection) throws Exception {
|
||||||
private String checkAliasReference(ZkStateReader zkStateReader, String extCollection) throws Exception {
|
Aliases aliases = zkStateReader.getAliases();
|
||||||
List<String> aliases = referencedByAlias(extCollection, zkStateReader.getAliases());
|
List<String> aliasesRefs = referencedByAlias(extCollection, aliases);
|
||||||
if (aliases.size() > 1) {
|
List<String> aliasesToDelete = new ArrayList<>();
|
||||||
|
if (aliasesRefs.size() > 0) {
|
||||||
zkStateReader.aliasesManager.update(); // aliases may have been stale; get latest from ZK
|
zkStateReader.aliasesManager.update(); // aliases may have been stale; get latest from ZK
|
||||||
aliases = referencedByAlias(extCollection, zkStateReader.getAliases());
|
aliases = zkStateReader.getAliases();
|
||||||
if (aliases.size() > 1) {
|
aliasesRefs = referencedByAlias(extCollection, aliases);
|
||||||
throw new SolrException(SolrException.ErrorCode.SERVER_ERROR,
|
if (aliasesRefs.size() > 0) {
|
||||||
"Collection : " + extCollection + " is part of aliases: " + aliases + ", remove or modify the aliases before removing this collection.");
|
for (String alias : aliasesRefs) {
|
||||||
|
// for back-compat in 8.x we don't automatically remove other
|
||||||
|
// aliases that point only to this collection
|
||||||
|
if (!extCollection.equals(alias)) {
|
||||||
|
throw new SolrException(SolrException.ErrorCode.SERVER_ERROR,
|
||||||
|
"Collection : " + extCollection + " is part of aliases: " + aliasesRefs + ", remove or modify the aliases before removing this collection.");
|
||||||
|
} else {
|
||||||
|
aliasesToDelete.add(alias);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!aliases.isEmpty()) {
|
return aliasesToDelete;
|
||||||
return aliases.get(0);
|
|
||||||
} else {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static List<String> referencedByAlias(String extCollection, Aliases aliases) throws IllegalArgumentException {
|
public static List<String> referencedByAlias(String extCollection, Aliases aliases) throws IllegalArgumentException {
|
||||||
|
|
|
@ -543,9 +543,19 @@ public class AliasIntegrationTest extends SolrCloudTestCase {
|
||||||
.commit(cluster.getSolrClient(), "collection2");
|
.commit(cluster.getSolrClient(), "collection2");
|
||||||
|
|
||||||
///////////////
|
///////////////
|
||||||
|
// make sure there's only one level of alias
|
||||||
|
CollectionAdminRequest.deleteAlias("collection1").process(cluster.getSolrClient());
|
||||||
CollectionAdminRequest.createAlias("testalias1", "collection1").process(cluster.getSolrClient());
|
CollectionAdminRequest.createAlias("testalias1", "collection1").process(cluster.getSolrClient());
|
||||||
|
|
||||||
// ensure that the alias has been registered
|
// verify proper resolution on the server-side
|
||||||
|
ZkStateReader zkStateReader = cluster.getSolrClient().getZkStateReader();
|
||||||
|
zkStateReader.aliasesManager.update();
|
||||||
|
Aliases aliases = zkStateReader.getAliases();
|
||||||
|
List<String> collections = aliases.resolveAliases("testalias1");
|
||||||
|
assertEquals(collections.toString(), 1, collections.size());
|
||||||
|
assertTrue(collections.contains("collection1"));
|
||||||
|
|
||||||
|
// ensure that the alias is visible in the API
|
||||||
assertEquals("collection1",
|
assertEquals("collection1",
|
||||||
new CollectionAdminRequest.ListAliases().process(cluster.getSolrClient()).getAliases().get("testalias1"));
|
new CollectionAdminRequest.ListAliases().process(cluster.getSolrClient()).getAliases().get("testalias1"));
|
||||||
|
|
||||||
|
|
|
@ -121,8 +121,8 @@ The name of the collection with which all replicas of this collection must be co
|
||||||
See <<colocating-collections.adoc#colocating-collections, Colocating collections>> for more details.
|
See <<colocating-collections.adoc#colocating-collections, Colocating collections>> for more details.
|
||||||
|
|
||||||
`alias`::
|
`alias`::
|
||||||
Starting with version 8.1 when a collection is created additionally an alias (by default with the same name) is created
|
Starting with version 8.1 when a collection is created additionally an alias can be created
|
||||||
that points to this collection. This parameter allows changing the name of this alias, effectively combining
|
that points to this collection. This parameter allows specifying the name of this alias, effectively combining
|
||||||
this operation with <<createalias, CREATEALIAS>>
|
this operation with <<createalias, CREATEALIAS>>
|
||||||
|
|
||||||
Collections are first created in read-write mode but can be put in `readOnly`
|
Collections are first created in read-write mode but can be put in `readOnly`
|
||||||
|
|
|
@ -248,11 +248,15 @@ public class Aliases {
|
||||||
for (int i = 0; i < level1.size(); i++) {
|
for (int i = 0; i < level1.size(); i++) {
|
||||||
String level1Alias = level1.get(i);
|
String level1Alias = level1.get(i);
|
||||||
List<String> level2 = collectionAliasListMap.get(level1Alias);
|
List<String> level2 = collectionAliasListMap.get(level1Alias);
|
||||||
if (level2 == null && uniqueResult != null) {
|
if (level2 == null) {
|
||||||
uniqueResult.add(level1Alias);
|
// will copy all level1alias-es so far on lazy init
|
||||||
|
if (uniqueResult != null) {
|
||||||
|
uniqueResult.add(level1Alias);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
if (uniqueResult == null) { // lazy init
|
if (uniqueResult == null) { // lazy init
|
||||||
uniqueResult = new LinkedHashSet<>(level1.size());
|
uniqueResult = new LinkedHashSet<>(level1.size());
|
||||||
|
// add all level1Alias-es so far
|
||||||
uniqueResult.addAll(level1.subList(0, i));
|
uniqueResult.addAll(level1.subList(0, i));
|
||||||
}
|
}
|
||||||
uniqueResult.addAll(level2);
|
uniqueResult.addAll(level2);
|
||||||
|
@ -294,6 +298,7 @@ public class Aliases {
|
||||||
entry.setValue(Collections.unmodifiableList(list));
|
entry.setValue(Collections.unmodifiableList(list));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
newColAliases.entrySet().removeIf(entry -> entry.getValue().isEmpty());
|
||||||
} else {
|
} else {
|
||||||
newColProperties = this.collectionAliasProperties;// no changes
|
newColProperties = this.collectionAliasProperties;// no changes
|
||||||
// java representation is a list, so split before adding to maintain consistency
|
// java representation is a list, so split before adding to maintain consistency
|
||||||
|
|
Loading…
Reference in New Issue