Skip to content

Commit f8edeee

Browse files
authored
Introduce feature flag for searchable snapshots (#54424)
This commit adds the `es.searchable_snapshots_feature_enabled` system property to allow the searchable snapshots feature to be wholly enabled/disabled at runtime even if the plugin is installed. It defaults to `true` in snapshot builds and `false` in release builds.
1 parent ff0eda5 commit f8edeee

File tree

4 files changed

+87
-34
lines changed

4 files changed

+87
-34
lines changed

docs/build.gradle

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ testClusters.integTest {
5454
if (BuildParams.isSnapshotBuild() == false) {
5555
systemProperty 'es.autoscaling_feature_flag_registered', 'true'
5656
systemProperty 'es.eql_feature_flag_registered', 'true'
57+
systemProperty 'es.searchable_snapshots_feature_enabled', 'true'
5758
}
5859
setting 'xpack.autoscaling.enabled', 'true'
5960
setting 'xpack.eql.enabled', 'true'

x-pack/plugin/searchable-snapshots/qa/rest/build.gradle

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import org.elasticsearch.gradle.info.BuildParams
2+
13
apply plugin: 'elasticsearch.testclusters'
24
apply plugin: 'elasticsearch.standalone-rest-test'
35
apply plugin: 'elasticsearch.rest-test'
@@ -14,6 +16,9 @@ integTest.runner {
1416

1517
testClusters.integTest {
1618
testDistribution = 'DEFAULT'
19+
if (BuildParams.isSnapshotBuild() == false) {
20+
systemProperty 'es.searchable_snapshots_feature_enabled', 'true'
21+
}
1722
setting 'path.repo', repoDir.absolutePath
1823
}
1924

x-pack/plugin/searchable-snapshots/qa/s3/build.gradle

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import static org.elasticsearch.gradle.PropertyNormalization.IGNORE_VALUE
2+
import org.elasticsearch.gradle.info.BuildParams
23

34
apply plugin: 'elasticsearch.standalone-rest-test'
45
apply plugin: 'elasticsearch.rest-test'
@@ -52,6 +53,10 @@ testClusters.integTest {
5253
testDistribution = 'DEFAULT'
5354
plugin file(repositoryPlugin.bundlePlugin.archiveFile)
5455

56+
if (BuildParams.isSnapshotBuild() == false) {
57+
systemProperty 'es.searchable_snapshots_feature_enabled', 'true'
58+
}
59+
5560
keystore 's3.client.searchable_snapshots.access_key', s3AccessKey
5661
keystore 's3.client.searchable_snapshots.secret_key', s3SecretKey
5762

x-pack/plugin/searchable-snapshots/src/main/java/org/elasticsearch/xpack/searchablesnapshots/SearchableSnapshots.java

Lines changed: 76 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
package org.elasticsearch.xpack.searchablesnapshots;
77

88
import org.apache.lucene.util.SetOnce;
9+
import org.elasticsearch.Build;
910
import org.elasticsearch.action.ActionRequest;
1011
import org.elasticsearch.action.ActionResponse;
1112
import org.elasticsearch.client.Client;
@@ -69,6 +70,23 @@
6970
*/
7071
public class SearchableSnapshots extends Plugin implements IndexStorePlugin, RepositoryPlugin, EnginePlugin, ActionPlugin, ClusterPlugin {
7172

73+
private static final boolean SEARCHABLE_SNAPSHOTS_FEATURE_ENABLED;
74+
75+
static {
76+
final String property = System.getProperty("es.searchable_snapshots_feature_enabled");
77+
if ("true".equals(property)) {
78+
SEARCHABLE_SNAPSHOTS_FEATURE_ENABLED = true;
79+
} else if ("false".equals(property)) {
80+
SEARCHABLE_SNAPSHOTS_FEATURE_ENABLED = false;
81+
} else if (property == null) {
82+
SEARCHABLE_SNAPSHOTS_FEATURE_ENABLED = Build.CURRENT.isSnapshot();
83+
} else {
84+
throw new IllegalArgumentException(
85+
"expected es.searchable_snapshots_feature_enabled to be unset or [true|false] but was [" + property + "]"
86+
);
87+
}
88+
}
89+
7290
public static final Setting<String> SNAPSHOT_REPOSITORY_SETTING =
7391
Setting.simpleString("index.store.snapshot.repository_name", Setting.Property.IndexScope, Setting.Property.PrivateIndex);
7492
public static final Setting<String> SNAPSHOT_SNAPSHOT_NAME_SETTING =
@@ -101,16 +119,20 @@ public SearchableSnapshots(final Settings settings) {
101119

102120
@Override
103121
public List<Setting<?>> getSettings() {
104-
return List.of(SNAPSHOT_REPOSITORY_SETTING,
105-
SNAPSHOT_SNAPSHOT_NAME_SETTING,
106-
SNAPSHOT_SNAPSHOT_ID_SETTING,
107-
SNAPSHOT_INDEX_ID_SETTING,
108-
SNAPSHOT_CACHE_ENABLED_SETTING,
109-
SNAPSHOT_CACHE_EXCLUDED_FILE_TYPES_SETTING,
110-
SNAPSHOT_UNCACHED_CHUNK_SIZE_SETTING,
111-
CacheService.SNAPSHOT_CACHE_SIZE_SETTING,
112-
CacheService.SNAPSHOT_CACHE_RANGE_SIZE_SETTING
113-
);
122+
if (SEARCHABLE_SNAPSHOTS_FEATURE_ENABLED) {
123+
return List.of(SNAPSHOT_REPOSITORY_SETTING,
124+
SNAPSHOT_SNAPSHOT_NAME_SETTING,
125+
SNAPSHOT_SNAPSHOT_ID_SETTING,
126+
SNAPSHOT_INDEX_ID_SETTING,
127+
SNAPSHOT_CACHE_ENABLED_SETTING,
128+
SNAPSHOT_CACHE_EXCLUDED_FILE_TYPES_SETTING,
129+
SNAPSHOT_UNCACHED_CHUNK_SIZE_SETTING,
130+
CacheService.SNAPSHOT_CACHE_SIZE_SETTING,
131+
CacheService.SNAPSHOT_CACHE_RANGE_SIZE_SETTING
132+
);
133+
} else {
134+
return List.of();
135+
}
114136
}
115137

116138
@Override
@@ -125,10 +147,13 @@ public Collection<Object> createComponents(
125147
final NodeEnvironment nodeEnvironment,
126148
final NamedWriteableRegistry registry,
127149
final IndexNameExpressionResolver resolver) {
128-
129-
final CacheService cacheService = new CacheService(settings);
130-
this.cacheService.set(cacheService);
131-
return List.of(cacheService);
150+
if (SEARCHABLE_SNAPSHOTS_FEATURE_ENABLED) {
151+
final CacheService cacheService = new CacheService(settings);
152+
this.cacheService.set(cacheService);
153+
return List.of(cacheService);
154+
} else {
155+
return List.of();
156+
}
132157
}
133158

134159
@Override
@@ -139,25 +164,30 @@ public void onRepositoriesModule(RepositoriesModule repositoriesModule) {
139164

140165
@Override
141166
public void onIndexModule(IndexModule indexModule) {
142-
if (isSearchableSnapshotStore(indexModule.getSettings())) {
167+
if (SEARCHABLE_SNAPSHOTS_FEATURE_ENABLED && isSearchableSnapshotStore(indexModule.getSettings())) {
143168
indexModule.addIndexEventListener(new SearchableSnapshotIndexEventListener());
144169
}
145170
}
146171

147172
@Override
148173
public Map<String, DirectoryFactory> getDirectoryFactories() {
149-
return Map.of(SNAPSHOT_DIRECTORY_FACTORY_KEY, (indexSettings, shardPath) -> {
150-
final RepositoriesService repositories = repositoriesService.get();
151-
assert repositories != null;
152-
final CacheService cache = cacheService.get();
153-
assert cache != null;
154-
return SearchableSnapshotDirectory.create(repositories, cache, indexSettings, shardPath, System::nanoTime);
155-
});
174+
if (SEARCHABLE_SNAPSHOTS_FEATURE_ENABLED) {
175+
return Map.of(SNAPSHOT_DIRECTORY_FACTORY_KEY, (indexSettings, shardPath) -> {
176+
final RepositoriesService repositories = repositoriesService.get();
177+
assert repositories != null;
178+
final CacheService cache = cacheService.get();
179+
assert cache != null;
180+
return SearchableSnapshotDirectory.create(repositories, cache, indexSettings, shardPath, System::nanoTime);
181+
});
182+
} else {
183+
return Map.of();
184+
}
156185
}
157186

158187
@Override
159188
public Optional<EngineFactory> getEngineFactory(IndexSettings indexSettings) {
160-
if (isSearchableSnapshotStore(indexSettings.getSettings())
189+
if (SEARCHABLE_SNAPSHOTS_FEATURE_ENABLED
190+
&& isSearchableSnapshotStore(indexSettings.getSettings())
161191
&& indexSettings.getSettings().getAsBoolean("index.frozen", false) == false) {
162192
return Optional.of(engineConfig -> new ReadOnlyEngine(engineConfig, null, new TranslogStats(), false, Function.identity()));
163193
}
@@ -166,27 +196,39 @@ public Optional<EngineFactory> getEngineFactory(IndexSettings indexSettings) {
166196

167197
@Override
168198
public List<ActionHandler<? extends ActionRequest, ? extends ActionResponse>> getActions() {
169-
return List.of(
170-
new ActionHandler<>(SearchableSnapshotsStatsAction.INSTANCE, TransportSearchableSnapshotsStatsAction.class),
171-
new ActionHandler<>(ClearSearchableSnapshotsCacheAction.INSTANCE, TransportClearSearchableSnapshotsCacheAction.class),
172-
new ActionHandler<>(MountSearchableSnapshotAction.INSTANCE, TransportMountSearchableSnapshotAction.class)
173-
);
199+
if (SEARCHABLE_SNAPSHOTS_FEATURE_ENABLED) {
200+
return List.of(
201+
new ActionHandler<>(SearchableSnapshotsStatsAction.INSTANCE, TransportSearchableSnapshotsStatsAction.class),
202+
new ActionHandler<>(ClearSearchableSnapshotsCacheAction.INSTANCE, TransportClearSearchableSnapshotsCacheAction.class),
203+
new ActionHandler<>(MountSearchableSnapshotAction.INSTANCE, TransportMountSearchableSnapshotAction.class)
204+
);
205+
} else {
206+
return List.of();
207+
}
174208
}
175209

176210
public List<RestHandler> getRestHandlers(Settings settings, RestController restController, ClusterSettings clusterSettings,
177211
IndexScopedSettings indexScopedSettings, SettingsFilter settingsFilter,
178212
IndexNameExpressionResolver indexNameExpressionResolver,
179213
Supplier<DiscoveryNodes> nodesInCluster) {
180-
return List.of(
181-
new RestSearchableSnapshotsStatsAction(),
182-
new RestClearSearchableSnapshotsCacheAction(),
183-
new RestMountSearchableSnapshotAction()
184-
);
214+
if (SEARCHABLE_SNAPSHOTS_FEATURE_ENABLED) {
215+
return List.of(
216+
new RestSearchableSnapshotsStatsAction(),
217+
new RestClearSearchableSnapshotsCacheAction(),
218+
new RestMountSearchableSnapshotAction()
219+
);
220+
} else {
221+
return List.of();
222+
}
185223
}
186224

187225
@Override
188226
public Map<String, ExistingShardsAllocator> getExistingShardsAllocators() {
189-
return Collections.singletonMap(SearchableSnapshotAllocator.ALLOCATOR_NAME, new SearchableSnapshotAllocator());
227+
if (SEARCHABLE_SNAPSHOTS_FEATURE_ENABLED) {
228+
return Collections.singletonMap(SearchableSnapshotAllocator.ALLOCATOR_NAME, new SearchableSnapshotAllocator());
229+
} else {
230+
return Collections.emptyMap();
231+
}
190232
}
191233

192234
static boolean isSearchableSnapshotStore(Settings indexSettings) {

0 commit comments

Comments
 (0)