|
35 | 35 | import org.elasticsearch.cluster.routing.allocation.DiskThresholdSettings; |
36 | 36 | import org.elasticsearch.cluster.service.ClusterService; |
37 | 37 | import org.elasticsearch.common.Nullable; |
| 38 | +import org.elasticsearch.common.Strings; |
38 | 39 | import org.elasticsearch.common.UUIDs; |
39 | 40 | import org.elasticsearch.common.collect.HppcMaps; |
40 | 41 | import org.elasticsearch.common.collect.ImmutableOpenMap; |
|
68 | 69 | import java.util.Comparator; |
69 | 70 | import java.util.EnumSet; |
70 | 71 | import java.util.HashMap; |
| 72 | +import java.util.HashSet; |
71 | 73 | import java.util.Iterator; |
72 | 74 | import java.util.List; |
73 | 75 | import java.util.Map; |
@@ -998,55 +1000,70 @@ public MetaData build() { |
998 | 1000 | // while these datastructures aren't even used. |
999 | 1001 | // 2) The aliasAndIndexLookup can be updated instead of rebuilding it all the time. |
1000 | 1002 |
|
1001 | | - // build all concrete indices arrays: |
1002 | | - // TODO: I think we can remove these arrays. it isn't worth the effort, for operations on all indices. |
1003 | | - // When doing an operation across all indices, most of the time is spent on actually going to all shards and |
1004 | | - // do the required operations, the bottleneck isn't resolving expressions into concrete indices. |
1005 | | - List<String> allIndicesLst = new ArrayList<>(); |
| 1003 | + final Set<String> allIndices = new HashSet<>(indices.size()); |
| 1004 | + final List<String> allOpenIndices = new ArrayList<>(); |
| 1005 | + final List<String> allClosedIndices = new ArrayList<>(); |
| 1006 | + final Set<String> duplicateAliasesIndices = new HashSet<>(); |
1006 | 1007 | for (ObjectCursor<IndexMetaData> cursor : indices.values()) { |
1007 | | - allIndicesLst.add(cursor.value.getIndex().getName()); |
1008 | | - } |
1009 | | - String[] allIndices = allIndicesLst.toArray(new String[allIndicesLst.size()]); |
1010 | | - |
1011 | | - List<String> allOpenIndicesLst = new ArrayList<>(); |
1012 | | - List<String> allClosedIndicesLst = new ArrayList<>(); |
1013 | | - for (ObjectCursor<IndexMetaData> cursor : indices.values()) { |
1014 | | - IndexMetaData indexMetaData = cursor.value; |
| 1008 | + final IndexMetaData indexMetaData = cursor.value; |
| 1009 | + final String name = indexMetaData.getIndex().getName(); |
| 1010 | + boolean added = allIndices.add(name); |
| 1011 | + assert added : "double index named [" + name + "]"; |
1015 | 1012 | if (indexMetaData.getState() == IndexMetaData.State.OPEN) { |
1016 | | - allOpenIndicesLst.add(indexMetaData.getIndex().getName()); |
| 1013 | + allOpenIndices.add(indexMetaData.getIndex().getName()); |
1017 | 1014 | } else if (indexMetaData.getState() == IndexMetaData.State.CLOSE) { |
1018 | | - allClosedIndicesLst.add(indexMetaData.getIndex().getName()); |
| 1015 | + allClosedIndices.add(indexMetaData.getIndex().getName()); |
1019 | 1016 | } |
| 1017 | + indexMetaData.getAliases().keysIt().forEachRemaining(duplicateAliasesIndices::add); |
| 1018 | + } |
| 1019 | + duplicateAliasesIndices.retainAll(allIndices); |
| 1020 | + if (duplicateAliasesIndices.isEmpty() == false) { |
| 1021 | + // iterate again and constructs a helpful message |
| 1022 | + ArrayList<String> duplicates = new ArrayList<>(); |
| 1023 | + for (ObjectCursor<IndexMetaData> cursor : indices.values()) { |
| 1024 | + for (String alias: duplicateAliasesIndices) { |
| 1025 | + if (cursor.value.getAliases().containsKey(alias)) { |
| 1026 | + duplicates.add(alias + " (alias of " + cursor.value.getIndex() + ")"); |
| 1027 | + } |
| 1028 | + } |
| 1029 | + } |
| 1030 | + assert duplicates.size() > 0; |
| 1031 | + throw new IllegalStateException("index and alias names need to be unique, but the following duplicates were found [" |
| 1032 | + + Strings.collectionToCommaDelimitedString(duplicates)+ "]"); |
| 1033 | + |
1020 | 1034 | } |
1021 | | - String[] allOpenIndices = allOpenIndicesLst.toArray(new String[allOpenIndicesLst.size()]); |
1022 | | - String[] allClosedIndices = allClosedIndicesLst.toArray(new String[allClosedIndicesLst.size()]); |
1023 | 1035 |
|
1024 | 1036 | // build all indices map |
1025 | 1037 | SortedMap<String, AliasOrIndex> aliasAndIndexLookup = new TreeMap<>(); |
1026 | 1038 | for (ObjectCursor<IndexMetaData> cursor : indices.values()) { |
1027 | 1039 | IndexMetaData indexMetaData = cursor.value; |
1028 | | - aliasAndIndexLookup.put(indexMetaData.getIndex().getName(), new AliasOrIndex.Index(indexMetaData)); |
| 1040 | + AliasOrIndex existing = aliasAndIndexLookup.put(indexMetaData.getIndex().getName(), new AliasOrIndex.Index(indexMetaData)); |
| 1041 | + assert existing == null : "duplicate for " + indexMetaData.getIndex(); |
1029 | 1042 |
|
1030 | 1043 | for (ObjectObjectCursor<String, AliasMetaData> aliasCursor : indexMetaData.getAliases()) { |
1031 | 1044 | AliasMetaData aliasMetaData = aliasCursor.value; |
1032 | | - AliasOrIndex aliasOrIndex = aliasAndIndexLookup.get(aliasMetaData.getAlias()); |
1033 | | - if (aliasOrIndex == null) { |
1034 | | - aliasOrIndex = new AliasOrIndex.Alias(aliasMetaData, indexMetaData); |
1035 | | - aliasAndIndexLookup.put(aliasMetaData.getAlias(), aliasOrIndex); |
1036 | | - } else if (aliasOrIndex instanceof AliasOrIndex.Alias) { |
1037 | | - AliasOrIndex.Alias alias = (AliasOrIndex.Alias) aliasOrIndex; |
1038 | | - alias.addIndex(indexMetaData); |
1039 | | - } else if (aliasOrIndex instanceof AliasOrIndex.Index) { |
1040 | | - AliasOrIndex.Index index = (AliasOrIndex.Index) aliasOrIndex; |
1041 | | - throw new IllegalStateException("index and alias names need to be unique, but alias [" + aliasMetaData.getAlias() + "] and index " + index.getIndex().getIndex() + " have the same name"); |
1042 | | - } else { |
1043 | | - throw new IllegalStateException("unexpected alias [" + aliasMetaData.getAlias() + "][" + aliasOrIndex + "]"); |
1044 | | - } |
| 1045 | + aliasAndIndexLookup.compute(aliasMetaData.getAlias(), (aliasName, alias) -> { |
| 1046 | + if (alias == null) { |
| 1047 | + return new AliasOrIndex.Alias(aliasMetaData, indexMetaData); |
| 1048 | + } else { |
| 1049 | + assert alias instanceof AliasOrIndex.Alias : alias.getClass().getName(); |
| 1050 | + ((AliasOrIndex.Alias) alias).addIndex(indexMetaData); |
| 1051 | + return alias; |
| 1052 | + } |
| 1053 | + }); |
1045 | 1054 | } |
1046 | 1055 | } |
1047 | 1056 | aliasAndIndexLookup = Collections.unmodifiableSortedMap(aliasAndIndexLookup); |
| 1057 | + // build all concrete indices arrays: |
| 1058 | + // TODO: I think we can remove these arrays. it isn't worth the effort, for operations on all indices. |
| 1059 | + // When doing an operation across all indices, most of the time is spent on actually going to all shards and |
| 1060 | + // do the required operations, the bottleneck isn't resolving expressions into concrete indices. |
| 1061 | + String[] allIndicesArray = allIndices.toArray(new String[allIndices.size()]); |
| 1062 | + String[] allOpenIndicesArray = allOpenIndices.toArray(new String[allOpenIndices.size()]); |
| 1063 | + String[] allClosedIndicesArray = allClosedIndices.toArray(new String[allClosedIndices.size()]); |
| 1064 | + |
1048 | 1065 | return new MetaData(clusterUUID, version, transientSettings, persistentSettings, indices.build(), templates.build(), |
1049 | | - customs.build(), allIndices, allOpenIndices, allClosedIndices, aliasAndIndexLookup); |
| 1066 | + customs.build(), allIndicesArray, allOpenIndicesArray, allClosedIndicesArray, aliasAndIndexLookup); |
1050 | 1067 | } |
1051 | 1068 |
|
1052 | 1069 | public static String toXContent(MetaData metaData) throws IOException { |
|
0 commit comments