|  | @@ -22,7 +22,6 @@ package org.elasticsearch.cluster.metadata;
 | 
											
												
													
														|  |  import com.carrotsearch.hppc.ObjectHashSet;
 |  |  import com.carrotsearch.hppc.ObjectHashSet;
 | 
											
												
													
														|  |  import com.carrotsearch.hppc.cursors.ObjectCursor;
 |  |  import com.carrotsearch.hppc.cursors.ObjectCursor;
 | 
											
												
													
														|  |  import com.carrotsearch.hppc.cursors.ObjectObjectCursor;
 |  |  import com.carrotsearch.hppc.cursors.ObjectObjectCursor;
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  |  import org.apache.logging.log4j.Logger;
 |  |  import org.apache.logging.log4j.Logger;
 | 
											
												
													
														|  |  import org.apache.lucene.util.CollectionUtil;
 |  |  import org.apache.lucene.util.CollectionUtil;
 | 
											
												
													
														|  |  import org.elasticsearch.cluster.Diff;
 |  |  import org.elasticsearch.cluster.Diff;
 | 
											
										
											
												
													
														|  | @@ -33,6 +32,7 @@ import org.elasticsearch.cluster.NamedDiffableValueSerializer;
 | 
											
												
													
														|  |  import org.elasticsearch.cluster.block.ClusterBlock;
 |  |  import org.elasticsearch.cluster.block.ClusterBlock;
 | 
											
												
													
														|  |  import org.elasticsearch.cluster.block.ClusterBlockLevel;
 |  |  import org.elasticsearch.cluster.block.ClusterBlockLevel;
 | 
											
												
													
														|  |  import org.elasticsearch.common.Nullable;
 |  |  import org.elasticsearch.common.Nullable;
 | 
											
												
													
														|  | 
 |  | +import org.elasticsearch.common.Strings;
 | 
											
												
													
														|  |  import org.elasticsearch.common.UUIDs;
 |  |  import org.elasticsearch.common.UUIDs;
 | 
											
												
													
														|  |  import org.elasticsearch.common.collect.HppcMaps;
 |  |  import org.elasticsearch.common.collect.HppcMaps;
 | 
											
												
													
														|  |  import org.elasticsearch.common.collect.ImmutableOpenMap;
 |  |  import org.elasticsearch.common.collect.ImmutableOpenMap;
 | 
											
										
											
												
													
														|  | @@ -62,9 +62,11 @@ import java.util.Collections;
 | 
											
												
													
														|  |  import java.util.Comparator;
 |  |  import java.util.Comparator;
 | 
											
												
													
														|  |  import java.util.EnumSet;
 |  |  import java.util.EnumSet;
 | 
											
												
													
														|  |  import java.util.HashMap;
 |  |  import java.util.HashMap;
 | 
											
												
													
														|  | 
 |  | +import java.util.HashSet;
 | 
											
												
													
														|  |  import java.util.Iterator;
 |  |  import java.util.Iterator;
 | 
											
												
													
														|  |  import java.util.List;
 |  |  import java.util.List;
 | 
											
												
													
														|  |  import java.util.Map;
 |  |  import java.util.Map;
 | 
											
												
													
														|  | 
 |  | +import java.util.Set;
 | 
											
												
													
														|  |  import java.util.SortedMap;
 |  |  import java.util.SortedMap;
 | 
											
												
													
														|  |  import java.util.TreeMap;
 |  |  import java.util.TreeMap;
 | 
											
												
													
														|  |  
 |  |  
 | 
											
										
											
												
													
														|  | @@ -914,55 +916,70 @@ public class MetaData implements Iterable<IndexMetaData>, Diffable<MetaData>, To
 | 
											
												
													
														|  |              //    while these datastructures aren't even used.
 |  |              //    while these datastructures aren't even used.
 | 
											
												
													
														|  |              // 2) The aliasAndIndexLookup can be updated instead of rebuilding it all the time.
 |  |              // 2) The aliasAndIndexLookup can be updated instead of rebuilding it all the time.
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  | -            // build all concrete indices arrays:
 |  | 
 | 
											
												
													
														|  | -            // TODO: I think we can remove these arrays. it isn't worth the effort, for operations on all indices.
 |  | 
 | 
											
												
													
														|  | -            // When doing an operation across all indices, most of the time is spent on actually going to all shards and
 |  | 
 | 
											
												
													
														|  | -            // do the required operations, the bottleneck isn't resolving expressions into concrete indices.
 |  | 
 | 
											
												
													
														|  | -            List<String> allIndicesLst = new ArrayList<>();
 |  | 
 | 
											
												
													
														|  | 
 |  | +            final Set<String> allIndices = new HashSet<>(indices.size());
 | 
											
												
													
														|  | 
 |  | +            final List<String> allOpenIndices = new ArrayList<>();
 | 
											
												
													
														|  | 
 |  | +            final List<String> allClosedIndices = new ArrayList<>();
 | 
											
												
													
														|  | 
 |  | +            final Set<String> duplicateAliasesIndices = new HashSet<>();
 | 
											
												
													
														|  |              for (ObjectCursor<IndexMetaData> cursor : indices.values()) {
 |  |              for (ObjectCursor<IndexMetaData> cursor : indices.values()) {
 | 
											
												
													
														|  | -                allIndicesLst.add(cursor.value.getIndex().getName());
 |  | 
 | 
											
												
													
														|  | -            }
 |  | 
 | 
											
												
													
														|  | -            String[] allIndices = allIndicesLst.toArray(new String[allIndicesLst.size()]);
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | -            List<String> allOpenIndicesLst = new ArrayList<>();
 |  | 
 | 
											
												
													
														|  | -            List<String> allClosedIndicesLst = new ArrayList<>();
 |  | 
 | 
											
												
													
														|  | -            for (ObjectCursor<IndexMetaData> cursor : indices.values()) {
 |  | 
 | 
											
												
													
														|  | -                IndexMetaData indexMetaData = cursor.value;
 |  | 
 | 
											
												
													
														|  | 
 |  | +                final IndexMetaData indexMetaData = cursor.value;
 | 
											
												
													
														|  | 
 |  | +                final String name = indexMetaData.getIndex().getName();
 | 
											
												
													
														|  | 
 |  | +                boolean added = allIndices.add(name);
 | 
											
												
													
														|  | 
 |  | +                assert added : "double index named [" + name + "]";
 | 
											
												
													
														|  |                  if (indexMetaData.getState() == IndexMetaData.State.OPEN) {
 |  |                  if (indexMetaData.getState() == IndexMetaData.State.OPEN) {
 | 
											
												
													
														|  | -                    allOpenIndicesLst.add(indexMetaData.getIndex().getName());
 |  | 
 | 
											
												
													
														|  | 
 |  | +                    allOpenIndices.add(indexMetaData.getIndex().getName());
 | 
											
												
													
														|  |                  } else if (indexMetaData.getState() == IndexMetaData.State.CLOSE) {
 |  |                  } else if (indexMetaData.getState() == IndexMetaData.State.CLOSE) {
 | 
											
												
													
														|  | -                    allClosedIndicesLst.add(indexMetaData.getIndex().getName());
 |  | 
 | 
											
												
													
														|  | 
 |  | +                    allClosedIndices.add(indexMetaData.getIndex().getName());
 | 
											
												
													
														|  | 
 |  | +                }
 | 
											
												
													
														|  | 
 |  | +                indexMetaData.getAliases().keysIt().forEachRemaining(duplicateAliasesIndices::add);
 | 
											
												
													
														|  | 
 |  | +            }
 | 
											
												
													
														|  | 
 |  | +            duplicateAliasesIndices.retainAll(allIndices);
 | 
											
												
													
														|  | 
 |  | +            if (duplicateAliasesIndices.isEmpty() == false) {
 | 
											
												
													
														|  | 
 |  | +                // iterate again and constructs a helpful message
 | 
											
												
													
														|  | 
 |  | +                ArrayList<String> duplicates = new ArrayList<>();
 | 
											
												
													
														|  | 
 |  | +                for (ObjectCursor<IndexMetaData> cursor : indices.values()) {
 | 
											
												
													
														|  | 
 |  | +                    for (String alias: duplicateAliasesIndices) {
 | 
											
												
													
														|  | 
 |  | +                        if (cursor.value.getAliases().containsKey(alias)) {
 | 
											
												
													
														|  | 
 |  | +                            duplicates.add(alias + " (alias of " + cursor.value.getIndex() + ")");
 | 
											
												
													
														|  | 
 |  | +                        }
 | 
											
												
													
														|  | 
 |  | +                    }
 | 
											
												
													
														|  |                  }
 |  |                  }
 | 
											
												
													
														|  | 
 |  | +                assert duplicates.size() > 0;
 | 
											
												
													
														|  | 
 |  | +                throw new IllegalStateException("index and alias names need to be unique, but the following duplicates were found ["
 | 
											
												
													
														|  | 
 |  | +                    + Strings.collectionToCommaDelimitedString(duplicates)+ "]");
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  |              }
 |  |              }
 | 
											
												
													
														|  | -            String[] allOpenIndices = allOpenIndicesLst.toArray(new String[allOpenIndicesLst.size()]);
 |  | 
 | 
											
												
													
														|  | -            String[] allClosedIndices = allClosedIndicesLst.toArray(new String[allClosedIndicesLst.size()]);
 |  | 
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  |              // build all indices map
 |  |              // build all indices map
 | 
											
												
													
														|  |              SortedMap<String, AliasOrIndex> aliasAndIndexLookup = new TreeMap<>();
 |  |              SortedMap<String, AliasOrIndex> aliasAndIndexLookup = new TreeMap<>();
 | 
											
												
													
														|  |              for (ObjectCursor<IndexMetaData> cursor : indices.values()) {
 |  |              for (ObjectCursor<IndexMetaData> cursor : indices.values()) {
 | 
											
												
													
														|  |                  IndexMetaData indexMetaData = cursor.value;
 |  |                  IndexMetaData indexMetaData = cursor.value;
 | 
											
												
													
														|  | -                aliasAndIndexLookup.put(indexMetaData.getIndex().getName(), new AliasOrIndex.Index(indexMetaData));
 |  | 
 | 
											
												
													
														|  | 
 |  | +                AliasOrIndex existing = aliasAndIndexLookup.put(indexMetaData.getIndex().getName(), new AliasOrIndex.Index(indexMetaData));
 | 
											
												
													
														|  | 
 |  | +                assert existing == null : "duplicate for " + indexMetaData.getIndex();
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  |                  for (ObjectObjectCursor<String, AliasMetaData> aliasCursor : indexMetaData.getAliases()) {
 |  |                  for (ObjectObjectCursor<String, AliasMetaData> aliasCursor : indexMetaData.getAliases()) {
 | 
											
												
													
														|  |                      AliasMetaData aliasMetaData = aliasCursor.value;
 |  |                      AliasMetaData aliasMetaData = aliasCursor.value;
 | 
											
												
													
														|  | -                    AliasOrIndex aliasOrIndex = aliasAndIndexLookup.get(aliasMetaData.getAlias());
 |  | 
 | 
											
												
													
														|  | -                    if (aliasOrIndex == null) {
 |  | 
 | 
											
												
													
														|  | -                        aliasOrIndex = new AliasOrIndex.Alias(aliasMetaData, indexMetaData);
 |  | 
 | 
											
												
													
														|  | -                        aliasAndIndexLookup.put(aliasMetaData.getAlias(), aliasOrIndex);
 |  | 
 | 
											
												
													
														|  | -                    } else if (aliasOrIndex instanceof AliasOrIndex.Alias) {
 |  | 
 | 
											
												
													
														|  | -                        AliasOrIndex.Alias alias = (AliasOrIndex.Alias) aliasOrIndex;
 |  | 
 | 
											
												
													
														|  | -                        alias.addIndex(indexMetaData);
 |  | 
 | 
											
												
													
														|  | -                    } else if (aliasOrIndex instanceof AliasOrIndex.Index) {
 |  | 
 | 
											
												
													
														|  | -                        AliasOrIndex.Index index = (AliasOrIndex.Index) aliasOrIndex;
 |  | 
 | 
											
												
													
														|  | -                        throw new IllegalStateException("index and alias names need to be unique, but alias [" + aliasMetaData.getAlias() + "] and index " + index.getIndex().getIndex() + " have the same name");
 |  | 
 | 
											
												
													
														|  | -                    } else {
 |  | 
 | 
											
												
													
														|  | -                        throw new IllegalStateException("unexpected alias [" + aliasMetaData.getAlias() + "][" + aliasOrIndex + "]");
 |  | 
 | 
											
												
													
														|  | -                    }
 |  | 
 | 
											
												
													
														|  | 
 |  | +                    aliasAndIndexLookup.compute(aliasMetaData.getAlias(), (aliasName, alias) -> {
 | 
											
												
													
														|  | 
 |  | +                        if (alias == null) {
 | 
											
												
													
														|  | 
 |  | +                            return new AliasOrIndex.Alias(aliasMetaData, indexMetaData);
 | 
											
												
													
														|  | 
 |  | +                        } else {
 | 
											
												
													
														|  | 
 |  | +                            assert alias instanceof AliasOrIndex.Alias : alias.getClass().getName();
 | 
											
												
													
														|  | 
 |  | +                            ((AliasOrIndex.Alias) alias).addIndex(indexMetaData);
 | 
											
												
													
														|  | 
 |  | +                            return alias;
 | 
											
												
													
														|  | 
 |  | +                        }
 | 
											
												
													
														|  | 
 |  | +                    });
 | 
											
												
													
														|  |                  }
 |  |                  }
 | 
											
												
													
														|  |              }
 |  |              }
 | 
											
												
													
														|  |              aliasAndIndexLookup = Collections.unmodifiableSortedMap(aliasAndIndexLookup);
 |  |              aliasAndIndexLookup = Collections.unmodifiableSortedMap(aliasAndIndexLookup);
 | 
											
												
													
														|  | 
 |  | +            // build all concrete indices arrays:
 | 
											
												
													
														|  | 
 |  | +            // TODO: I think we can remove these arrays. it isn't worth the effort, for operations on all indices.
 | 
											
												
													
														|  | 
 |  | +            // When doing an operation across all indices, most of the time is spent on actually going to all shards and
 | 
											
												
													
														|  | 
 |  | +            // do the required operations, the bottleneck isn't resolving expressions into concrete indices.
 | 
											
												
													
														|  | 
 |  | +            String[] allIndicesArray = allIndices.toArray(new String[allIndices.size()]);
 | 
											
												
													
														|  | 
 |  | +            String[] allOpenIndicesArray = allOpenIndices.toArray(new String[allOpenIndices.size()]);
 | 
											
												
													
														|  | 
 |  | +            String[] allClosedIndicesArray = allClosedIndices.toArray(new String[allClosedIndices.size()]);
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  |              return new MetaData(clusterUUID, version, transientSettings, persistentSettings, indices.build(), templates.build(),
 |  |              return new MetaData(clusterUUID, version, transientSettings, persistentSettings, indices.build(), templates.build(),
 | 
											
												
													
														|  | -                                customs.build(), allIndices, allOpenIndices, allClosedIndices, aliasAndIndexLookup);
 |  | 
 | 
											
												
													
														|  | 
 |  | +                                customs.build(), allIndicesArray, allOpenIndicesArray, allClosedIndicesArray, aliasAndIndexLookup);
 | 
											
												
													
														|  |          }
 |  |          }
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  |          public static String toXContent(MetaData metaData) throws IOException {
 |  |          public static String toXContent(MetaData metaData) throws IOException {
 |