org.opensearch.cluster.metadata.IndexMetadata Maven / Gradle / Ivy
Show all versions of opensearch Show documentation
/*
* SPDX-License-Identifier: Apache-2.0
*
* The OpenSearch Contributors require contributions made to
* this file be licensed under the Apache-2.0 license or a
* compatible open source license.
*/
/*
* Licensed to Elasticsearch under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch 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.
*/
/*
* Modifications Copyright OpenSearch Contributors. See
* GitHub history for details.
*/
package org.opensearch.cluster.metadata;
import org.opensearch.LegacyESVersion;
import org.opensearch.Version;
import org.opensearch.action.admin.indices.rollover.RolloverInfo;
import org.opensearch.action.support.ActiveShardCount;
import org.opensearch.cluster.Diff;
import org.opensearch.cluster.Diffable;
import org.opensearch.cluster.DiffableUtils;
import org.opensearch.cluster.block.ClusterBlock;
import org.opensearch.cluster.block.ClusterBlockLevel;
import org.opensearch.cluster.node.DiscoveryNodeFilters;
import org.opensearch.cluster.routing.allocation.IndexMetadataUpdater;
import org.opensearch.common.Nullable;
import org.opensearch.common.annotation.PublicApi;
import org.opensearch.common.collect.MapBuilder;
import org.opensearch.common.compress.CompressedXContent;
import org.opensearch.common.settings.Setting;
import org.opensearch.common.settings.Setting.Property;
import org.opensearch.common.settings.Settings;
import org.opensearch.common.xcontent.XContentHelper;
import org.opensearch.core.Assertions;
import org.opensearch.core.common.Strings;
import org.opensearch.core.common.io.stream.StreamInput;
import org.opensearch.core.common.io.stream.StreamOutput;
import org.opensearch.core.common.io.stream.Writeable;
import org.opensearch.core.index.Index;
import org.opensearch.core.index.shard.ShardId;
import org.opensearch.core.rest.RestStatus;
import org.opensearch.core.xcontent.MediaTypeRegistry;
import org.opensearch.core.xcontent.ToXContent;
import org.opensearch.core.xcontent.ToXContentFragment;
import org.opensearch.core.xcontent.XContentBuilder;
import org.opensearch.core.xcontent.XContentParser;
import org.opensearch.gateway.MetadataStateFormat;
import org.opensearch.index.IndexModule;
import org.opensearch.index.mapper.MapperService;
import org.opensearch.index.seqno.SequenceNumbers;
import org.opensearch.indices.replication.common.ReplicationType;
import java.io.IOException;
import java.time.Instant;
import java.time.ZoneOffset;
import java.time.ZonedDateTime;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.function.Function;
import static org.opensearch.cluster.metadata.Metadata.CONTEXT_MODE_PARAM;
import static org.opensearch.cluster.node.DiscoveryNodeFilters.IP_VALIDATOR;
import static org.opensearch.cluster.node.DiscoveryNodeFilters.OpType.AND;
import static org.opensearch.cluster.node.DiscoveryNodeFilters.OpType.OR;
import static org.opensearch.common.settings.Settings.readSettingsFromStream;
import static org.opensearch.common.settings.Settings.writeSettingsToStream;
/**
* Index metadata information
*
* @opensearch.api
*/
@PublicApi(since = "1.0.0")
public class IndexMetadata implements Diffable, ToXContentFragment {
public static final ClusterBlock INDEX_READ_ONLY_BLOCK = new ClusterBlock(
5,
"index read-only (api)",
false,
false,
false,
RestStatus.FORBIDDEN,
EnumSet.of(ClusterBlockLevel.WRITE, ClusterBlockLevel.METADATA_WRITE)
);
public static final ClusterBlock INDEX_READ_BLOCK = new ClusterBlock(
7,
"index read (api)",
false,
false,
false,
RestStatus.FORBIDDEN,
EnumSet.of(ClusterBlockLevel.READ)
);
public static final ClusterBlock INDEX_WRITE_BLOCK = new ClusterBlock(
8,
"index write (api)",
false,
false,
false,
RestStatus.FORBIDDEN,
EnumSet.of(ClusterBlockLevel.WRITE)
);
public static final ClusterBlock INDEX_METADATA_BLOCK = new ClusterBlock(
9,
"index metadata (api)",
false,
false,
false,
RestStatus.FORBIDDEN,
EnumSet.of(ClusterBlockLevel.METADATA_WRITE, ClusterBlockLevel.METADATA_READ)
);
public static final ClusterBlock INDEX_READ_ONLY_ALLOW_DELETE_BLOCK = new ClusterBlock(
12,
"disk usage exceeded flood-stage watermark, index has read-only-allow-delete block",
false,
false,
true,
RestStatus.TOO_MANY_REQUESTS,
EnumSet.of(ClusterBlockLevel.METADATA_WRITE, ClusterBlockLevel.WRITE)
);
public static final ClusterBlock REMOTE_READ_ONLY_ALLOW_DELETE = new ClusterBlock(
13,
"remote index is read-only",
false,
false,
true,
RestStatus.FORBIDDEN,
EnumSet.of(ClusterBlockLevel.METADATA_WRITE, ClusterBlockLevel.WRITE)
);
/**
* The state of the index.
*
* @opensearch.api
*/
@PublicApi(since = "1.0.0")
public enum State {
OPEN((byte) 0),
CLOSE((byte) 1);
private final byte id;
State(byte id) {
this.id = id;
}
public byte id() {
return this.id;
}
public static State fromId(byte id) {
if (id == 0) {
return OPEN;
} else if (id == 1) {
return CLOSE;
}
throw new IllegalStateException("No state match for id [" + id + "]");
}
public static State fromString(String state) {
if ("open".equals(state)) {
return OPEN;
} else if ("close".equals(state)) {
return CLOSE;
}
throw new IllegalStateException("No state match for [" + state + "]");
}
}
static Setting buildNumberOfShardsSetting() {
/* This is a safety limit that should only be exceeded in very rare and special cases. The assumption is that
* 99% of the users have less than 1024 shards per index. We also make it a hard check that requires restart of nodes
* if a cluster should allow to create more than 1024 shards per index. NOTE: this does not limit the number of shards
* per cluster. this also prevents creating stuff like a new index with millions of shards by accident which essentially
* kills the entire cluster with OOM on the spot.*/
final int maxNumShards = Integer.parseInt(System.getProperty(MAX_NUMBER_OF_SHARDS, "1024"));
if (maxNumShards < 1) {
throw new IllegalArgumentException(MAX_NUMBER_OF_SHARDS + " must be > 0");
}
/* This property should be provided if the default number of shards for any new index has to be changed to a value
* other than 1. This value is applicable only if the index.number_of_shards setting is not provided as part of the
* index creation request. */
final int defaultNumShards = Integer.parseInt(System.getProperty(DEFAULT_NUMBER_OF_SHARDS, "1"));
if (defaultNumShards < 1 || defaultNumShards > maxNumShards) {
throw new IllegalArgumentException(
DEFAULT_NUMBER_OF_SHARDS
+ " value ["
+ defaultNumShards
+ "] must between "
+ "1 and "
+ MAX_NUMBER_OF_SHARDS
+ " ["
+ maxNumShards
+ "]"
);
}
return Setting.intSetting(SETTING_NUMBER_OF_SHARDS, defaultNumShards, 1, maxNumShards, Property.IndexScope, Property.Final);
}
public static final String INDEX_SETTING_PREFIX = "index.";
public static final String SETTING_NUMBER_OF_SHARDS = "index.number_of_shards";
static final String DEFAULT_NUMBER_OF_SHARDS = "opensearch.index.default_number_of_shards";
static final String MAX_NUMBER_OF_SHARDS = "opensearch.index.max_number_of_shards";
public static final Setting INDEX_NUMBER_OF_SHARDS_SETTING = buildNumberOfShardsSetting();
public static final String SETTING_NUMBER_OF_REPLICAS = "index.number_of_replicas";
public static final Setting INDEX_NUMBER_OF_REPLICAS_SETTING = Setting.intSetting(
SETTING_NUMBER_OF_REPLICAS,
1,
0,
Property.Dynamic,
Property.IndexScope
);
public static final String SETTING_ROUTING_PARTITION_SIZE = "index.routing_partition_size";
public static final Setting INDEX_ROUTING_PARTITION_SIZE_SETTING = Setting.intSetting(
SETTING_ROUTING_PARTITION_SIZE,
1,
1,
Property.IndexScope
);
public static final Setting INDEX_NUMBER_OF_ROUTING_SHARDS_SETTING = Setting.intSetting(
"index.number_of_routing_shards",
INDEX_NUMBER_OF_SHARDS_SETTING,
1,
new Setting.Validator() {
@Override
public void validate(final Integer value) {
}
@Override
public void validate(final Integer numRoutingShards, final Map, Object> settings) {
int numShards = (int) settings.get(INDEX_NUMBER_OF_SHARDS_SETTING);
if (numRoutingShards < numShards) {
throw new IllegalArgumentException(
"index.number_of_routing_shards [" + numRoutingShards + "] must be >= index.number_of_shards [" + numShards + "]"
);
}
getRoutingFactor(numShards, numRoutingShards);
}
@Override
public Iterator> settings() {
final List> settings = Collections.singletonList(INDEX_NUMBER_OF_SHARDS_SETTING);
return settings.iterator();
}
},
Property.IndexScope
);
/**
* Used to specify the replication type for the index. By default, document replication is used.
*/
public static final String SETTING_REPLICATION_TYPE = "index.replication.type";
public static final Setting INDEX_REPLICATION_TYPE_SETTING = new Setting<>(
SETTING_REPLICATION_TYPE,
ReplicationType.DOCUMENT.toString(),
ReplicationType::parseString,
new Setting.Validator<>() {
@Override
public void validate(final ReplicationType value) {}
@Override
public void validate(final ReplicationType value, final Map, Object> settings) {
final Object remoteStoreEnabled = settings.get(INDEX_REMOTE_STORE_ENABLED_SETTING);
if (ReplicationType.SEGMENT.equals(value) == false && Objects.equals(remoteStoreEnabled, true)) {
throw new IllegalArgumentException(
"To enable "
+ INDEX_REMOTE_STORE_ENABLED_SETTING.getKey()
+ ", "
+ INDEX_REPLICATION_TYPE_SETTING.getKey()
+ " should be set to "
+ ReplicationType.SEGMENT
);
}
}
@Override
public Iterator> settings() {
final List> settings = List.of(INDEX_REMOTE_STORE_ENABLED_SETTING);
return settings.iterator();
}
},
Property.IndexScope,
Property.Final
);
public static final String SETTING_REMOTE_STORE_ENABLED = "index.remote_store.enabled";
public static final String SETTING_REMOTE_SEGMENT_STORE_REPOSITORY = "index.remote_store.segment.repository";
public static final String SETTING_REMOTE_TRANSLOG_STORE_REPOSITORY = "index.remote_store.translog.repository";
/**
* Used to specify if the index data should be persisted in the remote store.
*/
public static final Setting INDEX_REMOTE_STORE_ENABLED_SETTING = Setting.boolSetting(
SETTING_REMOTE_STORE_ENABLED,
false,
new Setting.Validator<>() {
@Override
public void validate(final Boolean value) {}
@Override
public void validate(final Boolean value, final Map, Object> settings) {
final Object replicationType = settings.get(INDEX_REPLICATION_TYPE_SETTING);
if (ReplicationType.SEGMENT.equals(replicationType) == false && value) {
throw new IllegalArgumentException(
"To enable "
+ INDEX_REMOTE_STORE_ENABLED_SETTING.getKey()
+ ", "
+ INDEX_REPLICATION_TYPE_SETTING.getKey()
+ " should be set to "
+ ReplicationType.SEGMENT
);
}
}
@Override
public Iterator> settings() {
final List> settings = List.of(INDEX_REPLICATION_TYPE_SETTING);
return settings.iterator();
}
},
Property.IndexScope,
Property.PrivateIndex,
Property.Dynamic
);
/**
* Used to specify remote store repository to use for this index.
*/
public static final Setting INDEX_REMOTE_SEGMENT_STORE_REPOSITORY_SETTING = Setting.simpleString(
SETTING_REMOTE_SEGMENT_STORE_REPOSITORY,
new Setting.Validator<>() {
@Override
public void validate(final String value) {}
@Override
public void validate(final String value, final Map, Object> settings) {
if (value == null || value.isEmpty()) {
throw new IllegalArgumentException(
"Setting "
+ INDEX_REMOTE_SEGMENT_STORE_REPOSITORY_SETTING.getKey()
+ " should be provided with non-empty repository ID"
);
} else {
validateRemoteStoreSettingEnabled(settings, INDEX_REMOTE_SEGMENT_STORE_REPOSITORY_SETTING);
}
}
@Override
public Iterator> settings() {
final List> settings = Collections.singletonList(INDEX_REMOTE_STORE_ENABLED_SETTING);
return settings.iterator();
}
},
Property.IndexScope,
Property.PrivateIndex,
Property.Dynamic
);
private static void validateRemoteStoreSettingEnabled(final Map, Object> settings, Setting> setting) {
final Boolean isRemoteSegmentStoreEnabled = (Boolean) settings.get(INDEX_REMOTE_STORE_ENABLED_SETTING);
if (isRemoteSegmentStoreEnabled == false) {
throw new IllegalArgumentException(
"Settings "
+ setting.getKey()
+ " can only be set/enabled when "
+ INDEX_REMOTE_STORE_ENABLED_SETTING.getKey()
+ " is set to true"
);
}
}
public static final Setting INDEX_REMOTE_TRANSLOG_REPOSITORY_SETTING = Setting.simpleString(
SETTING_REMOTE_TRANSLOG_STORE_REPOSITORY,
new Setting.Validator<>() {
@Override
public void validate(final String value) {}
@Override
public void validate(final String value, final Map, Object> settings) {
if (value == null || value.isEmpty()) {
throw new IllegalArgumentException(
"Setting " + INDEX_REMOTE_TRANSLOG_REPOSITORY_SETTING.getKey() + " should be provided with non-empty repository ID"
);
} else {
final Boolean isRemoteTranslogStoreEnabled = (Boolean) settings.get(INDEX_REMOTE_STORE_ENABLED_SETTING);
if (isRemoteTranslogStoreEnabled == null || isRemoteTranslogStoreEnabled == false) {
throw new IllegalArgumentException(
"Settings "
+ INDEX_REMOTE_TRANSLOG_REPOSITORY_SETTING.getKey()
+ " can only be set/enabled when "
+ INDEX_REMOTE_STORE_ENABLED_SETTING.getKey()
+ " is set to true"
);
}
}
}
@Override
public Iterator> settings() {
final List> settings = Collections.singletonList(INDEX_REMOTE_STORE_ENABLED_SETTING);
return settings.iterator();
}
},
Property.IndexScope,
Property.PrivateIndex,
Property.Dynamic
);
public static final String SETTING_AUTO_EXPAND_REPLICAS = "index.auto_expand_replicas";
public static final Setting INDEX_AUTO_EXPAND_REPLICAS_SETTING = AutoExpandReplicas.SETTING;
/**
* Blocks the API.
*
* @opensearch.api
*/
@PublicApi(since = "1.0.0")
public enum APIBlock implements Writeable {
READ_ONLY("read_only", INDEX_READ_ONLY_BLOCK),
READ("read", INDEX_READ_BLOCK),
WRITE("write", INDEX_WRITE_BLOCK),
METADATA("metadata", INDEX_METADATA_BLOCK),
READ_ONLY_ALLOW_DELETE("read_only_allow_delete", INDEX_READ_ONLY_ALLOW_DELETE_BLOCK);
final String name;
final String settingName;
final Setting setting;
final ClusterBlock block;
APIBlock(String name, ClusterBlock block) {
this.name = name;
this.settingName = "index.blocks." + name;
this.setting = Setting.boolSetting(settingName, false, Property.Dynamic, Property.IndexScope);
this.block = block;
}
public String settingName() {
return settingName;
}
public Setting setting() {
return setting;
}
public ClusterBlock getBlock() {
return block;
}
public static APIBlock fromName(String name) {
for (APIBlock block : APIBlock.values()) {
if (block.name.equals(name)) {
return block;
}
}
throw new IllegalArgumentException("No block found with name " + name);
}
public static APIBlock fromSetting(String settingName) {
for (APIBlock block : APIBlock.values()) {
if (block.settingName.equals(settingName)) {
return block;
}
}
throw new IllegalArgumentException("No block found with setting name " + settingName);
}
@Override
public void writeTo(StreamOutput out) throws IOException {
out.writeVInt(ordinal());
}
public static APIBlock readFrom(StreamInput input) throws IOException {
return APIBlock.values()[input.readVInt()];
}
}
public static final String SETTING_READ_ONLY = APIBlock.READ_ONLY.settingName();
public static final Setting INDEX_READ_ONLY_SETTING = APIBlock.READ_ONLY.setting();
public static final String SETTING_BLOCKS_READ = APIBlock.READ.settingName();
public static final Setting INDEX_BLOCKS_READ_SETTING = APIBlock.READ.setting();
public static final String SETTING_BLOCKS_WRITE = APIBlock.WRITE.settingName();
public static final Setting INDEX_BLOCKS_WRITE_SETTING = APIBlock.WRITE.setting();
public static final String SETTING_BLOCKS_METADATA = APIBlock.METADATA.settingName();
public static final Setting INDEX_BLOCKS_METADATA_SETTING = APIBlock.METADATA.setting();
public static final String SETTING_READ_ONLY_ALLOW_DELETE = APIBlock.READ_ONLY_ALLOW_DELETE.settingName();
public static final Setting INDEX_BLOCKS_READ_ONLY_ALLOW_DELETE_SETTING = APIBlock.READ_ONLY_ALLOW_DELETE.setting();
public static final String SETTING_VERSION_CREATED = "index.version.created";
public static final Setting SETTING_INDEX_VERSION_CREATED = Setting.versionSetting(
SETTING_VERSION_CREATED,
Version.V_EMPTY,
Property.IndexScope,
Property.PrivateIndex
);
public static final String SETTING_VERSION_CREATED_STRING = "index.version.created_string";
public static final String SETTING_VERSION_UPGRADED = "index.version.upgraded";
public static final String SETTING_VERSION_UPGRADED_STRING = "index.version.upgraded_string";
public static final String SETTING_CREATION_DATE = "index.creation_date";
/**
* The user provided name for an index. This is the plain string provided by the user when the index was created.
* It might still contain date math expressions etc. (added in 5.0)
*/
public static final String SETTING_INDEX_PROVIDED_NAME = "index.provided_name";
public static final String SETTING_PRIORITY = "index.priority";
public static final Setting INDEX_PRIORITY_SETTING = Setting.intSetting(
"index.priority",
1,
0,
Property.Dynamic,
Property.IndexScope
);
public static final String SETTING_CREATION_DATE_STRING = "index.creation_date_string";
public static final String SETTING_INDEX_UUID = "index.uuid";
public static final String SETTING_HISTORY_UUID = "index.history.uuid";
public static final String SETTING_DATA_PATH = "index.data_path";
public static final Setting INDEX_DATA_PATH_SETTING = new Setting<>(
SETTING_DATA_PATH,
"",
Function.identity(),
Property.IndexScope
);
public static final String INDEX_UUID_NA_VALUE = Strings.UNKNOWN_UUID_VALUE;
public static final String INDEX_ROUTING_REQUIRE_GROUP_PREFIX = "index.routing.allocation.require";
public static final String INDEX_ROUTING_INCLUDE_GROUP_PREFIX = "index.routing.allocation.include";
public static final String INDEX_ROUTING_EXCLUDE_GROUP_PREFIX = "index.routing.allocation.exclude";
public static final Setting.AffixSetting INDEX_ROUTING_REQUIRE_GROUP_SETTING = Setting.prefixKeySetting(
INDEX_ROUTING_REQUIRE_GROUP_PREFIX + ".",
key -> Setting.simpleString(key, value -> IP_VALIDATOR.accept(key, value), Property.Dynamic, Property.IndexScope)
);
public static final Setting.AffixSetting INDEX_ROUTING_INCLUDE_GROUP_SETTING = Setting.prefixKeySetting(
INDEX_ROUTING_INCLUDE_GROUP_PREFIX + ".",
key -> Setting.simpleString(key, value -> IP_VALIDATOR.accept(key, value), Property.Dynamic, Property.IndexScope)
);
public static final Setting.AffixSetting INDEX_ROUTING_EXCLUDE_GROUP_SETTING = Setting.prefixKeySetting(
INDEX_ROUTING_EXCLUDE_GROUP_PREFIX + ".",
key -> Setting.simpleString(key, value -> IP_VALIDATOR.accept(key, value), Property.Dynamic, Property.IndexScope)
);
public static final Setting.AffixSetting INDEX_ROUTING_INITIAL_RECOVERY_GROUP_SETTING = Setting.prefixKeySetting(
"index.routing.allocation.initial_recovery.",
key -> Setting.simpleString(key)
);
/**
* The number of active shard copies to check for before proceeding with a write operation.
*/
public static final Setting SETTING_WAIT_FOR_ACTIVE_SHARDS = new Setting<>(
"index.write.wait_for_active_shards",
"1",
ActiveShardCount::parseString,
Setting.Property.Dynamic,
Setting.Property.IndexScope
);
public static final String SETTING_INDEX_HIDDEN = "index.hidden";
/**
* Whether the index is considered hidden or not. A hidden index will not be resolved in
* normal wildcard searches unless explicitly allowed
*/
public static final Setting INDEX_HIDDEN_SETTING = Setting.boolSetting(
SETTING_INDEX_HIDDEN,
false,
Property.Dynamic,
Property.IndexScope
);
/**
* an internal index format description, allowing us to find out if this index is upgraded or needs upgrading
*/
private static final String INDEX_FORMAT = "index.format";
public static final Setting INDEX_FORMAT_SETTING = Setting.intSetting(
INDEX_FORMAT,
0,
Setting.Property.IndexScope,
Setting.Property.Final
);
public static final String KEY_IN_SYNC_ALLOCATIONS = "in_sync_allocations";
static final String KEY_VERSION = "version";
static final String KEY_MAPPING_VERSION = "mapping_version";
static final String KEY_SETTINGS_VERSION = "settings_version";
static final String KEY_ALIASES_VERSION = "aliases_version";
static final String KEY_ROUTING_NUM_SHARDS = "routing_num_shards";
static final String KEY_SETTINGS = "settings";
static final String KEY_STATE = "state";
static final String KEY_MAPPINGS = "mappings";
static final String KEY_ALIASES = "aliases";
static final String KEY_ROLLOVER_INFOS = "rollover_info";
static final String KEY_SYSTEM = "system";
public static final String KEY_PRIMARY_TERMS = "primary_terms";
public static final String REMOTE_STORE_CUSTOM_KEY = "remote_store";
public static final String TRANSLOG_METADATA_KEY = "translog_metadata";
public static final String INDEX_STATE_FILE_PREFIX = "state-";
static final Version SYSTEM_INDEX_FLAG_ADDED = LegacyESVersion.V_7_10_0;
private final int routingNumShards;
private final int routingFactor;
private final int routingPartitionSize;
private final int numberOfShards;
private final int numberOfReplicas;
private final Index index;
private final long version;
private final long mappingVersion;
private final long settingsVersion;
private final long aliasesVersion;
private final long[] primaryTerms;
private final State state;
private final Map aliases;
private final Settings settings;
private final Map mappings;
private final Map customData;
private final Map> inSyncAllocationIds;
private final transient int totalNumberOfShards;
private final DiscoveryNodeFilters requireFilters;
private final DiscoveryNodeFilters includeFilters;
private final DiscoveryNodeFilters excludeFilters;
private final DiscoveryNodeFilters initialRecoveryFilters;
private final Version indexCreatedVersion;
private final Version indexUpgradedVersion;
private final ActiveShardCount waitForActiveShards;
private final Map rolloverInfos;
private final boolean isSystem;
private final boolean isRemoteSnapshot;
private IndexMetadata(
final Index index,
final long version,
final long mappingVersion,
final long settingsVersion,
final long aliasesVersion,
final long[] primaryTerms,
final State state,
final int numberOfShards,
final int numberOfReplicas,
final Settings settings,
final Map mappings,
final Map aliases,
final Map customData,
final Map> inSyncAllocationIds,
final DiscoveryNodeFilters requireFilters,
final DiscoveryNodeFilters initialRecoveryFilters,
final DiscoveryNodeFilters includeFilters,
final DiscoveryNodeFilters excludeFilters,
final Version indexCreatedVersion,
final Version indexUpgradedVersion,
final int routingNumShards,
final int routingPartitionSize,
final ActiveShardCount waitForActiveShards,
final Map rolloverInfos,
final boolean isSystem
) {
this.index = index;
this.version = version;
assert mappingVersion >= 0 : mappingVersion;
this.mappingVersion = mappingVersion;
assert settingsVersion >= 0 : settingsVersion;
this.settingsVersion = settingsVersion;
assert aliasesVersion >= 0 : aliasesVersion;
this.aliasesVersion = aliasesVersion;
this.primaryTerms = primaryTerms;
assert primaryTerms.length == numberOfShards;
this.state = state;
this.numberOfShards = numberOfShards;
this.numberOfReplicas = numberOfReplicas;
this.totalNumberOfShards = numberOfShards * (numberOfReplicas + 1);
this.settings = settings;
this.mappings = Collections.unmodifiableMap(mappings);
this.customData = Collections.unmodifiableMap(customData);
this.aliases = Collections.unmodifiableMap(aliases);
this.inSyncAllocationIds = Collections.unmodifiableMap(inSyncAllocationIds);
this.requireFilters = requireFilters;
this.includeFilters = includeFilters;
this.excludeFilters = excludeFilters;
this.initialRecoveryFilters = initialRecoveryFilters;
this.indexCreatedVersion = indexCreatedVersion;
this.indexUpgradedVersion = indexUpgradedVersion;
this.routingNumShards = routingNumShards;
this.routingFactor = routingNumShards / numberOfShards;
this.routingPartitionSize = routingPartitionSize;
this.waitForActiveShards = waitForActiveShards;
this.rolloverInfos = Collections.unmodifiableMap(rolloverInfos);
this.isSystem = isSystem;
this.isRemoteSnapshot = IndexModule.Type.REMOTE_SNAPSHOT.match(this.settings);
assert numberOfShards * routingFactor == routingNumShards : routingNumShards + " must be a multiple of " + numberOfShards;
}
public Index getIndex() {
return index;
}
public String getIndexUUID() {
return index.getUUID();
}
/**
* Test whether the current index UUID is the same as the given one. Returns true if either are _na_
*/
public boolean isSameUUID(String otherUUID) {
assert otherUUID != null;
assert getIndexUUID() != null;
if (INDEX_UUID_NA_VALUE.equals(otherUUID) || INDEX_UUID_NA_VALUE.equals(getIndexUUID())) {
return true;
}
return otherUUID.equals(getIndexUUID());
}
public long getVersion() {
return this.version;
}
public long getMappingVersion() {
return mappingVersion;
}
public long getSettingsVersion() {
return settingsVersion;
}
public long getAliasesVersion() {
return aliasesVersion;
}
/**
* The term of the current selected primary. This is a non-negative number incremented when
* a primary shard is assigned after a full cluster restart or a replica shard is promoted to a primary.
*
* Note: since we increment the term every time a shard is assigned, the term for any operational shard (i.e., a shard
* that can be indexed into) is larger than 0. See {@link IndexMetadataUpdater#applyChanges}.
**/
public long primaryTerm(int shardId) {
return this.primaryTerms[shardId];
}
/**
* Return the {@link Version} on which this index has been created. This
* information is typically useful for backward compatibility.
*/
public Version getCreationVersion() {
return indexCreatedVersion;
}
/**
* Return the {@link Version} on which this index has been upgraded. This
* information is typically useful for backward compatibility.
*/
public Version getUpgradedVersion() {
return indexUpgradedVersion;
}
public long getCreationDate() {
return settings.getAsLong(SETTING_CREATION_DATE, -1L);
}
public State getState() {
return this.state;
}
public int getNumberOfShards() {
return numberOfShards;
}
public int getNumberOfReplicas() {
return numberOfReplicas;
}
public int getRoutingPartitionSize() {
return routingPartitionSize;
}
public boolean isRoutingPartitionedIndex() {
return routingPartitionSize != 1;
}
public int getTotalNumberOfShards() {
return totalNumberOfShards;
}
/**
* Returns the configured {@link #SETTING_WAIT_FOR_ACTIVE_SHARDS}, which defaults
* to an active shard count of 1 if not specified.
*/
public ActiveShardCount getWaitForActiveShards() {
return waitForActiveShards;
}
public Settings getSettings() {
return settings;
}
public Map getAliases() {
return this.aliases;
}
/**
* Return the concrete mapping for this index or {@code null} if this index has no mappings at all.
*/
@Nullable
public MappingMetadata mapping() {
for (final MappingMetadata cursor : mappings.values()) {
return cursor;
}
return null;
}
public static final String INDEX_RESIZE_SOURCE_UUID_KEY = "index.resize.source.uuid";
public static final String INDEX_RESIZE_SOURCE_NAME_KEY = "index.resize.source.name";
public static final Setting INDEX_RESIZE_SOURCE_UUID = Setting.simpleString(INDEX_RESIZE_SOURCE_UUID_KEY);
public static final Setting INDEX_RESIZE_SOURCE_NAME = Setting.simpleString(INDEX_RESIZE_SOURCE_NAME_KEY);
public Index getResizeSourceIndex() {
return INDEX_RESIZE_SOURCE_UUID.exists(settings)
? new Index(INDEX_RESIZE_SOURCE_NAME.get(settings), INDEX_RESIZE_SOURCE_UUID.get(settings))
: null;
}
Map getCustomData() {
return this.customData;
}
public Map getCustomData(final String key) {
return this.customData.get(key);
}
public Map> getInSyncAllocationIds() {
return inSyncAllocationIds;
}
public Map getRolloverInfos() {
return rolloverInfos;
}
public Set inSyncAllocationIds(int shardId) {
assert shardId >= 0 && shardId < numberOfShards;
return inSyncAllocationIds.get(shardId);
}
@Nullable
public DiscoveryNodeFilters requireFilters() {
return requireFilters;
}
@Nullable
public DiscoveryNodeFilters getInitialRecoveryFilters() {
return initialRecoveryFilters;
}
@Nullable
public DiscoveryNodeFilters includeFilters() {
return includeFilters;
}
@Nullable
public DiscoveryNodeFilters excludeFilters() {
return excludeFilters;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
IndexMetadata that = (IndexMetadata) o;
if (version != that.version) {
return false;
}
if (!aliases.equals(that.aliases)) {
return false;
}
if (!index.equals(that.index)) {
return false;
}
if (!mappings.equals(that.mappings)) {
return false;
}
if (!settings.equals(that.settings)) {
return false;
}
if (state != that.state) {
return false;
}
if (!customData.equals(that.customData)) {
return false;
}
if (routingNumShards != that.routingNumShards) {
return false;
}
if (routingFactor != that.routingFactor) {
return false;
}
if (Arrays.equals(primaryTerms, that.primaryTerms) == false) {
return false;
}
if (!inSyncAllocationIds.equals(that.inSyncAllocationIds)) {
return false;
}
if (rolloverInfos.equals(that.rolloverInfos) == false) {
return false;
}
if (isSystem != that.isSystem) {
return false;
}
return true;
}
@Override
public int hashCode() {
int result = index.hashCode();
result = 31 * result + Long.hashCode(version);
result = 31 * result + state.hashCode();
result = 31 * result + aliases.hashCode();
result = 31 * result + settings.hashCode();
result = 31 * result + mappings.hashCode();
result = 31 * result + customData.hashCode();
result = 31 * result + Long.hashCode(routingFactor);
result = 31 * result + Long.hashCode(routingNumShards);
result = 31 * result + Arrays.hashCode(primaryTerms);
result = 31 * result + inSyncAllocationIds.hashCode();
result = 31 * result + rolloverInfos.hashCode();
result = 31 * result + Boolean.hashCode(isSystem);
return result;
}
@Override
public Diff diff(IndexMetadata previousState) {
return new IndexMetadataDiff(previousState, this);
}
public static Diff readDiffFrom(StreamInput in) throws IOException {
return new IndexMetadataDiff(in);
}
public static IndexMetadata fromXContent(XContentParser parser) throws IOException {
return Builder.fromXContent(parser);
}
@Override
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
Builder.toXContent(this, builder, params);
return builder;
}
/**
* A diff of index metadata.
*
* @opensearch.internal
*/
private static class IndexMetadataDiff implements Diff {
private final String index;
private final int routingNumShards;
private final long version;
private final long mappingVersion;
private final long settingsVersion;
private final long aliasesVersion;
private final long[] primaryTerms;
private final State state;
private final Settings settings;
private final Diff