All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.elasticsearch.cluster.metadata.MetaData Maven / Gradle / Ivy

/*
 * 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.cluster.metadata;

import org.elasticsearch.ElasticSearchIllegalArgumentException;
import org.elasticsearch.common.Nullable;
import org.elasticsearch.common.Strings;
import org.elasticsearch.common.collect.ImmutableMap;
import org.elasticsearch.common.collect.ImmutableSet;
import org.elasticsearch.common.collect.Lists;
import org.elasticsearch.common.collect.MapBuilder;
import org.elasticsearch.common.collect.Sets;
import org.elasticsearch.common.collect.UnmodifiableIterator;
import org.elasticsearch.common.io.stream.StreamInput;
import org.elasticsearch.common.io.stream.StreamOutput;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.trove.set.hash.THashSet;
import org.elasticsearch.common.util.concurrent.Immutable;
import org.elasticsearch.common.xcontent.ToXContent;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentFactory;
import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.Index;
import org.elasticsearch.indices.IndexMissingException;

import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Set;

import static org.elasticsearch.common.collect.Lists.*;
import static org.elasticsearch.common.collect.MapBuilder.*;
import static org.elasticsearch.common.collect.Maps.*;
import static org.elasticsearch.common.collect.Sets.*;
import static org.elasticsearch.common.settings.ImmutableSettings.*;

/**
 * @author kimchy (shay.banon)
 */
@Immutable
public class MetaData implements Iterable {

    public static final MetaData EMPTY_META_DATA = newMetaDataBuilder().build();

    private final long version;

    private final ImmutableMap indices;
    private final ImmutableMap templates;

    private final transient int totalNumberOfShards;

    private final String[] allIndices;
    private final String[] allOpenIndices;

    private final ImmutableMap> aliases;

    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;

    private MetaData(long version, ImmutableMap indices, ImmutableMap templates) {
        this.version = version;
        this.indices = ImmutableMap.copyOf(indices);
        this.templates = templates;
        int totalNumberOfShards = 0;
        for (IndexMetaData indexMetaData : indices.values()) {
            totalNumberOfShards += indexMetaData.totalNumberOfShards();
        }
        this.totalNumberOfShards = totalNumberOfShards;

        // build all indices map
        List allIndicesLst = Lists.newArrayList();
        for (IndexMetaData indexMetaData : indices.values()) {
            allIndicesLst.add(indexMetaData.index());
        }
        allIndices = allIndicesLst.toArray(new String[allIndicesLst.size()]);

        List allOpenIndices = Lists.newArrayList();
        for (IndexMetaData indexMetaData : indices.values()) {
            if (indexMetaData.state() == IndexMetaData.State.OPEN) {
                allOpenIndices.add(indexMetaData.index());
            }
        }
        this.allOpenIndices = allOpenIndices.toArray(new String[allOpenIndices.size()]);

        // build aliases map
        MapBuilder> tmpAliasesMap = newMapBuilder();
        for (IndexMetaData indexMetaData : indices.values()) {
            String index = indexMetaData.index();
            for (AliasMetaData aliasMd : indexMetaData.aliases().values()) {
                MapBuilder indexAliasMap = tmpAliasesMap.get(aliasMd.alias());
                if (indexAliasMap == null) {
                    indexAliasMap = newMapBuilder();
                    tmpAliasesMap.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());
                }
            }
        }
        MapBuilder>> aliasToIndexToSearchRoutingMap = newMapBuilder();
        for (Map.Entry>> alias : tmpAliasToIndexToSearchRoutingMap.map().entrySet()) {
            aliasToIndexToSearchRoutingMap.put(alias.getKey(), alias.getValue().immutableMap());
        }
        this.aliasToIndexToSearchRoutingMap = aliasToIndexToSearchRoutingMap.immutableMap();

        // build filtering required map
        MapBuilder> filteringRequiredMap = newMapBuilder();
        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);
                }
            }
            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());

            for (String alias : indexMetaData.aliases().keySet()) {
                lst = tmpAliasAndIndexToIndexBuilder.get(alias);
                if (lst == null) {
                    lst = newHashSet();
                    tmpAliasAndIndexToIndexBuilder.put(alias, lst);
                }
                lst.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()]));
        }
        this.aliasAndIndexToIndexMap = aliasAndIndexToIndexBuilder.immutableMap();
    }

    public long version() {
        return this.version;
    }

    public ImmutableMap> aliases() {
        return this.aliases;
    }

    public ImmutableMap> getAliases() {
        return aliases();
    }

    /**
     * Returns all the concrete indices.
     */
    public String[] concreteAllIndices() {
        return allIndices;
    }

    public String[] getConcreteAllIndices() {
        return concreteAllIndices();
    }

    public String[] concreteAllOpenIndices() {
        return allOpenIndices;
    }

    public String[] getConcreteAllOpenIndices() {
        return allOpenIndices;
    }

    /**
     * Translates the provided indices (possibly aliased) into actual indices.
     */
    public String[] concreteIndices(String[] indices) throws IndexMissingException {
        return concreteIndices(indices, false, false);
    }

    /**
     * Translates the provided indices (possibly aliased) into actual indices.
     */
    public String[] concreteIndicesIgnoreMissing(String[] indices) {
        return concreteIndices(indices, true, false);
    }

    /**
     * Returns indexing routing for the given index.
     */
    public String resolveIndexRouting(@Nullable String routing, String aliasOrIndex) {
        // Check if index is specified by an alias
        ImmutableMap indexAliases = aliases.get(aliasOrIndex);
        if (indexAliases == null || indexAliases.isEmpty()) {
            return routing;
        }
        if (indexAliases.size() > 1) {
            throw new ElasticSearchIllegalArgumentException("Alias [" + aliasOrIndex + "] has more than one index associated with it [" + indexAliases.keySet() + "], can't execute a single index op");
        }
        AliasMetaData aliasMd = indexAliases.values().iterator().next();
        if (aliasMd.indexRouting() != null) {
            if (routing != null) {
                if (!routing.equals(aliasMd.indexRouting())) {
                    throw new ElasticSearchIllegalArgumentException("Alias [" + aliasOrIndex + "] has index routing associated with it [" + aliasMd.indexRouting() + "], and was provided with routing value [" + routing + "], rejecting operation");
                }
            }
            routing = aliasMd.indexRouting();
        }
        if (routing != null) {
            if (routing.indexOf(',') != -1) {
                throw new ElasticSearchIllegalArgumentException("index/alias [" + aliasOrIndex + "] provided with routing value [" + routing + "] that resolved to several routing values, rejecting operation");
            }
        }
        return routing;
    }

    /**
     * Sets the same routing for all indices
     */
    private Map> resolveSearchRoutingAllIndices(String routing) {
        if (routing != null) {
            Set r = Strings.splitStringByCommaToSet(routing);
            Map> routings = newHashMap();
            String[] concreteIndices = concreteAllIndices();
            for (String index : concreteIndices) {
                routings.put(index, r);
            }
            return routings;
        }
        return null;
    }

    public Map> resolveSearchRouting(@Nullable String routing, String aliasOrIndex) {
        Map> routings = null;
        Set paramRouting = null;
        if (routing != null) {
            paramRouting = Strings.splitStringByCommaToSet(routing);
        }

        ImmutableMap> indexToRoutingMap = aliasToIndexToSearchRoutingMap.get(aliasOrIndex);
        if (indexToRoutingMap != null && !indexToRoutingMap.isEmpty()) {
            // It's an alias
            for (Map.Entry> indexRouting : indexToRoutingMap.entrySet()) {
                if (!indexRouting.getValue().isEmpty()) {
                    // Routing alias
                    Set r = new THashSet(indexRouting.getValue());
                    if (paramRouting != null) {
                        r.retainAll(paramRouting);
                    }
                    if (!r.isEmpty()) {
                        if (routings == null) {
                            routings = newHashMap();
                        }
                        routings.put(indexRouting.getKey(), r);
                    }
                } else {
                    // Non-routing alias
                    if (paramRouting != null) {
                        Set r = new THashSet(paramRouting);
                        if (routings == null) {
                            routings = newHashMap();
                        }
                        routings.put(indexRouting.getKey(), r);
                    }
                }
            }
        } else {
            // It's an index
            if (paramRouting != null) {
                routings = ImmutableMap.of(aliasOrIndex, paramRouting);
            }
        }
        return routings;
    }


    public Map> resolveSearchRouting(@Nullable String routing, String[] aliasesOrIndices) {
        if (aliasesOrIndices == null || aliasesOrIndices.length == 0) {
            return resolveSearchRoutingAllIndices(routing);
        }

        if (aliasesOrIndices.length == 1) {
            if (aliasesOrIndices[0].equals("_all")) {
                return resolveSearchRoutingAllIndices(routing);
            } else {
                return resolveSearchRouting(routing, aliasesOrIndices[0]);
            }
        }

        Map> routings = null;
        Set paramRouting = null;
        // List of indices that don't require any routing
        Set norouting = newHashSet();
        if (routing != null) {
            paramRouting = Strings.splitStringByCommaToSet(routing);
        }

        for (String aliasOrIndex : aliasesOrIndices) {
            ImmutableMap> indexToRoutingMap = aliasToIndexToSearchRoutingMap.get(aliasOrIndex);
            if (indexToRoutingMap != null && !indexToRoutingMap.isEmpty()) {
                for (Map.Entry> indexRouting : indexToRoutingMap.entrySet()) {
                    if (!norouting.contains(indexRouting.getKey())) {
                        if (!indexRouting.getValue().isEmpty()) {
                            // Routing alias
                            if (routings == null) {
                                routings = newHashMap();
                            }
                            Set r = routings.get(indexRouting.getKey());
                            if (r == null) {
                                r = new THashSet();
                                routings.put(indexRouting.getKey(), r);
                            }
                            r.addAll(indexRouting.getValue());
                            if (paramRouting != null) {
                                r.retainAll(paramRouting);
                            }
                            if (r.isEmpty()) {
                                routings.remove(indexRouting.getKey());
                            }
                        } else {
                            // Non-routing alias
                            if (!norouting.contains(indexRouting.getKey())) {
                                norouting.add(indexRouting.getKey());
                                if (paramRouting != null) {
                                    Set r = new THashSet(paramRouting);
                                    if (routings == null) {
                                        routings = newHashMap();
                                    }
                                    routings.put(indexRouting.getKey(), r);
                                } else {
                                    if (routings != null) {
                                        routings.remove(indexRouting.getKey());
                                    }
                                }
                            }
                        }
                    }
                }
            } else {
                // Index
                if (!norouting.contains(aliasOrIndex)) {
                    norouting.add(aliasOrIndex);
                    if (paramRouting != null) {
                        Set r = new THashSet(paramRouting);
                        if (routings == null) {
                            routings = newHashMap();
                        }
                        routings.put(aliasOrIndex, r);
                    } else {
                        if (routings != null) {
                            routings.remove(aliasOrIndex);
                        }
                    }
                }
            }

        }
        if (routings == null || routings.isEmpty()) {
            return null;
        }
        return routings;
    }

    /**
     * Translates the provided indices (possibly aliased) into actual indices.
     */
    public String[] concreteIndices(String[] indices, boolean ignoreMissing, boolean allOnlyOpen) throws IndexMissingException {
        if (indices == null || indices.length == 0) {
            return allOnlyOpen ? concreteAllOpenIndices() : concreteAllIndices();
        }
        // optimize for single element index (common case)
        if (indices.length == 1) {
            String index = indices[0];
            if (index.length() == 0) {
                return allOnlyOpen ? concreteAllOpenIndices() : concreteAllIndices();
            }
            if (index.equals("_all")) {
                return allOnlyOpen ? concreteAllOpenIndices() : concreteAllIndices();
            }
            // if a direct index name, just return the array provided
            if (this.indices.containsKey(index)) {
                return indices;
            }
            String[] actualLst = aliasAndIndexToIndexMap.get(index);
            if (actualLst == null) {
                if (!ignoreMissing) {
                    throw new IndexMissingException(new Index(index));
                } else {
                    return Strings.EMPTY_ARRAY;
                }
            } else {
                return actualLst;
            }
        }

        // check if its a possible aliased index, if not, just return the
        // passed array
        boolean possiblyAliased = false;
        for (String index : indices) {
            if (!this.indices.containsKey(index)) {
                possiblyAliased = true;
                break;
            }
        }
        if (!possiblyAliased) {
            return indices;
        }

        Set actualIndices = Sets.newHashSetWithExpectedSize(indices.length);
        for (String index : indices) {
            String[] actualLst = aliasAndIndexToIndexMap.get(index);
            if (actualLst == null) {
                if (!ignoreMissing) {
                    throw new IndexMissingException(new Index(index));
                }
            } else {
                for (String x : actualLst) {
                    actualIndices.add(x);
                }
            }
        }
        return actualIndices.toArray(new String[actualIndices.size()]);
    }

    public String concreteIndex(String index) throws IndexMissingException, ElasticSearchIllegalArgumentException {
        // a quick check, if this is an actual index, if so, return it
        if (indices.containsKey(index)) {
            return index;
        }
        // not an actual index, fetch from an alias
        String[] 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");
        }
        return lst[0];
    }

    public boolean hasIndex(String index) {
        return indices.containsKey(index);
    }

    public boolean hasConcreteIndex(String index) {
        return aliasAndIndexToIndexMap.containsKey(index);
    }

    public IndexMetaData index(String index) {
        return indices.get(index);
    }

    public ImmutableMap indices() {
        return this.indices;
    }

    public ImmutableMap getIndices() {
        return indices();
    }

    public ImmutableMap templates() {
        return this.templates;
    }

    public ImmutableMap getTemplates() {
        return this.templates;
    }

    public int totalNumberOfShards() {
        return this.totalNumberOfShards;
    }

    public int getTotalNumberOfShards() {
        return totalNumberOfShards();
    }


    /**
     * Iterates through the list of indices and selects the effective list of filtering aliases for the
     * given index.
     *
     * 

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 (indices == null || indices.length == 0) { return null; } // optimize for the most common single index/alias scenario if (indices.length == 1) { String alias = indices[0]; // This list contains "_all" - no filtering needed if (alias.equals("_all")) { return null; } ImmutableMap aliasToFilteringRequiredMap = indexToAliasFilteringRequiredMap.get(index); if (aliasToFilteringRequiredMap == null) { // Shouldn't happen throw new IndexMissingException(new Index(index)); } Boolean filteringRequired = aliasToFilteringRequiredMap.get(alias); if (filteringRequired == null || !filteringRequired) { return null; } return new String[]{alias}; } List filteringAliases = null; for (String alias : indices) { ImmutableMap aliasToFilteringRequiredMap = indexToAliasFilteringRequiredMap.get(index); if (aliasToFilteringRequiredMap == null) { // Shouldn't happen throw new IndexMissingException(new Index(index)); } Boolean filteringRequired = aliasToFilteringRequiredMap.get(alias); // Check that this is an alias for the current index // Otherwise - skip it if (filteringRequired != null) { if (filteringRequired) { // If filtering required - add it to the list of filters if (filteringAliases == null) { filteringAliases = newArrayList(); } filteringAliases.add(alias); } else { // If not, we have a non filtering alias for this index - no filtering needed return null; } } } if (filteringAliases == null) { return null; } return filteringAliases.toArray(new String[filteringAliases.size()]); } @Override public UnmodifiableIterator iterator() { return indices.values().iterator(); } public static Builder builder() { return new Builder(); } public static Builder newMetaDataBuilder() { return new Builder(); } public static class Builder { private long version; private MapBuilder indices = newMapBuilder(); private MapBuilder templates = newMapBuilder(); public Builder metaData(MetaData metaData) { this.version = metaData.version; this.indices.putAll(metaData.indices); this.templates.putAll(metaData.templates); return this; } public Builder put(IndexMetaData.Builder indexMetaDataBuilder) { return put(indexMetaDataBuilder.build()); } public Builder put(IndexMetaData indexMetaData) { indices.put(indexMetaData.index(), indexMetaData); return this; } public IndexMetaData get(String index) { return indices.get(index); } public Builder remove(String index) { indices.remove(index); return this; } public Builder put(IndexTemplateMetaData.Builder template) { return put(template.build()); } public Builder put(IndexTemplateMetaData template) { templates.put(template.name(), template); return this; } public Builder remoteTemplate(String templateName) { templates.remove(templateName); return this; } public Builder updateSettings(Settings settings, String... indices) { if (indices == null || indices.length == 0) { indices = this.indices.map().keySet().toArray(new String[this.indices.map().keySet().size()]); } for (String index : indices) { IndexMetaData indexMetaData = this.indices.get(index); if (indexMetaData == null) { throw new IndexMissingException(new Index(index)); } put(IndexMetaData.newIndexMetaDataBuilder(indexMetaData) .settings(settingsBuilder().put(indexMetaData.settings()).put(settings)) .build()); } return this; } public Builder updateNumberOfReplicas(int numberOfReplicas, String... indices) { if (indices == null || indices.length == 0) { indices = this.indices.map().keySet().toArray(new String[this.indices.map().keySet().size()]); } for (String index : indices) { IndexMetaData indexMetaData = this.indices.get(index); if (indexMetaData == null) { throw new IndexMissingException(new Index(index)); } put(IndexMetaData.newIndexMetaDataBuilder(indexMetaData).numberOfReplicas(numberOfReplicas).build()); } return this; } public Builder version(long version) { this.version = version; return this; } public MetaData build() { return new MetaData(version, indices.immutableMap(), templates.immutableMap()); } public static String toXContent(MetaData metaData) throws IOException { XContentBuilder builder = XContentFactory.contentBuilder(XContentType.JSON); builder.startObject(); toXContent(metaData, builder, ToXContent.EMPTY_PARAMS); builder.endObject(); return builder.string(); } public static void toXContent(MetaData metaData, XContentBuilder builder, ToXContent.Params params) throws IOException { builder.startObject("meta-data"); builder.startObject("templates"); for (IndexTemplateMetaData template : metaData.templates().values()) { IndexTemplateMetaData.Builder.toXContent(template, builder, params); } builder.endObject(); builder.startObject("indices"); for (IndexMetaData indexMetaData : metaData) { IndexMetaData.Builder.toXContent(indexMetaData, builder, params); } builder.endObject(); builder.endObject(); } public static MetaData fromXContent(XContentParser parser) throws IOException { Builder builder = new Builder(); XContentParser.Token token = parser.currentToken(); String currentFieldName = parser.currentName(); if (!"meta-data".equals(currentFieldName)) { token = parser.nextToken(); currentFieldName = parser.currentName(); if (token == null) { // no data... return builder.build(); } } while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) { if (token == XContentParser.Token.FIELD_NAME) { currentFieldName = parser.currentName(); } else if (token == XContentParser.Token.START_OBJECT) { if ("indices".equals(currentFieldName)) { while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) { builder.put(IndexMetaData.Builder.fromXContent(parser)); } } else if ("templates".equals(currentFieldName)) { while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) { builder.put(IndexTemplateMetaData.Builder.fromXContent(parser)); } } } } return builder.build(); } public static MetaData readFrom(StreamInput in) throws IOException { Builder builder = new Builder(); builder.version = in.readLong(); int size = in.readVInt(); for (int i = 0; i < size; i++) { builder.put(IndexMetaData.Builder.readFrom(in)); } size = in.readVInt(); for (int i = 0; i < size; i++) { builder.put(IndexTemplateMetaData.Builder.readFrom(in)); } return builder.build(); } public static void writeTo(MetaData metaData, StreamOutput out) throws IOException { out.writeLong(metaData.version); out.writeVInt(metaData.indices.size()); for (IndexMetaData indexMetaData : metaData) { IndexMetaData.Builder.writeTo(indexMetaData, out); } out.writeVInt(metaData.templates.size()); for (IndexTemplateMetaData template : metaData.templates.values()) { IndexTemplateMetaData.Builder.writeTo(template, out); } } } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy