From 8449abfad39a90061a5c717c921e855045390296 Mon Sep 17 00:00:00 2001 From: Henning Andersen <33268011+henningandersen@users.noreply.github.com> Date: Thu, 11 Mar 2021 16:37:20 +0100 Subject: [PATCH] Avoid regular indices in frozen tier (#70141) (#70313) The frozen tier will be dedicated for partially cached searchable snapshots. This PR ensures that we do not allow allocating regular indices (including fully cached searchable snapshots) to the frozen tier. --- build.gradle | 3 +- .../routing/allocation/DataTierIT.java | 30 +++++++ .../allocation/DataTierAllocationDecider.java | 42 +++++++++- .../SearchableSnapshotsConstants.java | 22 +++++ .../DataTierAllocationDeciderTests.java | 54 ++++++++++++ .../SearchableSnapshotsConstantsTests.java | 35 ++++++++ .../BaseSearchableSnapshotsIntegTestCase.java | 2 +- .../SearchableSnapshotDataTierIntegTests.java | 84 +++++++++++++++++++ .../SearchableSnapshotsIntegTests.java | 10 ++- .../store/SearchableSnapshotDirectory.java | 2 +- .../HasFrozenCacheAllocationDecider.java | 2 +- .../SearchableSnapshotAllocator.java | 2 +- .../SearchableSnapshots.java | 14 +--- ...ransportMountSearchableSnapshotAction.java | 37 +++++--- ...rtSearchableSnapshotCacheStoresAction.java | 2 +- ...SearchableSnapshotDirectoryStatsTests.java | 12 +-- .../store/cache/FrozenIndexInputTests.java | 3 +- .../SearchableSnapshotAllocatorTests.java | 2 +- 18 files changed, 315 insertions(+), 43 deletions(-) create mode 100644 x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/searchablesnapshots/SearchableSnapshotsConstantsTests.java create mode 100644 x-pack/plugin/searchable-snapshots/src/internalClusterTest/java/org/elasticsearch/xpack/searchablesnapshots/SearchableSnapshotDataTierIntegTests.java diff --git a/build.gradle b/build.gradle index e77bcb950f7b0..af41c21ad0cf9 100644 --- a/build.gradle +++ b/build.gradle @@ -192,7 +192,8 @@ tasks.register("verifyVersions") { */ boolean bwc_tests_enabled = true -String bwc_tests_disabled_issue = "" /* place a PR link here when committing bwc changes */ +// place a PR link here when committing bwc changes: +String bwc_tests_disabled_issue = "" /* * FIPS 140-2 behavior was fixed in 7.11.0. Before that there is no way to run elasticsearch in a * JVM that is properly configured to be in fips mode with BCFIPS. For now we need to disable diff --git a/x-pack/plugin/core/src/internalClusterTest/java/org/elasticsearch/xpack/cluster/routing/allocation/DataTierIT.java b/x-pack/plugin/core/src/internalClusterTest/java/org/elasticsearch/xpack/cluster/routing/allocation/DataTierIT.java index cde70ec83143a..5d2cd38b5b2ac 100644 --- a/x-pack/plugin/core/src/internalClusterTest/java/org/elasticsearch/xpack/cluster/routing/allocation/DataTierIT.java +++ b/x-pack/plugin/core/src/internalClusterTest/java/org/elasticsearch/xpack/cluster/routing/allocation/DataTierIT.java @@ -7,6 +7,7 @@ package org.elasticsearch.xpack.cluster.routing.allocation; +import org.elasticsearch.action.admin.indices.settings.put.UpdateSettingsRequest; import org.elasticsearch.action.admin.indices.shrink.ResizeType; import org.elasticsearch.action.admin.indices.template.put.PutComposableIndexTemplateAction; import org.elasticsearch.cluster.health.ClusterHealthStatus; @@ -271,6 +272,35 @@ public void testTierFilteringIgnoredByFilterAllocationDecider() { .get(); } + public void testIllegalOnFrozen() { + startDataNode(); + + IllegalArgumentException e = expectThrows(IllegalArgumentException.class, + () -> createIndex(index, Settings.builder() + .put("index.number_of_shards", 1) + .put("index.number_of_replicas", 0) + .put(DataTierAllocationDecider.INDEX_ROUTING_PREFER, DataTier.DATA_FROZEN) + .build())); + assertThat(e.getMessage(), equalTo("[data_frozen] tier can only be used for partial searchable snapshots")); + + String initialTier = randomFrom(DataTier.DATA_HOT, DataTier.DATA_WARM, DataTier.DATA_COLD); + createIndex(index, Settings.builder() + .put("index.number_of_shards", 1) + .put("index.number_of_replicas", 0) + .put(DataTierAllocationDecider.INDEX_ROUTING_PREFER, initialTier) + .build()); + + IllegalArgumentException e2 = expectThrows(IllegalArgumentException.class, () -> updatePreference(DataTier.DATA_FROZEN)); + assertThat(e2.getMessage(), equalTo("[data_frozen] tier can only be used for partial searchable snapshots")); + + updatePreference(randomValueOtherThan(initialTier, () -> randomFrom(DataTier.DATA_HOT, DataTier.DATA_WARM, DataTier.DATA_COLD))); + } + + private void updatePreference(String tier) { + client().admin().indices().updateSettings(new UpdateSettingsRequest(index) + .settings(org.elasticsearch.common.collect.Map.of(DataTierAllocationDecider.INDEX_ROUTING_PREFER, tier))).actionGet(); + } + private DataTiersFeatureSetUsage getUsage() { XPackUsageResponse usages = new XPackUsageRequestBuilder(client()).execute().actionGet(); XPackFeatureSet.Usage dtUsage = usages.getUsages().stream() diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/cluster/routing/allocation/DataTierAllocationDecider.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/cluster/routing/allocation/DataTierAllocationDecider.java index 845b17851725f..7c29cb348dc46 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/cluster/routing/allocation/DataTierAllocationDecider.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/cluster/routing/allocation/DataTierAllocationDecider.java @@ -21,13 +21,20 @@ import org.elasticsearch.common.settings.ClusterSettings; import org.elasticsearch.common.settings.Setting; import org.elasticsearch.common.settings.Settings; +import org.elasticsearch.index.IndexModule; import org.elasticsearch.xpack.core.DataTier; +import org.elasticsearch.xpack.searchablesnapshots.SearchableSnapshotsConstants; import java.util.Arrays; +import java.util.Collection; +import java.util.Iterator; +import java.util.Map; import java.util.Optional; import java.util.Set; import java.util.stream.Collectors; +import static org.elasticsearch.xpack.core.DataTier.DATA_FROZEN; + /** * The {@code DataTierAllocationDecider} is a custom allocation decider that behaves similar to the * {@link org.elasticsearch.cluster.routing.allocation.decider.FilterAllocationDecider}, however it @@ -45,6 +52,7 @@ public class DataTierAllocationDecider extends AllocationDecider { public static final String INDEX_ROUTING_PREFER = "index.routing.allocation.include._tier_preference"; public static final String INDEX_ROUTING_EXCLUDE = "index.routing.allocation.exclude._tier"; + private static final DataTierValidator VALIDATOR = new DataTierValidator(); public static final Setting CLUSTER_ROUTING_REQUIRE_SETTING = Setting.simpleString(CLUSTER_ROUTING_REQUIRE, DataTierAllocationDecider::validateTierSetting, Setting.Property.Dynamic, Setting.Property.NodeScope); public static final Setting CLUSTER_ROUTING_INCLUDE_SETTING = Setting.simpleString(CLUSTER_ROUTING_INCLUDE, @@ -52,13 +60,13 @@ public class DataTierAllocationDecider extends AllocationDecider { public static final Setting CLUSTER_ROUTING_EXCLUDE_SETTING = Setting.simpleString(CLUSTER_ROUTING_EXCLUDE, DataTierAllocationDecider::validateTierSetting, Setting.Property.Dynamic, Setting.Property.NodeScope); public static final Setting INDEX_ROUTING_REQUIRE_SETTING = Setting.simpleString(INDEX_ROUTING_REQUIRE, - DataTierAllocationDecider::validateTierSetting, Setting.Property.Dynamic, Setting.Property.IndexScope); + VALIDATOR, Setting.Property.Dynamic, Setting.Property.IndexScope); public static final Setting INDEX_ROUTING_INCLUDE_SETTING = Setting.simpleString(INDEX_ROUTING_INCLUDE, - DataTierAllocationDecider::validateTierSetting, Setting.Property.Dynamic, Setting.Property.IndexScope); + VALIDATOR, Setting.Property.Dynamic, Setting.Property.IndexScope); public static final Setting INDEX_ROUTING_EXCLUDE_SETTING = Setting.simpleString(INDEX_ROUTING_EXCLUDE, - DataTierAllocationDecider::validateTierSetting, Setting.Property.Dynamic, Setting.Property.IndexScope); + VALIDATOR, Setting.Property.Dynamic, Setting.Property.IndexScope); public static final Setting INDEX_ROUTING_PREFER_SETTING = Setting.simpleString(INDEX_ROUTING_PREFER, - DataTierAllocationDecider::validateTierSetting, Setting.Property.Dynamic, Setting.Property.IndexScope); + VALIDATOR, Setting.Property.Dynamic, Setting.Property.IndexScope); private static void validateTierSetting(String setting) { if (Strings.hasText(setting)) { @@ -71,6 +79,32 @@ private static void validateTierSetting(String setting) { } } + private static class DataTierValidator implements Setting.Validator { + private static final Collection> dependencies = + org.elasticsearch.common.collect.List.of(IndexModule.INDEX_STORE_TYPE_SETTING, + SearchableSnapshotsConstants.SNAPSHOT_PARTIAL_SETTING); + + @Override + public void validate(String value) { + validateTierSetting(value); + } + + @Override + public void validate(String value, Map, Object> settings) { + if (Strings.hasText(value) && SearchableSnapshotsConstants.isPartialSearchableSnapshotIndex(settings) == false) { + String[] split = value.split(","); + if (Arrays.stream(split).anyMatch(DATA_FROZEN::equals)) { + throw new IllegalArgumentException("[" + DATA_FROZEN + "] tier can only be used for partial searchable snapshots"); + } + } + } + + @Override + public Iterator> settings() { + return dependencies.iterator(); + } + } + private volatile String clusterRequire; private volatile String clusterInclude; private volatile String clusterExclude; diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/searchablesnapshots/SearchableSnapshotsConstants.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/searchablesnapshots/SearchableSnapshotsConstants.java index c1b8d0e9b90af..5ad93d8955360 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/searchablesnapshots/SearchableSnapshotsConstants.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/searchablesnapshots/SearchableSnapshotsConstants.java @@ -7,19 +7,41 @@ package org.elasticsearch.xpack.searchablesnapshots; import org.elasticsearch.Version; +import org.elasticsearch.common.settings.Setting; import org.elasticsearch.common.settings.Settings; +import java.util.Map; + import static org.elasticsearch.index.IndexModule.INDEX_STORE_TYPE_SETTING; public class SearchableSnapshotsConstants { public static final String SNAPSHOT_DIRECTORY_FACTORY_KEY = "snapshot"; public static final String SNAPSHOT_RECOVERY_STATE_FACTORY_KEY = "snapshot_prewarm"; + public static final Setting SNAPSHOT_PARTIAL_SETTING = Setting.boolSetting( + "index.store.snapshot.partial", + false, + Setting.Property.IndexScope, + Setting.Property.PrivateIndex, + Setting.Property.NotCopyableOnResize + ); public static boolean isSearchableSnapshotStore(Settings indexSettings) { return SNAPSHOT_DIRECTORY_FACTORY_KEY.equals(INDEX_STORE_TYPE_SETTING.get(indexSettings)); } + /** + * Based on a map from setting to value, do the settings represent a partial searchable snapshot index? + * + * Both index.store.type and index.store.snapshot.partial must be supplied. + */ + public static boolean isPartialSearchableSnapshotIndex(Map, Object> indexSettings) { + assert indexSettings.containsKey(INDEX_STORE_TYPE_SETTING) : "must include store type in map"; + assert indexSettings.get(SNAPSHOT_PARTIAL_SETTING) != null : "partial setting must be non-null in map (has default value)"; + return SNAPSHOT_DIRECTORY_FACTORY_KEY.equals(indexSettings.get(INDEX_STORE_TYPE_SETTING)) + && (boolean) indexSettings.get(SNAPSHOT_PARTIAL_SETTING); + } + public static final String CACHE_FETCH_ASYNC_THREAD_POOL_NAME = "searchable_snapshots_cache_fetch_async"; public static final String CACHE_FETCH_ASYNC_THREAD_POOL_SETTING = "xpack.searchable_snapshots.cache_fetch_async_thread_pool"; diff --git a/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/cluster/routing/allocation/DataTierAllocationDeciderTests.java b/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/cluster/routing/allocation/DataTierAllocationDeciderTests.java index 4a15cc59baeff..bc357ca4ef00d 100644 --- a/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/cluster/routing/allocation/DataTierAllocationDeciderTests.java +++ b/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/cluster/routing/allocation/DataTierAllocationDeciderTests.java @@ -7,6 +7,7 @@ package org.elasticsearch.xpack.cluster.routing.allocation; +import joptsimple.internal.Strings; import org.elasticsearch.Version; import org.elasticsearch.cluster.ClusterState; import org.elasticsearch.cluster.ESAllocationTestCase; @@ -27,20 +28,26 @@ import org.elasticsearch.cluster.routing.allocation.decider.Decision; import org.elasticsearch.cluster.routing.allocation.decider.ReplicaAfterPrimaryActiveAllocationDecider; import org.elasticsearch.cluster.routing.allocation.decider.SameShardAllocationDecider; +import org.elasticsearch.common.Randomness; import org.elasticsearch.common.settings.ClusterSettings; import org.elasticsearch.common.settings.Setting; import org.elasticsearch.common.settings.Settings; +import org.elasticsearch.index.IndexModule; import org.elasticsearch.index.shard.ShardId; import org.elasticsearch.snapshots.EmptySnapshotsInfoService; import org.elasticsearch.test.gateway.TestGatewayAllocator; import org.elasticsearch.xpack.core.DataTier; +import org.elasticsearch.xpack.searchablesnapshots.SearchableSnapshotsConstants; +import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.HashSet; +import java.util.List; import java.util.Optional; import java.util.Set; +import static org.elasticsearch.xpack.core.DataTier.DATA_FROZEN; import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.equalTo; @@ -702,6 +709,53 @@ public void testExistedClusterFilters() { "tier filters [data_hot,data_warm]")); } + public void testFrozenIllegalForRegularIndices() { + List tierList = new ArrayList<>(randomSubsetOf(DataTier.ALL_DATA_TIERS)); + if (tierList.contains(DATA_FROZEN) == false) { + tierList.add(DATA_FROZEN); + } + Randomness.shuffle(tierList); + + String value = Strings.join(tierList, ","); + Setting setting = randomTierSetting(); + Settings.Builder builder = Settings.builder().put(setting.getKey(), value); + if (randomBoolean()) { + builder.put(IndexModule.INDEX_STORE_TYPE_SETTING.getKey(), SearchableSnapshotsConstants.SNAPSHOT_DIRECTORY_FACTORY_KEY); + } + + Settings settings = builder.build(); + IllegalArgumentException exception = expectThrows(IllegalArgumentException.class, () -> setting.get(settings)); + assertThat(exception.getMessage(), equalTo("[data_frozen] tier can only be used for partial searchable snapshots")); + } + + public void testFrozenLegalForPartialSnapshot() { + List tierList = new ArrayList<>(randomSubsetOf(DataTier.ALL_DATA_TIERS)); + if (tierList.contains(DATA_FROZEN) == false) { + tierList.add(DATA_FROZEN); + } + Randomness.shuffle(tierList); + + String value = Strings.join(tierList, ","); + Setting setting = randomTierSetting(); + Settings.Builder builder = Settings.builder().put(setting.getKey(), value); + builder.put(IndexModule.INDEX_STORE_TYPE_SETTING.getKey(), SearchableSnapshotsConstants.SNAPSHOT_DIRECTORY_FACTORY_KEY); + builder.put(SearchableSnapshotsConstants.SNAPSHOT_PARTIAL_SETTING.getKey(), true); + + Settings settings = builder.build(); + + // validate do not throw + assertThat(setting.get(settings), equalTo(value)); + } + + public Setting randomTierSetting() { + //noinspection unchecked + return randomFrom( + DataTierAllocationDecider.INDEX_ROUTING_EXCLUDE_SETTING, + DataTierAllocationDecider.INDEX_ROUTING_INCLUDE_SETTING, + DataTierAllocationDecider.INDEX_ROUTING_REQUIRE_SETTING, + DataTierAllocationDecider.INDEX_ROUTING_PREFER_SETTING); + } + private ClusterState prepareState(ClusterState initialState) { return prepareState(initialState, Settings.EMPTY); } diff --git a/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/searchablesnapshots/SearchableSnapshotsConstantsTests.java b/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/searchablesnapshots/SearchableSnapshotsConstantsTests.java new file mode 100644 index 0000000000000..56fc2a4f5a04b --- /dev/null +++ b/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/searchablesnapshots/SearchableSnapshotsConstantsTests.java @@ -0,0 +1,35 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +package org.elasticsearch.xpack.searchablesnapshots; + +import org.elasticsearch.index.IndexModule; +import org.elasticsearch.test.ESTestCase; + +import org.elasticsearch.common.collect.Map; + +import static org.hamcrest.Matchers.is; + +public class SearchableSnapshotsConstantsTests extends ESTestCase { + + public void testIsPartialSearchableSnapshotIndex() { + assertThat(SearchableSnapshotsConstants.isPartialSearchableSnapshotIndex( + Map.of(IndexModule.INDEX_STORE_TYPE_SETTING, SearchableSnapshotsConstants.SNAPSHOT_DIRECTORY_FACTORY_KEY, + SearchableSnapshotsConstants.SNAPSHOT_PARTIAL_SETTING, false)), + is(false)); + + assertThat(SearchableSnapshotsConstants.isPartialSearchableSnapshotIndex( + Map.of(IndexModule.INDEX_STORE_TYPE_SETTING, "abc", + SearchableSnapshotsConstants.SNAPSHOT_PARTIAL_SETTING, randomBoolean())), + is(false)); + + assertThat(SearchableSnapshotsConstants.isPartialSearchableSnapshotIndex( + Map.of(IndexModule.INDEX_STORE_TYPE_SETTING, SearchableSnapshotsConstants.SNAPSHOT_DIRECTORY_FACTORY_KEY, + SearchableSnapshotsConstants.SNAPSHOT_PARTIAL_SETTING, true)), + is(true)); + } +} diff --git a/x-pack/plugin/searchable-snapshots/src/internalClusterTest/java/org/elasticsearch/xpack/searchablesnapshots/BaseSearchableSnapshotsIntegTestCase.java b/x-pack/plugin/searchable-snapshots/src/internalClusterTest/java/org/elasticsearch/xpack/searchablesnapshots/BaseSearchableSnapshotsIntegTestCase.java index 3c9dcdddc85b3..93675b2de2f63 100644 --- a/x-pack/plugin/searchable-snapshots/src/internalClusterTest/java/org/elasticsearch/xpack/searchablesnapshots/BaseSearchableSnapshotsIntegTestCase.java +++ b/x-pack/plugin/searchable-snapshots/src/internalClusterTest/java/org/elasticsearch/xpack/searchablesnapshots/BaseSearchableSnapshotsIntegTestCase.java @@ -157,7 +157,7 @@ protected void mountSnapshot( storage ); - final RestoreSnapshotResponse restoreResponse = client().execute(MountSearchableSnapshotAction.INSTANCE, mountRequest).get(); + final RestoreSnapshotResponse restoreResponse = client().execute(MountSearchableSnapshotAction.INSTANCE, mountRequest).actionGet(); assertThat(restoreResponse.getRestoreInfo().successfulShards(), equalTo(getNumShards(restoredIndexName).numPrimaries)); assertThat(restoreResponse.getRestoreInfo().failedShards(), equalTo(0)); } diff --git a/x-pack/plugin/searchable-snapshots/src/internalClusterTest/java/org/elasticsearch/xpack/searchablesnapshots/SearchableSnapshotDataTierIntegTests.java b/x-pack/plugin/searchable-snapshots/src/internalClusterTest/java/org/elasticsearch/xpack/searchablesnapshots/SearchableSnapshotDataTierIntegTests.java new file mode 100644 index 0000000000000..4566968268906 --- /dev/null +++ b/x-pack/plugin/searchable-snapshots/src/internalClusterTest/java/org/elasticsearch/xpack/searchablesnapshots/SearchableSnapshotDataTierIntegTests.java @@ -0,0 +1,84 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +package org.elasticsearch.xpack.searchablesnapshots; + +import org.elasticsearch.action.admin.indices.settings.put.UpdateSettingsRequest; +import org.elasticsearch.common.settings.Settings; +import org.elasticsearch.test.ESIntegTestCase; +import org.elasticsearch.xpack.cluster.routing.allocation.DataTierAllocationDecider; +import org.elasticsearch.xpack.core.DataTier; +import org.elasticsearch.xpack.core.searchablesnapshots.MountSearchableSnapshotRequest; + +@ESIntegTestCase.ClusterScope(scope = ESIntegTestCase.Scope.TEST) +public class SearchableSnapshotDataTierIntegTests extends BaseSearchableSnapshotsIntegTestCase { + + private static final String repoName = "test-repo"; + private static final String indexName = "test-index"; + private static final String snapshotName = "test-snapshot"; + private static final String mountedIndexName = "test-index-mounted"; + private static final Settings frozenSettings = Settings.builder() + .put(DataTierAllocationDecider.INDEX_ROUTING_PREFER, DataTier.DATA_FROZEN) + .build(); + + public void testPartialLegalOnFrozen() throws Exception { + createRepository(repoName, "fs"); + createIndex(indexName); + createFullSnapshot(repoName, snapshotName); + Settings mountSettings = randomFrom(Settings.EMPTY, frozenSettings); + mountSnapshot( + repoName, + snapshotName, + indexName, + mountedIndexName, + mountSettings, + MountSearchableSnapshotRequest.Storage.SHARED_CACHE + ); + + updatePreference(DataTier.DATA_FROZEN); + } + + public void testFullIllegalOnFrozen() throws Exception { + createRepository(repoName, "fs"); + createIndex(indexName); + createFullSnapshot(repoName, snapshotName); + expectThrows( + IllegalArgumentException.class, + () -> mountSnapshot( + repoName, + snapshotName, + indexName, + mountedIndexName, + frozenSettings, + MountSearchableSnapshotRequest.Storage.FULL_COPY + ) + ); + Settings mountSettings = randomFrom( + Settings.EMPTY, + Settings.builder() + .put( + DataTierAllocationDecider.INDEX_ROUTING_PREFER, + randomValueOtherThan(DataTier.DATA_FROZEN, () -> randomFrom(DataTier.ALL_DATA_TIERS)) + ) + .build() + ); + mountSnapshot(repoName, snapshotName, indexName, mountedIndexName, mountSettings, MountSearchableSnapshotRequest.Storage.FULL_COPY); + + expectThrows(IllegalArgumentException.class, () -> updatePreference(DataTier.DATA_FROZEN)); + } + + private void updatePreference(String tier) { + client().admin() + .indices() + .updateSettings( + new UpdateSettingsRequest(mountedIndexName).settings( + org.elasticsearch.common.collect.Map.of(DataTierAllocationDecider.INDEX_ROUTING_PREFER, tier) + ) + ) + .actionGet(); + } +} diff --git a/x-pack/plugin/searchable-snapshots/src/internalClusterTest/java/org/elasticsearch/xpack/searchablesnapshots/SearchableSnapshotsIntegTests.java b/x-pack/plugin/searchable-snapshots/src/internalClusterTest/java/org/elasticsearch/xpack/searchablesnapshots/SearchableSnapshotsIntegTests.java index 78f0c90fd8cd0..056f7aefffaac 100644 --- a/x-pack/plugin/searchable-snapshots/src/internalClusterTest/java/org/elasticsearch/xpack/searchablesnapshots/SearchableSnapshotsIntegTests.java +++ b/x-pack/plugin/searchable-snapshots/src/internalClusterTest/java/org/elasticsearch/xpack/searchablesnapshots/SearchableSnapshotsIntegTests.java @@ -223,7 +223,12 @@ public void testCreateAndRestoreSearchableSnapshot() throws Exception { } final String expectedDataTiersPreference; if (randomBoolean()) { - expectedDataTiersPreference = String.join(",", randomSubsetOf(DataTier.ALL_DATA_TIERS)); + expectedDataTiersPreference = String.join( + ",", + randomSubsetOf( + DataTier.ALL_DATA_TIERS.stream().filter(tier -> tier.equals(DataTier.DATA_FROZEN) == false).collect(Collectors.toSet()) + ) + ); indexSettingsBuilder.put(DataTierAllocationDecider.INDEX_ROUTING_PREFER, expectedDataTiersPreference); } else { expectedDataTiersPreference = getDataTiersPreference(MountSearchableSnapshotRequest.Storage.FULL_COPY); @@ -557,7 +562,7 @@ public void testCreateAndRestorePartialSearchableSnapshot() throws Exception { assertThat(IndexMetadata.INDEX_AUTO_EXPAND_REPLICAS_SETTING.get(settings).toString(), equalTo("false")); assertThat(IndexMetadata.INDEX_NUMBER_OF_REPLICAS_SETTING.get(settings), equalTo(expectedReplicas)); assertThat(DataTierAllocationDecider.INDEX_ROUTING_PREFER_SETTING.get(settings), equalTo(expectedDataTiersPreference)); - assertTrue(SearchableSnapshots.SNAPSHOT_PARTIAL_SETTING.get(settings)); + assertTrue(SearchableSnapshotsConstants.SNAPSHOT_PARTIAL_SETTING.get(settings)); assertTrue(DiskThresholdDecider.SETTING_IGNORE_DISK_WATERMARKS.get(settings)); checkSoftDeletesNotEagerlyLoaded(restoredIndexName); @@ -691,6 +696,7 @@ public void testCreateAndRestorePartialSearchableSnapshot() throws Exception { Settings.builder() .putNull(IndexModule.INDEX_STORE_TYPE_SETTING.getKey()) .putNull(IndexModule.INDEX_RECOVERY_TYPE_SETTING.getKey()) + .put(DataTierAllocationDecider.INDEX_ROUTING_PREFER, DataTier.DATA_HOT) .build() ) ); diff --git a/x-pack/plugin/searchable-snapshots/src/main/java/org/elasticsearch/index/store/SearchableSnapshotDirectory.java b/x-pack/plugin/searchable-snapshots/src/main/java/org/elasticsearch/index/store/SearchableSnapshotDirectory.java index 2661e3c91da66..7d559e24073f9 100644 --- a/x-pack/plugin/searchable-snapshots/src/main/java/org/elasticsearch/index/store/SearchableSnapshotDirectory.java +++ b/x-pack/plugin/searchable-snapshots/src/main/java/org/elasticsearch/index/store/SearchableSnapshotDirectory.java @@ -94,7 +94,7 @@ import static org.elasticsearch.xpack.searchablesnapshots.SearchableSnapshots.SNAPSHOT_CACHE_PREWARM_ENABLED_SETTING; import static org.elasticsearch.xpack.searchablesnapshots.SearchableSnapshots.SNAPSHOT_INDEX_ID_SETTING; import static org.elasticsearch.xpack.searchablesnapshots.SearchableSnapshots.SNAPSHOT_INDEX_NAME_SETTING; -import static org.elasticsearch.xpack.searchablesnapshots.SearchableSnapshots.SNAPSHOT_PARTIAL_SETTING; +import static org.elasticsearch.xpack.searchablesnapshots.SearchableSnapshotsConstants.SNAPSHOT_PARTIAL_SETTING; import static org.elasticsearch.xpack.searchablesnapshots.SearchableSnapshots.SNAPSHOT_REPOSITORY_NAME_SETTING; import static org.elasticsearch.xpack.searchablesnapshots.SearchableSnapshots.SNAPSHOT_REPOSITORY_UUID_SETTING; import static org.elasticsearch.xpack.searchablesnapshots.SearchableSnapshots.SNAPSHOT_SNAPSHOT_ID_SETTING; diff --git a/x-pack/plugin/searchable-snapshots/src/main/java/org/elasticsearch/xpack/searchablesnapshots/HasFrozenCacheAllocationDecider.java b/x-pack/plugin/searchable-snapshots/src/main/java/org/elasticsearch/xpack/searchablesnapshots/HasFrozenCacheAllocationDecider.java index 2a4d4df06b676..fbdf446eabe6c 100644 --- a/x-pack/plugin/searchable-snapshots/src/main/java/org/elasticsearch/xpack/searchablesnapshots/HasFrozenCacheAllocationDecider.java +++ b/x-pack/plugin/searchable-snapshots/src/main/java/org/elasticsearch/xpack/searchablesnapshots/HasFrozenCacheAllocationDecider.java @@ -18,7 +18,7 @@ import org.elasticsearch.xpack.searchablesnapshots.cache.FrozenCacheInfoService; import static org.elasticsearch.snapshots.SnapshotsService.SNAPSHOT_CACHE_SIZE_SETTING; -import static org.elasticsearch.xpack.searchablesnapshots.SearchableSnapshots.SNAPSHOT_PARTIAL_SETTING; +import static org.elasticsearch.xpack.searchablesnapshots.SearchableSnapshotsConstants.SNAPSHOT_PARTIAL_SETTING; public class HasFrozenCacheAllocationDecider extends AllocationDecider { diff --git a/x-pack/plugin/searchable-snapshots/src/main/java/org/elasticsearch/xpack/searchablesnapshots/SearchableSnapshotAllocator.java b/x-pack/plugin/searchable-snapshots/src/main/java/org/elasticsearch/xpack/searchablesnapshots/SearchableSnapshotAllocator.java index 1b10c29c95ff2..133d13f9f6df9 100644 --- a/x-pack/plugin/searchable-snapshots/src/main/java/org/elasticsearch/xpack/searchablesnapshots/SearchableSnapshotAllocator.java +++ b/x-pack/plugin/searchable-snapshots/src/main/java/org/elasticsearch/xpack/searchablesnapshots/SearchableSnapshotAllocator.java @@ -60,7 +60,7 @@ import static org.elasticsearch.xpack.searchablesnapshots.SearchableSnapshots.SNAPSHOT_INDEX_ID_SETTING; import static org.elasticsearch.xpack.searchablesnapshots.SearchableSnapshots.SNAPSHOT_INDEX_NAME_SETTING; -import static org.elasticsearch.xpack.searchablesnapshots.SearchableSnapshots.SNAPSHOT_PARTIAL_SETTING; +import static org.elasticsearch.xpack.searchablesnapshots.SearchableSnapshotsConstants.SNAPSHOT_PARTIAL_SETTING; import static org.elasticsearch.xpack.searchablesnapshots.SearchableSnapshots.SNAPSHOT_REPOSITORY_NAME_SETTING; import static org.elasticsearch.xpack.searchablesnapshots.SearchableSnapshots.SNAPSHOT_SNAPSHOT_ID_SETTING; import static org.elasticsearch.xpack.searchablesnapshots.SearchableSnapshots.SNAPSHOT_SNAPSHOT_NAME_SETTING; diff --git a/x-pack/plugin/searchable-snapshots/src/main/java/org/elasticsearch/xpack/searchablesnapshots/SearchableSnapshots.java b/x-pack/plugin/searchable-snapshots/src/main/java/org/elasticsearch/xpack/searchablesnapshots/SearchableSnapshots.java index fcb12c8ef8b4c..8fbf149b8491a 100644 --- a/x-pack/plugin/searchable-snapshots/src/main/java/org/elasticsearch/xpack/searchablesnapshots/SearchableSnapshots.java +++ b/x-pack/plugin/searchable-snapshots/src/main/java/org/elasticsearch/xpack/searchablesnapshots/SearchableSnapshots.java @@ -188,13 +188,6 @@ public class SearchableSnapshots extends Plugin implements IndexStorePlugin, Eng Setting.Property.NodeScope, Setting.Property.NotCopyableOnResize ); - public static final Setting SNAPSHOT_PARTIAL_SETTING = Setting.boolSetting( - "index.store.snapshot.partial", - false, - Setting.Property.IndexScope, - Setting.Property.PrivateIndex, - Setting.Property.NotCopyableOnResize - ); public static final String SNAPSHOT_BLOB_CACHE_METADATA_FILES_MAX_LENGTH = "index.store.snapshot.blob_cache.metadata_files.max_length"; public static final Setting SNAPSHOT_BLOB_CACHE_METADATA_FILES_MAX_LENGTH_SETTING = new Setting<>( new Setting.SimpleKey(SNAPSHOT_BLOB_CACHE_METADATA_FILES_MAX_LENGTH), @@ -222,13 +215,12 @@ public class SearchableSnapshots extends Plugin implements IndexStorePlugin, Eng ); /** - * Prefer to allocate to the cold tier, then the frozen tier, then the warm tier, then the hot tier + * Prefer to allocate to the cold tier, then the warm tier, then the hot tier * This affects the system searchable snapshot cache index (not the searchable snapshot index itself) */ public static final String DATA_TIERS_CACHE_INDEX_PREFERENCE = String.join( ",", DataTier.DATA_COLD, - DataTier.DATA_FROZEN, DataTier.DATA_WARM, DataTier.DATA_HOT ); @@ -300,7 +292,7 @@ public List> getSettings() { SNAPSHOT_CACHE_PREWARM_ENABLED_SETTING, SNAPSHOT_CACHE_EXCLUDED_FILE_TYPES_SETTING, SNAPSHOT_UNCACHED_CHUNK_SIZE_SETTING, - SNAPSHOT_PARTIAL_SETTING, + SearchableSnapshotsConstants.SNAPSHOT_PARTIAL_SETTING, SNAPSHOT_BLOB_CACHE_METADATA_FILES_MAX_LENGTH_SETTING, CacheService.SNAPSHOT_CACHE_SIZE_SETTING, CacheService.SNAPSHOT_CACHE_RANGE_SIZE_SETTING, @@ -445,7 +437,7 @@ public Map getDirectoryFactories() { public Optional getEngineFactory(IndexSettings indexSettings) { if (SearchableSnapshotsConstants.isSearchableSnapshotStore(indexSettings.getSettings())) { final Boolean frozen = indexSettings.getSettings().getAsBoolean("index.frozen", null); - final boolean useFrozenEngine = SearchableSnapshots.SNAPSHOT_PARTIAL_SETTING.get(indexSettings.getSettings()) + final boolean useFrozenEngine = SearchableSnapshotsConstants.SNAPSHOT_PARTIAL_SETTING.get(indexSettings.getSettings()) && (frozen == null || frozen.equals(Boolean.TRUE)); if (useFrozenEngine) { diff --git a/x-pack/plugin/searchable-snapshots/src/main/java/org/elasticsearch/xpack/searchablesnapshots/action/TransportMountSearchableSnapshotAction.java b/x-pack/plugin/searchable-snapshots/src/main/java/org/elasticsearch/xpack/searchablesnapshots/action/TransportMountSearchableSnapshotAction.java index 353076aa3950b..368a93afcc65c 100644 --- a/x-pack/plugin/searchable-snapshots/src/main/java/org/elasticsearch/xpack/searchablesnapshots/action/TransportMountSearchableSnapshotAction.java +++ b/x-pack/plugin/searchable-snapshots/src/main/java/org/elasticsearch/xpack/searchablesnapshots/action/TransportMountSearchableSnapshotAction.java @@ -23,6 +23,7 @@ import org.elasticsearch.cluster.routing.allocation.decider.DiskThresholdDecider; import org.elasticsearch.cluster.service.ClusterService; import org.elasticsearch.common.inject.Inject; +import org.elasticsearch.common.settings.Setting; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.index.IndexNotFoundException; import org.elasticsearch.indices.SystemIndices; @@ -42,6 +43,7 @@ import org.elasticsearch.xpack.searchablesnapshots.SearchableSnapshotsConstants; import java.util.Arrays; +import java.util.Collection; import java.util.LinkedHashSet; import java.util.Locale; import java.util.Map; @@ -64,6 +66,13 @@ public class TransportMountSearchableSnapshotAction extends TransportMasterNodeA MountSearchableSnapshotRequest, RestoreSnapshotResponse> { + private static final Collection> DATA_TIER_ALLOCATION_SETTINGS = org.elasticsearch.common.collect.List.of( + DataTierAllocationDecider.INDEX_ROUTING_EXCLUDE_SETTING, + DataTierAllocationDecider.INDEX_ROUTING_INCLUDE_SETTING, + DataTierAllocationDecider.INDEX_ROUTING_REQUIRE_SETTING, + DataTierAllocationDecider.INDEX_ROUTING_PREFER_SETTING + ); + private final Client client; private final RepositoriesService repositoriesService; private final XPackLicenseState licenseState; @@ -133,7 +142,7 @@ private static Settings buildIndexSettings( .put(INDEX_RECOVERY_TYPE_SETTING.getKey(), SearchableSnapshotsConstants.SNAPSHOT_RECOVERY_STATE_FACTORY_KEY); if (storage == MountSearchableSnapshotRequest.Storage.SHARED_CACHE) { - settings.put(SearchableSnapshots.SNAPSHOT_PARTIAL_SETTING.getKey(), true) + settings.put(SearchableSnapshotsConstants.SNAPSHOT_PARTIAL_SETTING.getKey(), true) .put(DiskThresholdDecider.SETTING_IGNORE_DISK_WATERMARKS.getKey(), true); } @@ -209,6 +218,20 @@ protected void masterOperation( } } + Settings indexSettings = Settings.builder() + .put(IndexMetadata.SETTING_NUMBER_OF_REPLICAS, 0) // can be overridden + .put(IndexMetadata.SETTING_AUTO_EXPAND_REPLICAS, false) // can be overridden + .put(DataTierAllocationDecider.INDEX_ROUTING_PREFER, getDataTiersPreference(request.storage())) + .put(request.indexSettings()) + .put(buildIndexSettings(repoData.getUuid(), request.repositoryName(), snapshotId, indexId, request.storage())) + .build(); + + // todo: restore archives bad settings, for now we verify just the data tiers, since we know their dependencies are available + // in settings + for (Setting dataTierAllocationSetting : DATA_TIER_ALLOCATION_SETTINGS) { + dataTierAllocationSetting.get(indexSettings); + } + client.admin() .cluster() .restoreSnapshot( @@ -219,17 +242,7 @@ protected void masterOperation( .renamePattern(".+") .renameReplacement(mountedIndexName) // Pass through index settings, adding the index-level settings required to use searchable snapshots - .indexSettings( - Settings.builder() - .put(IndexMetadata.SETTING_NUMBER_OF_REPLICAS, 0) // can be overridden - .put(IndexMetadata.SETTING_AUTO_EXPAND_REPLICAS, false) // can be overridden - .put(DataTierAllocationDecider.INDEX_ROUTING_PREFER, getDataTiersPreference(request.storage())) - .put(request.indexSettings()) - .put( - buildIndexSettings(repoData.getUuid(), request.repositoryName(), snapshotId, indexId, request.storage()) - ) - .build() - ) + .indexSettings(indexSettings) // Pass through ignored index settings .ignoreIndexSettings(ignoreIndexSettings.toArray(new String[0])) // Don't include global state diff --git a/x-pack/plugin/searchable-snapshots/src/main/java/org/elasticsearch/xpack/searchablesnapshots/action/cache/TransportSearchableSnapshotCacheStoresAction.java b/x-pack/plugin/searchable-snapshots/src/main/java/org/elasticsearch/xpack/searchablesnapshots/action/cache/TransportSearchableSnapshotCacheStoresAction.java index 09035aa0b2738..0a9ecd1e9f5a9 100644 --- a/x-pack/plugin/searchable-snapshots/src/main/java/org/elasticsearch/xpack/searchablesnapshots/action/cache/TransportSearchableSnapshotCacheStoresAction.java +++ b/x-pack/plugin/searchable-snapshots/src/main/java/org/elasticsearch/xpack/searchablesnapshots/action/cache/TransportSearchableSnapshotCacheStoresAction.java @@ -31,7 +31,7 @@ import java.util.List; import java.util.Optional; -import static org.elasticsearch.xpack.searchablesnapshots.SearchableSnapshots.SNAPSHOT_PARTIAL_SETTING; +import static org.elasticsearch.xpack.searchablesnapshots.SearchableSnapshotsConstants.SNAPSHOT_PARTIAL_SETTING; public class TransportSearchableSnapshotCacheStoresAction extends TransportNodesAction< TransportSearchableSnapshotCacheStoresAction.Request, diff --git a/x-pack/plugin/searchable-snapshots/src/test/java/org/elasticsearch/index/store/SearchableSnapshotDirectoryStatsTests.java b/x-pack/plugin/searchable-snapshots/src/test/java/org/elasticsearch/index/store/SearchableSnapshotDirectoryStatsTests.java index fbed51040bba5..fb757ecbc38a3 100644 --- a/x-pack/plugin/searchable-snapshots/src/test/java/org/elasticsearch/index/store/SearchableSnapshotDirectoryStatsTests.java +++ b/x-pack/plugin/searchable-snapshots/src/test/java/org/elasticsearch/index/store/SearchableSnapshotDirectoryStatsTests.java @@ -36,7 +36,7 @@ import org.elasticsearch.snapshots.Snapshot; import org.elasticsearch.snapshots.SnapshotId; import org.elasticsearch.xpack.searchablesnapshots.AbstractSearchableSnapshotsTestCase; -import org.elasticsearch.xpack.searchablesnapshots.SearchableSnapshots; +import org.elasticsearch.xpack.searchablesnapshots.SearchableSnapshotsConstants; import org.elasticsearch.xpack.searchablesnapshots.cache.CacheService; import org.elasticsearch.xpack.searchablesnapshots.cache.FrozenCacheService; @@ -544,7 +544,7 @@ private void executeTestCase(final TriConsumer