Skip to content

Commit eb675a1

Browse files
authored
Introduce index store plugins (#32375)
Today we allow plugins to add index store implementations yet we are not doing this in our new way of managing plugins as pull versus push. That is, today we still allow plugins to push index store providers via an on index module call where they can turn around and add an index store. Aside from being inconsistent with how we manage plugins today where we would look to pull such implementations from plugins at node creation time, it also means that we do not know at a top-level (for example, in the indices service) which index stores are available. This commit addresses this by adding a dedicated plugin type for index store plugins, removing the index module hook for adding index stores, and by aggregating these into the top-level of the indices service.
1 parent bec888f commit eb675a1

File tree

9 files changed

+202
-70
lines changed

9 files changed

+202
-70
lines changed

plugins/store-smb/src/main/java/org/elasticsearch/plugin/store/smb/SMBStorePlugin.java

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,16 +19,26 @@
1919

2020
package org.elasticsearch.plugin.store.smb;
2121

22-
import org.elasticsearch.index.IndexModule;
22+
import org.elasticsearch.index.IndexSettings;
23+
import org.elasticsearch.index.store.IndexStore;
2324
import org.elasticsearch.index.store.smbmmapfs.SmbMmapFsIndexStore;
2425
import org.elasticsearch.index.store.smbsimplefs.SmbSimpleFsIndexStore;
26+
import org.elasticsearch.plugins.IndexStorePlugin;
2527
import org.elasticsearch.plugins.Plugin;
2628

27-
public class SMBStorePlugin extends Plugin {
29+
import java.util.Collections;
30+
import java.util.HashMap;
31+
import java.util.Map;
32+
import java.util.function.Function;
33+
34+
public class SMBStorePlugin extends Plugin implements IndexStorePlugin {
2835

2936
@Override
30-
public void onIndexModule(IndexModule indexModule) {
31-
indexModule.addIndexStore("smb_mmap_fs", SmbMmapFsIndexStore::new);
32-
indexModule.addIndexStore("smb_simple_fs", SmbSimpleFsIndexStore::new);
37+
public Map<String, Function<IndexSettings, IndexStore>> getIndexStoreFactories() {
38+
final Map<String, Function<IndexSettings, IndexStore>> indexStoreFactories = new HashMap<>(2);
39+
indexStoreFactories.put("smb_mmap_fs", SmbMmapFsIndexStore::new);
40+
indexStoreFactories.put("smb_simple_fs", SmbSimpleFsIndexStore::new);
41+
return Collections.unmodifiableMap(indexStoreFactories);
3342
}
43+
3444
}

server/src/main/java/org/elasticsearch/index/IndexModule.java

Lines changed: 14 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@
4949
import org.elasticsearch.indices.breaker.CircuitBreakerService;
5050
import org.elasticsearch.indices.fielddata.cache.IndicesFieldDataCache;
5151
import org.elasticsearch.indices.mapper.MapperRegistry;
52+
import org.elasticsearch.plugins.IndexStorePlugin;
5253
import org.elasticsearch.script.ScriptService;
5354
import org.elasticsearch.threadpool.ThreadPool;
5455

@@ -74,7 +75,7 @@
7475
* {@link #addSimilarity(String, TriFunction)} while existing Providers can be referenced through Settings under the
7576
* {@link IndexModule#SIMILARITY_SETTINGS_PREFIX} prefix along with the "type" value. For example, to reference the
7677
* {@link BM25Similarity}, the configuration {@code "index.similarity.my_similarity.type : "BM25"} can be used.</li>
77-
* <li>{@link IndexStore} - Custom {@link IndexStore} instances can be registered via {@link #addIndexStore(String, Function)}</li>
78+
* <li>{@link IndexStore} - Custom {@link IndexStore} instances can be registered via {@link IndexStorePlugin}</li>
7879
* <li>{@link IndexEventListener} - Custom {@link IndexEventListener} instances can be registered via
7980
* {@link #addIndexEventListener(IndexEventListener)}</li>
8081
* <li>Settings update listener - Custom settings update listener can be registered via
@@ -109,7 +110,7 @@ public final class IndexModule {
109110
private SetOnce<IndexSearcherWrapperFactory> indexSearcherWrapper = new SetOnce<>();
110111
private final Set<IndexEventListener> indexEventListeners = new HashSet<>();
111112
private final Map<String, TriFunction<Settings, Version, ScriptService, Similarity>> similarities = new HashMap<>();
112-
private final Map<String, Function<IndexSettings, IndexStore>> storeTypes = new HashMap<>();
113+
private final Map<String, Function<IndexSettings, IndexStore>> indexStoreFactories;
113114
private final SetOnce<BiFunction<IndexSettings, IndicesQueryCache, QueryCache>> forceQueryCacheProvider = new SetOnce<>();
114115
private final List<SearchOperationListener> searchOperationListeners = new ArrayList<>();
115116
private final List<IndexingOperationListener> indexOperationListeners = new ArrayList<>();
@@ -119,16 +120,22 @@ public final class IndexModule {
119120
* Construct the index module for the index with the specified index settings. The index module contains extension points for plugins
120121
* via {@link org.elasticsearch.plugins.PluginsService#onIndexModule(IndexModule)}.
121122
*
122-
* @param indexSettings the index settings
123-
* @param analysisRegistry the analysis registry
124-
* @param engineFactory the engine factory
123+
* @param indexSettings the index settings
124+
* @param analysisRegistry the analysis registry
125+
* @param engineFactory the engine factory
126+
* @param indexStoreFactories the available store types
125127
*/
126-
public IndexModule(final IndexSettings indexSettings, final AnalysisRegistry analysisRegistry, final EngineFactory engineFactory) {
128+
public IndexModule(
129+
final IndexSettings indexSettings,
130+
final AnalysisRegistry analysisRegistry,
131+
final EngineFactory engineFactory,
132+
final Map<String, Function<IndexSettings, IndexStore>> indexStoreFactories) {
127133
this.indexSettings = indexSettings;
128134
this.analysisRegistry = analysisRegistry;
129135
this.engineFactory = Objects.requireNonNull(engineFactory);
130136
this.searchOperationListeners.add(new SearchSlowLog(indexSettings));
131137
this.indexOperationListeners.add(new IndexingSlowLog(indexSettings));
138+
this.indexStoreFactories = Collections.unmodifiableMap(indexStoreFactories);
132139
}
133140

134141
/**
@@ -245,25 +252,6 @@ public void addIndexOperationListener(IndexingOperationListener listener) {
245252
this.indexOperationListeners.add(listener);
246253
}
247254

248-
/**
249-
* Adds an {@link IndexStore} type to this index module. Typically stores are registered with a reference to
250-
* it's constructor:
251-
* <pre>
252-
* indexModule.addIndexStore("my_store_type", MyStore::new);
253-
* </pre>
254-
*
255-
* @param type the type to register
256-
* @param provider the instance provider / factory method
257-
*/
258-
public void addIndexStore(String type, Function<IndexSettings, IndexStore> provider) {
259-
ensureNotFrozen();
260-
if (storeTypes.containsKey(type)) {
261-
throw new IllegalArgumentException("key [" + type +"] already registered");
262-
}
263-
storeTypes.put(type, provider);
264-
}
265-
266-
267255
/**
268256
* Registers the given {@link Similarity} with the given name.
269257
* The function takes as parameters:<ul>
@@ -360,7 +348,7 @@ public IndexService newIndexService(
360348
if (Strings.isEmpty(storeType) || isBuiltinType(storeType)) {
361349
store = new IndexStore(indexSettings);
362350
} else {
363-
Function<IndexSettings, IndexStore> factory = storeTypes.get(storeType);
351+
Function<IndexSettings, IndexStore> factory = indexStoreFactories.get(storeType);
364352
if (factory == null) {
365353
throw new IllegalArgumentException("Unknown store type [" + storeType + "]");
366354
}

server/src/main/java/org/elasticsearch/indices/IndicesService.java

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,7 @@
100100
import org.elasticsearch.index.shard.IndexingOperationListener;
101101
import org.elasticsearch.index.shard.IndexingStats;
102102
import org.elasticsearch.index.shard.ShardId;
103+
import org.elasticsearch.index.store.IndexStore;
103104
import org.elasticsearch.indices.breaker.CircuitBreakerService;
104105
import org.elasticsearch.indices.cluster.IndicesClusterStateService;
105106
import org.elasticsearch.indices.fielddata.cache.IndicesFieldDataCache;
@@ -181,6 +182,7 @@ public class IndicesService extends AbstractLifecycleComponent
181182
private final IndicesQueryCache indicesQueryCache;
182183
private final MetaStateService metaStateService;
183184
private final Collection<Function<IndexSettings, Optional<EngineFactory>>> engineFactoryProviders;
185+
private final Map<String, Function<IndexSettings, IndexStore>> indexStoreFactories;
184186

185187
@Override
186188
protected void doStart() {
@@ -193,7 +195,8 @@ public IndicesService(Settings settings, PluginsService pluginsService, NodeEnvi
193195
MapperRegistry mapperRegistry, NamedWriteableRegistry namedWriteableRegistry, ThreadPool threadPool,
194196
IndexScopedSettings indexScopedSettings, CircuitBreakerService circuitBreakerService, BigArrays bigArrays,
195197
ScriptService scriptService, Client client, MetaStateService metaStateService,
196-
Collection<Function<IndexSettings, Optional<EngineFactory>>> engineFactoryProviders) {
198+
Collection<Function<IndexSettings, Optional<EngineFactory>>> engineFactoryProviders,
199+
Map<String, Function<IndexSettings, IndexStore>> indexStoreFactories) {
197200
super(settings);
198201
this.threadPool = threadPool;
199202
this.pluginsService = pluginsService;
@@ -225,6 +228,7 @@ public void onRemoval(ShardId shardId, String fieldName, boolean wasEvicted, lon
225228
this.cacheCleaner = new CacheCleaner(indicesFieldDataCache, indicesRequestCache, logger, threadPool, this.cleanInterval);
226229
this.metaStateService = metaStateService;
227230
this.engineFactoryProviders = engineFactoryProviders;
231+
this.indexStoreFactories = indexStoreFactories;
228232
}
229233

230234
@Override
@@ -464,7 +468,7 @@ private synchronized IndexService createIndexService(final String reason,
464468
idxSettings.getNumberOfReplicas(),
465469
reason);
466470

467-
final IndexModule indexModule = new IndexModule(idxSettings, analysisRegistry, getEngineFactory(idxSettings));
471+
final IndexModule indexModule = new IndexModule(idxSettings, analysisRegistry, getEngineFactory(idxSettings), indexStoreFactories);
468472
for (IndexingOperationListener operationListener : indexingOperationListeners) {
469473
indexModule.addIndexOperationListener(operationListener);
470474
}
@@ -524,7 +528,7 @@ private EngineFactory getEngineFactory(final IndexSettings idxSettings) {
524528
*/
525529
public synchronized MapperService createIndexMapperService(IndexMetaData indexMetaData) throws IOException {
526530
final IndexSettings idxSettings = new IndexSettings(indexMetaData, this.settings, indexScopedSettings);
527-
final IndexModule indexModule = new IndexModule(idxSettings, analysisRegistry, getEngineFactory(idxSettings));
531+
final IndexModule indexModule = new IndexModule(idxSettings, analysisRegistry, getEngineFactory(idxSettings), indexStoreFactories);
528532
pluginsService.onIndexModule(indexModule);
529533
return indexModule.newIndexMapperService(xContentRegistry, mapperRegistry, scriptService);
530534
}

server/src/main/java/org/elasticsearch/node/Node.java

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,8 @@
2626
import org.elasticsearch.ElasticsearchException;
2727
import org.elasticsearch.ElasticsearchTimeoutException;
2828
import org.elasticsearch.Version;
29-
import org.elasticsearch.action.ActionModule;
3029
import org.elasticsearch.action.Action;
30+
import org.elasticsearch.action.ActionModule;
3131
import org.elasticsearch.action.search.SearchExecutionStatsCollector;
3232
import org.elasticsearch.action.search.SearchPhaseController;
3333
import org.elasticsearch.action.search.SearchTransportService;
@@ -94,6 +94,7 @@
9494
import org.elasticsearch.index.IndexSettings;
9595
import org.elasticsearch.index.analysis.AnalysisRegistry;
9696
import org.elasticsearch.index.engine.EngineFactory;
97+
import org.elasticsearch.index.store.IndexStore;
9798
import org.elasticsearch.indices.IndicesModule;
9899
import org.elasticsearch.indices.IndicesService;
99100
import org.elasticsearch.indices.analysis.AnalysisModule;
@@ -117,6 +118,7 @@
117118
import org.elasticsearch.plugins.ClusterPlugin;
118119
import org.elasticsearch.plugins.DiscoveryPlugin;
119120
import org.elasticsearch.plugins.EnginePlugin;
121+
import org.elasticsearch.plugins.IndexStorePlugin;
120122
import org.elasticsearch.plugins.IngestPlugin;
121123
import org.elasticsearch.plugins.MapperPlugin;
122124
import org.elasticsearch.plugins.MetaDataUpgrader;
@@ -407,11 +409,19 @@ protected Node(final Environment environment, Collection<Class<? extends Plugin>
407409
enginePlugins.stream().map(plugin -> plugin::getEngineFactory))
408410
.collect(Collectors.toList());
409411

412+
413+
final Map<String, Function<IndexSettings, IndexStore>> indexStoreFactories =
414+
pluginsService.filterPlugins(IndexStorePlugin.class)
415+
.stream()
416+
.map(IndexStorePlugin::getIndexStoreFactories)
417+
.flatMap(m -> m.entrySet().stream())
418+
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
419+
410420
final IndicesService indicesService =
411421
new IndicesService(settings, pluginsService, nodeEnvironment, xContentRegistry, analysisModule.getAnalysisRegistry(),
412422
clusterModule.getIndexNameExpressionResolver(), indicesModule.getMapperRegistry(), namedWriteableRegistry,
413423
threadPool, settingsModule.getIndexScopedSettings(), circuitBreakerService, bigArrays,
414-
scriptModule.getScriptService(), client, metaStateService, engineFactoryProviders);
424+
scriptModule.getScriptService(), client, metaStateService, engineFactoryProviders, indexStoreFactories);
415425

416426

417427
Collection<Object> pluginComponents = pluginsService.filterPlugins(Plugin.class).stream()
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
/*
2+
* Licensed to Elasticsearch under one or more contributor
3+
* license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright
5+
* ownership. Elasticsearch licenses this file to you under
6+
* the Apache License, Version 2.0 (the "License"); you may
7+
* not use this file except in compliance with the License.
8+
* You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
20+
package org.elasticsearch.plugins;
21+
22+
import org.elasticsearch.index.IndexSettings;
23+
import org.elasticsearch.index.store.IndexStore;
24+
25+
import java.util.Map;
26+
import java.util.function.Function;
27+
28+
/**
29+
* A plugin that provides alternative index store implementations.
30+
*/
31+
public interface IndexStorePlugin {
32+
33+
/**
34+
* The index store factories for this plugin. When an index is created the store type setting
35+
* {@link org.elasticsearch.index.IndexModule#INDEX_STORE_TYPE_SETTING} on the index will be examined and either use the default or a
36+
* built-in type, or looked up among all the index store factories from {@link IndexStore} plugins.
37+
*
38+
* @return a map from store type to an index store factory
39+
*/
40+
Map<String, Function<IndexSettings, IndexStore>> getIndexStoreFactories();
41+
42+
}

0 commit comments

Comments
 (0)