diff --git a/src/main/java/org/elasticsearch/action/admin/indices/alias/IndicesAliasesRequest.java b/src/main/java/org/elasticsearch/action/admin/indices/alias/IndicesAliasesRequest.java index 19a47283e48..2be1fa6397f 100644 --- a/src/main/java/org/elasticsearch/action/admin/indices/alias/IndicesAliasesRequest.java +++ b/src/main/java/org/elasticsearch/action/admin/indices/alias/IndicesAliasesRequest.java @@ -143,6 +143,10 @@ public class IndicesAliasesRequest extends MasterNodeOperationRequest getAliasActions() { + return aliasActions(); + } + /** * Timeout to wait till the put mapping gets acknowledged of all current cluster nodes. Defaults to * 10s. diff --git a/src/main/java/org/elasticsearch/action/admin/indices/exists/types/TransportTypesExistsAction.java b/src/main/java/org/elasticsearch/action/admin/indices/exists/types/TransportTypesExistsAction.java index e7e7871e8ae..f20bb47a990 100644 --- a/src/main/java/org/elasticsearch/action/admin/indices/exists/types/TransportTypesExistsAction.java +++ b/src/main/java/org/elasticsearch/action/admin/indices/exists/types/TransportTypesExistsAction.java @@ -19,7 +19,6 @@ package org.elasticsearch.action.admin.indices.exists.types; -import com.google.common.collect.ImmutableMap; import org.elasticsearch.ElasticSearchException; import org.elasticsearch.action.ActionListener; import org.elasticsearch.action.support.master.TransportMasterNodeOperationAction; @@ -33,6 +32,8 @@ import org.elasticsearch.common.settings.Settings; import org.elasticsearch.threadpool.ThreadPool; import org.elasticsearch.transport.TransportService; +import java.util.Map; + /** * Types exists transport action. */ @@ -84,7 +85,7 @@ public class TransportTypesExistsAction extends TransportMasterNodeOperationActi return; } - ImmutableMap mappings = state.metaData().getIndices().get(concreteIndex).mappings(); + Map mappings = state.metaData().getIndices().get(concreteIndex).mappings(); if (mappings.isEmpty()) { listener.onResponse(new TypesExistsResponse(false)); return; diff --git a/src/main/java/org/elasticsearch/cluster/ClusterChangedEvent.java b/src/main/java/org/elasticsearch/cluster/ClusterChangedEvent.java index 305b539e25b..737496e723b 100644 --- a/src/main/java/org/elasticsearch/cluster/ClusterChangedEvent.java +++ b/src/main/java/org/elasticsearch/cluster/ClusterChangedEvent.java @@ -20,7 +20,6 @@ package org.elasticsearch.cluster; import com.google.common.collect.ImmutableList; -import com.google.common.collect.ImmutableMap; import com.google.common.collect.Lists; import org.elasticsearch.cluster.metadata.IndexMetaData; import org.elasticsearch.cluster.metadata.MetaData; @@ -166,8 +165,8 @@ public class ClusterChangedEvent { public boolean indicesStateChanged() { if (metaDataChanged()) { - ImmutableMap indices = state.metaData().indices(); - ImmutableMap previousIndices = previousState.metaData().indices(); + Map indices = state.metaData().indices(); + Map previousIndices = previousState.metaData().indices(); for (Map.Entry entry : indices.entrySet()) { IndexMetaData indexMetaData = entry.getValue(); diff --git a/src/main/java/org/elasticsearch/cluster/metadata/AliasMetaData.java b/src/main/java/org/elasticsearch/cluster/metadata/AliasMetaData.java index aa37118858b..3ea01962211 100644 --- a/src/main/java/org/elasticsearch/cluster/metadata/AliasMetaData.java +++ b/src/main/java/org/elasticsearch/cluster/metadata/AliasMetaData.java @@ -19,6 +19,7 @@ package org.elasticsearch.cluster.metadata; +import com.google.common.collect.ImmutableSet; import org.elasticsearch.ElasticSearchGenerationException; import org.elasticsearch.common.Strings; import org.elasticsearch.common.compress.CompressedString; @@ -30,7 +31,9 @@ import org.elasticsearch.common.xcontent.XContentFactory; import org.elasticsearch.common.xcontent.XContentParser; import java.io.IOException; +import java.util.Collections; import java.util.Map; +import java.util.Set; /** * @@ -41,15 +44,22 @@ public class AliasMetaData { private final CompressedString filter; - private String indexRouting; + private final String indexRouting; - private String searchRouting; + private final String searchRouting; + + private final Set searchRoutingValues; private AliasMetaData(String alias, CompressedString filter, String indexRouting, String searchRouting) { this.alias = alias; this.filter = filter; this.indexRouting = indexRouting; this.searchRouting = searchRouting; + if (searchRouting != null) { + searchRoutingValues = Collections.unmodifiableSet(Strings.splitStringByCommaToSet(searchRouting)); + } else { + searchRoutingValues = ImmutableSet.of(); + } } public String alias() { @@ -68,6 +78,10 @@ public class AliasMetaData { return filter(); } + public boolean filteringRequired() { + return filter != null; + } + public String getSearchRouting() { return searchRouting(); } @@ -84,6 +98,10 @@ public class AliasMetaData { return indexRouting; } + public Set searchRoutingValues() { + return searchRoutingValues; + } + public static Builder builder(String alias) { return new Builder(alias); } diff --git a/src/main/java/org/elasticsearch/cluster/metadata/IndexMetaData.java b/src/main/java/org/elasticsearch/cluster/metadata/IndexMetaData.java index 4794741f00e..7bac53e90c6 100644 --- a/src/main/java/org/elasticsearch/cluster/metadata/IndexMetaData.java +++ b/src/main/java/org/elasticsearch/cluster/metadata/IndexMetaData.java @@ -161,13 +161,13 @@ public class IndexMetaData { private final State state; - private final ImmutableMap aliases; + private final Map aliases; private final Settings settings; - private final ImmutableMap mappings; + private final Map mappings; - private final ImmutableMap customs; + private final Map customs; private transient final int totalNumberOfShards; @@ -175,7 +175,7 @@ public class IndexMetaData { private final DiscoveryNodeFilters includeFilters; private final DiscoveryNodeFilters excludeFilters; - private IndexMetaData(String index, long version, State state, Settings settings, ImmutableMap mappings, ImmutableMap aliases, ImmutableMap customs) { + private IndexMetaData(String index, long version, State state, Settings settings, Map mappings, Map aliases, Map customs) { Preconditions.checkArgument(settings.getAsInt(SETTING_NUMBER_OF_SHARDS, -1) != -1, "must specify numberOfShards for index [" + index + "]"); Preconditions.checkArgument(settings.getAsInt(SETTING_NUMBER_OF_REPLICAS, -1) != -1, "must specify numberOfReplicas for index [" + index + "]"); this.index = index; @@ -264,19 +264,19 @@ public class IndexMetaData { return settings(); } - public ImmutableMap aliases() { + public Map aliases() { return this.aliases; } - public ImmutableMap getAliases() { + public Map getAliases() { return aliases(); } - public ImmutableMap mappings() { + public Map mappings() { return mappings; } - public ImmutableMap getMappings() { + public Map getMappings() { return mappings(); } @@ -301,11 +301,11 @@ public class IndexMetaData { return mappings.get(MapperService.DEFAULT_MAPPING); } - public ImmutableMap customs() { + public Map customs() { return this.customs; } - public ImmutableMap getCustoms() { + public Map getCustoms() { return this.customs; } @@ -508,7 +508,7 @@ public class IndexMetaData { AliasMetaData aliasMd = AliasMetaData.newAliasMetaDataBuilder(alias).build(); tmpAliases.put(alias, aliasMd); } - tmpAliases.putAll(aliases.immutableMap()); + tmpAliases.putAll(aliases.map()); // Remove index.aliases from settings once they are migrated to the new data structure tmpSettings = ImmutableSettings.settingsBuilder().put(settings).putArray("index.aliases").build(); } @@ -521,7 +521,7 @@ public class IndexMetaData { } } - return new IndexMetaData(index, version, state, tmpSettings, mappings.immutableMap(), tmpAliases.immutableMap(), customs.immutableMap()); + return new IndexMetaData(index, version, state, tmpSettings, mappings.readOnlyMap(), tmpAliases.readOnlyMap(), customs.readOnlyMap()); } public static void toXContent(IndexMetaData indexMetaData, XContentBuilder builder, ToXContent.Params params) throws IOException { diff --git a/src/main/java/org/elasticsearch/cluster/metadata/MetaData.java b/src/main/java/org/elasticsearch/cluster/metadata/MetaData.java index f90468a6ce7..1fe8b3f5c70 100644 --- a/src/main/java/org/elasticsearch/cluster/metadata/MetaData.java +++ b/src/main/java/org/elasticsearch/cluster/metadata/MetaData.java @@ -22,6 +22,8 @@ package org.elasticsearch.cluster.metadata; import com.google.common.base.Predicate; import com.google.common.collect.*; import gnu.trove.set.hash.THashSet; +import org.apache.lucene.util.ArrayUtil; +import org.apache.lucene.util.RamUsageEstimator; import org.elasticsearch.ElasticSearchIllegalArgumentException; import org.elasticsearch.action.support.IgnoreIndices; import org.elasticsearch.cluster.block.ClusterBlock; @@ -29,12 +31,14 @@ import org.elasticsearch.cluster.block.ClusterBlockLevel; import org.elasticsearch.common.Nullable; import org.elasticsearch.common.Strings; import org.elasticsearch.common.collect.MapBuilder; +import org.elasticsearch.common.collect.XMaps; import org.elasticsearch.common.io.stream.StreamInput; import org.elasticsearch.common.io.stream.StreamOutput; import org.elasticsearch.common.regex.Regex; import org.elasticsearch.common.settings.ImmutableSettings; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.loader.SettingsLoader; +import org.elasticsearch.common.trove.ExtTHashMap; import org.elasticsearch.common.xcontent.*; import org.elasticsearch.index.Index; import org.elasticsearch.indices.IndexMissingException; @@ -46,7 +50,6 @@ import java.util.*; import static com.google.common.collect.Lists.newArrayList; import static com.google.common.collect.Maps.newHashMap; -import static com.google.common.collect.Sets.newHashSet; import static org.elasticsearch.common.collect.MapBuilder.newMapBuilder; import static org.elasticsearch.common.settings.ImmutableSettings.*; @@ -105,9 +108,9 @@ public class MetaData implements Iterable { private final Settings transientSettings; private final Settings persistentSettings; private final Settings settings; - private final ImmutableMap indices; - private final ImmutableMap templates; - private final ImmutableMap customs; + private final Map indices; + private final Map templates; + private final Map customs; private final transient int totalNumberOfShards; // Transient ? not serializable anyway? private final int numberOfShards; @@ -117,29 +120,24 @@ public class MetaData implements Iterable { private final ImmutableSet allIndicesSet; private final String[] allOpenIndices; - private final ImmutableMap> aliases; + private final Map> aliases; + private final Map aliasAndIndexToIndexMap; - private final ImmutableMap>> aliasToIndexToSearchRoutingMap; - - // This map indicates if an alias associated with an index is filtering alias - private final ImmutableMap> indexToAliasFilteringRequiredMap; - - private final ImmutableMap aliasAndIndexToIndexMap; - - - MetaData(long version, Settings transientSettings, Settings persistentSettings, ImmutableMap indices, ImmutableMap templates, ImmutableMap customs) { + MetaData(long version, Settings transientSettings, Settings persistentSettings, Map indices, Map templates, Map customs) { this.version = version; this.transientSettings = transientSettings; this.persistentSettings = persistentSettings; this.settings = ImmutableSettings.settingsBuilder().put(persistentSettings).put(transientSettings).build(); - this.indices = ImmutableMap.copyOf(indices); + this.indices = indices; this.customs = customs; this.templates = templates; int totalNumberOfShards = 0; int numberOfShards = 0; + int numAliases = 0; for (IndexMetaData indexMetaData : indices.values()) { totalNumberOfShards += indexMetaData.totalNumberOfShards(); numberOfShards += indexMetaData.numberOfShards(); + numAliases += indexMetaData.aliases().size(); } this.totalNumberOfShards = totalNumberOfShards; this.numberOfShards = numberOfShards; @@ -151,6 +149,7 @@ public class MetaData implements Iterable { } allIndices = allIndicesLst.toArray(new String[allIndicesLst.size()]); allIndicesSet = ImmutableSet.copyOf(allIndices); + int numIndices = allIndicesSet.size(); List allOpenIndices = Lists.newArrayList(); for (IndexMetaData indexMetaData : indices.values()) { @@ -161,88 +160,49 @@ public class MetaData implements Iterable { this.allOpenIndices = allOpenIndices.toArray(new String[allOpenIndices.size()]); // build aliases map - MapBuilder> tmpAliasesMap = newMapBuilder(); + ExtTHashMap> aliases = new ExtTHashMap>(numAliases); for (IndexMetaData indexMetaData : indices.values()) { String index = indexMetaData.index(); for (AliasMetaData aliasMd : indexMetaData.aliases().values()) { - MapBuilder indexAliasMap = tmpAliasesMap.get(aliasMd.alias()); + Map indexAliasMap = aliases.get(aliasMd.alias()); if (indexAliasMap == null) { - indexAliasMap = newMapBuilder(); - tmpAliasesMap.put(aliasMd.alias(), indexAliasMap); + indexAliasMap = new ExtTHashMap(indices.size()); + aliases.put(aliasMd.alias(), indexAliasMap); } indexAliasMap.put(index, aliasMd); } } - MapBuilder> aliases = newMapBuilder(); - for (Map.Entry> alias : tmpAliasesMap.map().entrySet()) { - aliases.put(alias.getKey(), alias.getValue().immutableMap()); - } - this.aliases = aliases.immutableMap(); - - // build routing aliases set - MapBuilder>> tmpAliasToIndexToSearchRoutingMap = newMapBuilder(); - for (IndexMetaData indexMetaData : indices.values()) { - for (AliasMetaData aliasMd : indexMetaData.aliases().values()) { - MapBuilder> indexToSearchRoutingMap = tmpAliasToIndexToSearchRoutingMap.get(aliasMd.alias()); - if (indexToSearchRoutingMap == null) { - indexToSearchRoutingMap = newMapBuilder(); - tmpAliasToIndexToSearchRoutingMap.put(aliasMd.alias(), indexToSearchRoutingMap); - } - if (aliasMd.searchRouting() != null) { - indexToSearchRoutingMap.put(indexMetaData.index(), ImmutableSet.copyOf(Strings.splitStringByCommaToSet(aliasMd.searchRouting()))); - } else { - indexToSearchRoutingMap.put(indexMetaData.index(), ImmutableSet.of()); - } + for (int i = 0; i < aliases.internalValues().length; i++) { + if (aliases.internalValues()[i] != null) { + aliases.internalValues()[i] = XMaps.makeReadOnly((Map) aliases.internalValues()[i]); } } - MapBuilder>> aliasToIndexToSearchRoutingMap = newMapBuilder(); - for (Map.Entry>> alias : tmpAliasToIndexToSearchRoutingMap.map().entrySet()) { - aliasToIndexToSearchRoutingMap.put(alias.getKey(), alias.getValue().immutableMap()); - } - this.aliasToIndexToSearchRoutingMap = aliasToIndexToSearchRoutingMap.immutableMap(); + this.aliases = XMaps.makeReadOnly(aliases); - // build filtering required map - MapBuilder> filteringRequiredMap = newMapBuilder(); + ExtTHashMap aliasAndIndexToIndexMap = new ExtTHashMap(numAliases + numIndices); for (IndexMetaData indexMetaData : indices.values()) { - MapBuilder indexFilteringRequiredMap = newMapBuilder(); - // Filtering is not required for the index itself - indexFilteringRequiredMap.put(indexMetaData.index(), false); - for (AliasMetaData aliasMetaData : indexMetaData.aliases().values()) { - if (aliasMetaData.filter() != null) { - indexFilteringRequiredMap.put(aliasMetaData.alias(), true); - } else { - indexFilteringRequiredMap.put(aliasMetaData.alias(), false); - } + StringArray indicesLst = aliasAndIndexToIndexMap.get(indexMetaData.index()); + if (indicesLst == null) { + indicesLst = new StringArray(); + aliasAndIndexToIndexMap.put(indexMetaData.index(), indicesLst); } - filteringRequiredMap.put(indexMetaData.index(), indexFilteringRequiredMap.immutableMap()); - } - indexToAliasFilteringRequiredMap = filteringRequiredMap.immutableMap(); - - // build aliasAndIndex to Index map - MapBuilder> tmpAliasAndIndexToIndexBuilder = newMapBuilder(); - for (IndexMetaData indexMetaData : indices.values()) { - Set lst = tmpAliasAndIndexToIndexBuilder.get(indexMetaData.index()); - if (lst == null) { - lst = newHashSet(); - tmpAliasAndIndexToIndexBuilder.put(indexMetaData.index(), lst); - } - lst.add(indexMetaData.index()); + indicesLst.add(indexMetaData.index()); for (String alias : indexMetaData.aliases().keySet()) { - lst = tmpAliasAndIndexToIndexBuilder.get(alias); - if (lst == null) { - lst = newHashSet(); - tmpAliasAndIndexToIndexBuilder.put(alias, lst); + indicesLst = aliasAndIndexToIndexMap.get(alias); + if (indicesLst == null) { + indicesLst = new StringArray(); + aliasAndIndexToIndexMap.put(alias, indicesLst); } - lst.add(indexMetaData.index()); + indicesLst.add(indexMetaData.index()); } } - MapBuilder aliasAndIndexToIndexBuilder = newMapBuilder(); - for (Map.Entry> entry : tmpAliasAndIndexToIndexBuilder.map().entrySet()) { - aliasAndIndexToIndexBuilder.put(entry.getKey(), entry.getValue().toArray(new String[entry.getValue().size()])); + for (StringArray stringArray : aliasAndIndexToIndexMap.values()) { + stringArray.trim(); } - this.aliasAndIndexToIndexMap = aliasAndIndexToIndexBuilder.immutableMap(); + + this.aliasAndIndexToIndexMap = XMaps.makeReadOnly(aliasAndIndexToIndexMap); } public long version() { @@ -264,11 +224,11 @@ public class MetaData implements Iterable { return this.persistentSettings; } - public ImmutableMap> aliases() { + public Map> aliases() { return this.aliases; } - public ImmutableMap> getAliases() { + public Map> getAliases() { return aliases(); } @@ -438,7 +398,7 @@ public class MetaData implements Iterable { */ public String resolveIndexRouting(@Nullable String routing, String aliasOrIndex) { // Check if index is specified by an alias - ImmutableMap indexAliases = aliases.get(aliasOrIndex); + Map indexAliases = aliases.get(aliasOrIndex); if (indexAliases == null || indexAliases.isEmpty()) { return routing; } @@ -486,11 +446,11 @@ public class MetaData implements Iterable { } for (String aliasOrIndex : aliasesOrIndices) { - ImmutableMap> indexToRoutingMap = aliasToIndexToSearchRoutingMap.get(aliasOrIndex); + Map indexToRoutingMap = aliases.get(aliasOrIndex); if (indexToRoutingMap != null && !indexToRoutingMap.isEmpty()) { - for (Map.Entry> indexRouting : indexToRoutingMap.entrySet()) { + for (Map.Entry indexRouting : indexToRoutingMap.entrySet()) { if (!norouting.contains(indexRouting.getKey())) { - if (!indexRouting.getValue().isEmpty()) { + if (!indexRouting.getValue().searchRoutingValues().isEmpty()) { // Routing alias if (routings == null) { routings = newHashMap(); @@ -500,7 +460,7 @@ public class MetaData implements Iterable { r = new THashSet(); routings.put(indexRouting.getKey(), r); } - r.addAll(indexRouting.getValue()); + r.addAll(indexRouting.getValue().searchRoutingValues()); if (paramRouting != null) { r.retainAll(paramRouting); } @@ -558,13 +518,13 @@ public class MetaData implements Iterable { paramRouting = Strings.splitStringByCommaToSet(routing); } - ImmutableMap> indexToRoutingMap = aliasToIndexToSearchRoutingMap.get(aliasOrIndex); + Map indexToRoutingMap = aliases.get(aliasOrIndex); if (indexToRoutingMap != null && !indexToRoutingMap.isEmpty()) { // It's an alias - for (Map.Entry> indexRouting : indexToRoutingMap.entrySet()) { - if (!indexRouting.getValue().isEmpty()) { + for (Map.Entry indexRouting : indexToRoutingMap.entrySet()) { + if (!indexRouting.getValue().searchRoutingValues().isEmpty()) { // Routing alias - Set r = new THashSet(indexRouting.getValue()); + Set r = new THashSet(indexRouting.getValue().searchRoutingValues()); if (paramRouting != null) { r.retainAll(paramRouting); } @@ -639,11 +599,11 @@ public class MetaData implements Iterable { if (this.indices.containsKey(aliasOrIndex)) { return aliasesOrIndices; } - String[] actualLst = aliasAndIndexToIndexMap.get(aliasOrIndex); + StringArray actualLst = aliasAndIndexToIndexMap.get(aliasOrIndex); if (actualLst == null) { throw new IndexMissingException(new Index(aliasOrIndex)); } else { - return actualLst; + return actualLst.values; } } @@ -662,13 +622,13 @@ public class MetaData implements Iterable { Set actualIndices = new THashSet(); for (String index : aliasesOrIndices) { - String[] actualLst = aliasAndIndexToIndexMap.get(index); + StringArray actualLst = aliasAndIndexToIndexMap.get(index); if (actualLst == null) { if (ignoreIndices != IgnoreIndices.MISSING) { throw new IndexMissingException(new Index(index)); } } else { - for (String x : actualLst) { + for (String x : actualLst.values) { actualIndices.add(x); } } @@ -686,14 +646,14 @@ public class MetaData implements Iterable { return index; } // not an actual index, fetch from an alias - String[] lst = aliasAndIndexToIndexMap.get(index); + StringArray lst = aliasAndIndexToIndexMap.get(index); if (lst == null) { throw new IndexMissingException(new Index(index)); } - if (lst.length > 1) { - throw new ElasticSearchIllegalArgumentException("Alias [" + index + "] has more than one indices associated with it [" + Arrays.toString(lst) + "], can't execute a single index op"); + if (lst.values.length > 1) { + throw new ElasticSearchIllegalArgumentException("Alias [" + index + "] has more than one indices associated with it [" + Arrays.toString(lst.values) + "], can't execute a single index op"); } - return lst[0]; + return lst.values[0]; } public String[] convertFromWildcards(String[] aliasesOrIndices, boolean wildcardOnlyOpen, IgnoreIndices ignoreIndices) { @@ -780,27 +740,27 @@ public class MetaData implements Iterable { return indices.get(index); } - public ImmutableMap indices() { + public Map indices() { return this.indices; } - public ImmutableMap getIndices() { + public Map getIndices() { return indices(); } - public ImmutableMap templates() { + public Map templates() { return this.templates; } - public ImmutableMap getTemplates() { + public Map getTemplates() { return this.templates; } - public ImmutableMap customs() { + public Map customs() { return this.customs; } - public ImmutableMap getCustoms() { + public Map getCustoms() { return this.customs; } @@ -828,35 +788,42 @@ public class MetaData implements Iterable { *

Only aliases with filters are returned. If the indices list contains a non-filtering reference to * the index itself - null is returned. Returns null if no filtering is required.

*/ - public String[] filteringAliases(String index, String... indices) { - if (isAllIndices(indices)) { + public String[] filteringAliases(String index, String... indicesOrAliases) { + if (isAllIndices(indicesOrAliases)) { return null; } // optimize for the most common single index/alias scenario - if (indices.length == 1) { - String alias = indices[0]; - ImmutableMap aliasToFilteringRequiredMap = indexToAliasFilteringRequiredMap.get(index); - if (aliasToFilteringRequiredMap == null) { + if (indicesOrAliases.length == 1) { + String alias = indicesOrAliases[0]; + IndexMetaData indexMetaData = this.indices.get(index); + if (indexMetaData == null) { // Shouldn't happen throw new IndexMissingException(new Index(index)); } - Boolean filteringRequired = aliasToFilteringRequiredMap.get(alias); - if (filteringRequired == null || !filteringRequired) { + AliasMetaData aliasMetaData = indexMetaData.aliases().get(alias); + boolean filteringRequired = aliasMetaData != null && aliasMetaData.filteringRequired(); + if (!filteringRequired) { return null; } return new String[]{alias}; } List filteringAliases = null; - for (String alias : indices) { - ImmutableMap aliasToFilteringRequiredMap = indexToAliasFilteringRequiredMap.get(index); - if (aliasToFilteringRequiredMap == null) { + for (String alias : indicesOrAliases) { + if (alias.equals(index)) { + return null; + } + + IndexMetaData indexMetaData = this.indices.get(index); + if (indexMetaData == null) { // Shouldn't happen throw new IndexMissingException(new Index(index)); } - Boolean filteringRequired = aliasToFilteringRequiredMap.get(alias); + + AliasMetaData aliasMetaData = indexMetaData.aliases().get(alias); // Check that this is an alias for the current index // Otherwise - skip it - if (filteringRequired != null) { + if (aliasMetaData != null) { + boolean filteringRequired = aliasMetaData.filteringRequired(); if (filteringRequired) { // If filtering required - add it to the list of filters if (filteringAliases == null) { @@ -925,7 +892,7 @@ public class MetaData implements Iterable { } @Override - public UnmodifiableIterator iterator() { + public Iterator iterator() { return indices.values().iterator(); } @@ -1082,7 +1049,7 @@ public class MetaData implements Iterable { } public MetaData build() { - return new MetaData(version, transientSettings, persistentSettings, indices.immutableMap(), templates.immutableMap(), customs.immutableMap()); + return new MetaData(version, transientSettings, persistentSettings, indices.readOnlyMap(), templates.readOnlyMap(), customs.readOnlyMap()); } public static String toXContent(MetaData metaData) throws IOException { @@ -1224,4 +1191,35 @@ public class MetaData implements Iterable { } } } + + static class StringArray { + + String[] values = new String[1]; + int head = 0; + + void add(String value) { + if (head == values.length) { + grow(); + } + values[head++] = value; + } + + void grow() { + int newSize = values.length + 1; + String[] newValues = new String[ArrayUtil.oversize(newSize, RamUsageEstimator.NUM_BYTES_OBJECT_REF)]; + System.arraycopy(values, 0, newValues, 0, values.length); + values = newValues; + } + + void trim() { + if (values.length == head) { + return; + } + + String[] newValues = new String[head]; + System.arraycopy(values, 0, newValues, 0, head); + values = newValues; + } + + } } diff --git a/src/main/java/org/elasticsearch/cluster/metadata/MetaDataIndexAliasesService.java b/src/main/java/org/elasticsearch/cluster/metadata/MetaDataIndexAliasesService.java index 4a84c3f0a1c..d4286fe67a9 100644 --- a/src/main/java/org/elasticsearch/cluster/metadata/MetaDataIndexAliasesService.java +++ b/src/main/java/org/elasticsearch/cluster/metadata/MetaDataIndexAliasesService.java @@ -110,6 +110,7 @@ public class MetaDataIndexAliasesService extends AbstractComponent { if (indexMetaData == null) { throw new IndexMissingException(new Index(aliasAction.index())); } + // TODO: not copy (putAll) IndexMetaData.Builder indexMetaDataBuilder = newIndexMetaDataBuilder(indexMetaData); if (aliasAction.actionType() == AliasAction.Type.ADD) { String filter = aliasAction.filter(); diff --git a/src/main/java/org/elasticsearch/common/collect/MapBuilder.java b/src/main/java/org/elasticsearch/common/collect/MapBuilder.java index dd069e90c24..6d107c13147 100644 --- a/src/main/java/org/elasticsearch/common/collect/MapBuilder.java +++ b/src/main/java/org/elasticsearch/common/collect/MapBuilder.java @@ -80,6 +80,10 @@ public class MapBuilder { return this.map; } + public Map readOnlyMap() { + return XMaps.makeReadOnly(map); + } + public ImmutableMap immutableMap() { return ImmutableMap.copyOf(map); } diff --git a/src/main/java/org/elasticsearch/common/collect/XMaps.java b/src/main/java/org/elasticsearch/common/collect/XMaps.java index 63b1d260b15..52e51081285 100644 --- a/src/main/java/org/elasticsearch/common/collect/XMaps.java +++ b/src/main/java/org/elasticsearch/common/collect/XMaps.java @@ -19,14 +19,13 @@ package org.elasticsearch.common.collect; +import com.google.common.collect.ForwardingMap; import gnu.trove.impl.Constants; - -import java.util.Map; - import org.elasticsearch.ElasticSearchIllegalArgumentException; import org.elasticsearch.common.trove.ExtTHashMap; -import com.google.common.collect.ForwardingMap; +import java.util.Collections; +import java.util.Map; /** * This class provides factory methods for Maps. The returned {@link Map} @@ -89,4 +88,12 @@ public final class XMaps { } }; } + + /** + * Wraps the given map into a read only implementation. + */ + public static Map makeReadOnly(Map map) { + return Collections.unmodifiableMap(map); + } + } diff --git a/src/main/java/org/elasticsearch/index/aliases/IndexAliasesService.java b/src/main/java/org/elasticsearch/index/aliases/IndexAliasesService.java index 47b1de66fd6..3acb0ec2ad3 100644 --- a/src/main/java/org/elasticsearch/index/aliases/IndexAliasesService.java +++ b/src/main/java/org/elasticsearch/index/aliases/IndexAliasesService.java @@ -19,8 +19,6 @@ package org.elasticsearch.index.aliases; -import com.google.common.collect.ImmutableMap; -import com.google.common.collect.UnmodifiableIterator; import org.apache.lucene.queries.FilterClause; import org.apache.lucene.search.BooleanClause; import org.apache.lucene.search.Filter; @@ -29,6 +27,7 @@ import org.elasticsearch.common.compress.CompressedString; import org.elasticsearch.common.inject.Inject; import org.elasticsearch.common.lucene.search.XBooleanFilter; import org.elasticsearch.common.settings.Settings; +import org.elasticsearch.common.util.concurrent.ConcurrentCollections; import org.elasticsearch.common.xcontent.XContentFactory; import org.elasticsearch.common.xcontent.XContentParser; import org.elasticsearch.index.AbstractIndexComponent; @@ -39,20 +38,16 @@ import org.elasticsearch.indices.AliasFilterParsingException; import org.elasticsearch.indices.InvalidAliasNameException; import java.io.IOException; +import java.util.Iterator; import java.util.Map; -import static org.elasticsearch.common.collect.MapBuilder.newMapBuilder; - /** * */ public class IndexAliasesService extends AbstractIndexComponent implements Iterable { private final IndexQueryParserService indexQueryParser; - - private volatile ImmutableMap aliases = ImmutableMap.of(); - - private final Object mutex = new Object(); + private final Map aliases = ConcurrentCollections.newConcurrentMapWithAggressiveConcurrency(); @Inject public IndexAliasesService(Index index, @IndexSettings Settings indexSettings, IndexQueryParserService indexQueryParser) { @@ -77,9 +72,7 @@ public class IndexAliasesService extends AbstractIndexComponent implements Itera } public void addAll(Map aliases) { - synchronized (mutex) { - this.aliases = newMapBuilder(this.aliases).putAll(aliases).immutableMap(); - } + this.aliases.putAll(aliases); } /** @@ -126,15 +119,11 @@ public class IndexAliasesService extends AbstractIndexComponent implements Itera } private void add(IndexAlias indexAlias) { - synchronized (mutex) { - aliases = newMapBuilder(aliases).put(indexAlias.alias(), indexAlias).immutableMap(); - } + aliases.put(indexAlias.alias(), indexAlias); } public void remove(String alias) { - synchronized (mutex) { - aliases = newMapBuilder(aliases).remove(alias).immutableMap(); - } + aliases.remove(alias); } private Filter parse(String alias, CompressedString filter) { @@ -155,7 +144,7 @@ public class IndexAliasesService extends AbstractIndexComponent implements Itera } @Override - public UnmodifiableIterator iterator() { + public Iterator iterator() { return aliases.values().iterator(); } } diff --git a/src/test/java/org/elasticsearch/benchmark/aliases/AliasesBenchmark.java b/src/test/java/org/elasticsearch/benchmark/aliases/AliasesBenchmark.java new file mode 100644 index 00000000000..dadcb8fbf8e --- /dev/null +++ b/src/test/java/org/elasticsearch/benchmark/aliases/AliasesBenchmark.java @@ -0,0 +1,133 @@ +/* + * Licensed to Elastic Search and Shay Banon under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. Elastic Search 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. + */ + +package org.elasticsearch.benchmark.aliases; + +import org.elasticsearch.action.admin.indices.alias.IndicesAliasesRequestBuilder; +import org.elasticsearch.action.admin.indices.alias.get.GetAliasesResponse; +import org.elasticsearch.client.Client; +import org.elasticsearch.common.settings.ImmutableSettings; +import org.elasticsearch.common.settings.Settings; +import org.elasticsearch.indices.AliasMissingException; +import org.elasticsearch.indices.IndexAlreadyExistsException; +import org.elasticsearch.node.Node; +import org.elasticsearch.node.NodeBuilder; + +import java.io.IOException; + +/** + */ +public class AliasesBenchmark { + + private final static String INDEX_NAME = "my-index"; + + public static void main(String[] args) throws IOException { + int NUM_ADDITIONAL_NODES = 0; + int BASE_ALIAS_COUNT = 100000; + int NUM_ADD_ALIAS_REQUEST = 1000; + + Settings settings = ImmutableSettings.settingsBuilder() + .put("gateway.type", "local") + .put("node.master", false).build(); + Node node1 = NodeBuilder.nodeBuilder().settings( + ImmutableSettings.settingsBuilder().put(settings).put("node.master", true) + ).node(); + + Node[] otherNodes = new Node[NUM_ADDITIONAL_NODES]; + for (int i = 0; i < otherNodes.length; i++) { + otherNodes[i] = NodeBuilder.nodeBuilder().settings(settings).node(); + } + + Client client = node1.client(); + try { + client.admin().indices().prepareCreate(INDEX_NAME).execute().actionGet(); + } catch (IndexAlreadyExistsException e) {} + client.admin().cluster().prepareHealth().setWaitForYellowStatus().execute().actionGet(); + int numberOfAliases = countAliases(client); + System.out.println("Number of aliases: " + numberOfAliases); + + if (numberOfAliases < BASE_ALIAS_COUNT) { + int diff = BASE_ALIAS_COUNT - numberOfAliases; + System.out.println("Adding " + diff + " more aliases to get to the start amount of " + BASE_ALIAS_COUNT + " aliases"); + IndicesAliasesRequestBuilder builder = client.admin().indices().prepareAliases(); + for (int i = 1; i <= diff; i++) { + builder.addAlias(INDEX_NAME, "alias" + numberOfAliases + i); + if (i % 1000 == 0) { + builder.execute().actionGet(); + builder = client.admin().indices().prepareAliases(); + } + } + if (!builder.request().getAliasActions().isEmpty()) { + builder.execute().actionGet(); + } + } else if (numberOfAliases > BASE_ALIAS_COUNT) { + IndicesAliasesRequestBuilder builder = client.admin().indices().prepareAliases(); + int diff = numberOfAliases - BASE_ALIAS_COUNT; + System.out.println("Removing " + diff + " aliases to get to the start amount of " + BASE_ALIAS_COUNT + "aliases"); + for (int i = 0; i <= diff; i++) { + builder.removeAlias(INDEX_NAME, "alias" + (BASE_ALIAS_COUNT + i)); + if (i % 1000 == 0) { + builder.execute().actionGet(); + builder = client.admin().indices().prepareAliases(); + } + } + if (!builder.request().getAliasActions().isEmpty()) { + builder.execute().actionGet(); + } + } + + numberOfAliases = countAliases(client); + System.out.println("Number of aliases: " + numberOfAliases); + + long totalTime = 0; + int max = numberOfAliases + NUM_ADD_ALIAS_REQUEST; + for (int i = numberOfAliases; i <= max; i++) { + if (i != numberOfAliases && i % 100 == 0) { + long avgTime = totalTime / 100; + System.out.println("Added [" + (i - numberOfAliases) + "] aliases. Avg create time: " + avgTime + " ms"); + totalTime = 0; + } + + long time = System.currentTimeMillis(); +// String filter = termFilter("field" + i, "value" + i).toXContent(XContentFactory.jsonBuilder(), null).string(); + client.admin().indices().prepareAliases().addAlias(INDEX_NAME, "alias" + i/*, filter*/) + .execute().actionGet(); + totalTime += System.currentTimeMillis() - time; + } + System.out.println("Number of aliases: " + countAliases(client)); + + client.close(); + node1.close(); + for (Node otherNode : otherNodes) { + otherNode.close(); + } + } + + private static int countAliases(Client client) { + try { + GetAliasesResponse response = client.admin().indices().prepareGetAliases("a*") + .addIndices(INDEX_NAME) + .execute().actionGet(); + return response.getAliases().get(INDEX_NAME).size(); + } catch (AliasMissingException e) { + return 0; + } + } + +}