diff --git a/docs/reference/migration/migrate_7_3.asciidoc b/docs/reference/migration/migrate_7_3.asciidoc new file mode 100644 index 00000000000..5a0b5539ba2 --- /dev/null +++ b/docs/reference/migration/migrate_7_3.asciidoc @@ -0,0 +1,28 @@ +[[breaking-changes-7.3]] +== Breaking changes in 7.3 +++++ +7.3 +++++ + +This section discusses the changes that you need to be aware of when migrating +your application to Elasticsearch 7.3. + +See also <> and <>. + +coming[7.3.0] + +//NOTE: The notable-breaking-changes tagged regions are re-used in the +//Installation and Upgrade Guide + +//tag::notable-breaking-changes[] + +// end::notable-breaking-changes[] + +[[breaking_73_plugin_changes]] +=== Plugins changes + +[float] +==== IndexStorePlugin changes + +IndexStore and DirectoryService have been replaced by a stateless and simple +DirectoryFactory interface to create custom Lucene directory instances per shard. \ No newline at end of file diff --git a/plugins/store-smb/src/main/java/org/elasticsearch/index/store/smbmmapfs/SmbMmapFsDirectoryService.java b/plugins/store-smb/src/main/java/org/elasticsearch/index/store/smbmmapfs/SmbMmapFsDirectoryFactory.java similarity index 74% rename from plugins/store-smb/src/main/java/org/elasticsearch/index/store/smbmmapfs/SmbMmapFsDirectoryService.java rename to plugins/store-smb/src/main/java/org/elasticsearch/index/store/smbmmapfs/SmbMmapFsDirectoryFactory.java index 1264464cf00..13b6f9401ab 100644 --- a/plugins/store-smb/src/main/java/org/elasticsearch/index/store/smbmmapfs/SmbMmapFsDirectoryService.java +++ b/plugins/store-smb/src/main/java/org/elasticsearch/index/store/smbmmapfs/SmbMmapFsDirectoryFactory.java @@ -23,22 +23,16 @@ import org.apache.lucene.store.Directory; import org.apache.lucene.store.LockFactory; import org.apache.lucene.store.MMapDirectory; import org.elasticsearch.index.IndexSettings; -import org.elasticsearch.index.shard.ShardPath; -import org.elasticsearch.index.store.FsDirectoryService; +import org.elasticsearch.index.store.FsDirectoryFactory; import org.elasticsearch.index.store.SmbDirectoryWrapper; import java.io.IOException; import java.nio.file.Path; -public class SmbMmapFsDirectoryService extends FsDirectoryService { - - public SmbMmapFsDirectoryService(IndexSettings indexSettings, ShardPath path) { - super(indexSettings, path); - } +public final class SmbMmapFsDirectoryFactory extends FsDirectoryFactory { @Override - protected Directory newFSDirectory(Path location, LockFactory lockFactory) throws IOException { - logger.debug("wrapping MMapDirectory for SMB"); - return new SmbDirectoryWrapper(new MMapDirectory(location, indexSettings.getValue(INDEX_LOCK_FACTOR_SETTING))); + protected Directory newFSDirectory(Path location, LockFactory lockFactory, IndexSettings indexSettings) throws IOException { + return new SmbDirectoryWrapper(new MMapDirectory(location, lockFactory)); } } diff --git a/plugins/store-smb/src/main/java/org/elasticsearch/index/store/smbmmapfs/SmbMmapFsIndexStore.java b/plugins/store-smb/src/main/java/org/elasticsearch/index/store/smbmmapfs/SmbMmapFsIndexStore.java deleted file mode 100644 index 03993489663..00000000000 --- a/plugins/store-smb/src/main/java/org/elasticsearch/index/store/smbmmapfs/SmbMmapFsIndexStore.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * 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. - */ - -package org.elasticsearch.index.store.smbmmapfs; - -import org.elasticsearch.index.IndexSettings; -import org.elasticsearch.index.shard.ShardPath; -import org.elasticsearch.index.store.DirectoryService; -import org.elasticsearch.index.store.IndexStore; - -public class SmbMmapFsIndexStore extends IndexStore { - - public SmbMmapFsIndexStore(IndexSettings indexSettings) { - super(indexSettings); - } - - @Override - public DirectoryService newDirectoryService(ShardPath path) { - return new SmbMmapFsDirectoryService(indexSettings, path); - } -} diff --git a/plugins/store-smb/src/main/java/org/elasticsearch/index/store/smbsimplefs/SmbSimpleFsDirectoryService.java b/plugins/store-smb/src/main/java/org/elasticsearch/index/store/smbsimplefs/SmbSimpleFsDirectoryFactory.java similarity index 76% rename from plugins/store-smb/src/main/java/org/elasticsearch/index/store/smbsimplefs/SmbSimpleFsDirectoryService.java rename to plugins/store-smb/src/main/java/org/elasticsearch/index/store/smbsimplefs/SmbSimpleFsDirectoryFactory.java index 87e45a02cf6..e5e9025f82d 100644 --- a/plugins/store-smb/src/main/java/org/elasticsearch/index/store/smbsimplefs/SmbSimpleFsDirectoryService.java +++ b/plugins/store-smb/src/main/java/org/elasticsearch/index/store/smbsimplefs/SmbSimpleFsDirectoryFactory.java @@ -23,22 +23,16 @@ import org.apache.lucene.store.Directory; import org.apache.lucene.store.LockFactory; import org.apache.lucene.store.SimpleFSDirectory; import org.elasticsearch.index.IndexSettings; -import org.elasticsearch.index.shard.ShardPath; -import org.elasticsearch.index.store.FsDirectoryService; +import org.elasticsearch.index.store.FsDirectoryFactory; import org.elasticsearch.index.store.SmbDirectoryWrapper; import java.io.IOException; import java.nio.file.Path; -public class SmbSimpleFsDirectoryService extends FsDirectoryService { - - public SmbSimpleFsDirectoryService(IndexSettings indexSettings, ShardPath path) { - super(indexSettings, path); - } +public final class SmbSimpleFsDirectoryFactory extends FsDirectoryFactory { @Override - protected Directory newFSDirectory(Path location, LockFactory lockFactory) throws IOException { - logger.debug("wrapping SimpleFSDirectory for SMB"); + protected Directory newFSDirectory(Path location, LockFactory lockFactory, IndexSettings indexSettings) throws IOException { return new SmbDirectoryWrapper(new SimpleFSDirectory(location, lockFactory)); } } diff --git a/plugins/store-smb/src/main/java/org/elasticsearch/index/store/smbsimplefs/SmbSimpleFsIndexStore.java b/plugins/store-smb/src/main/java/org/elasticsearch/index/store/smbsimplefs/SmbSimpleFsIndexStore.java deleted file mode 100644 index 3b6b3c3c899..00000000000 --- a/plugins/store-smb/src/main/java/org/elasticsearch/index/store/smbsimplefs/SmbSimpleFsIndexStore.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * 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. - */ - -package org.elasticsearch.index.store.smbsimplefs; - -import org.elasticsearch.index.IndexSettings; -import org.elasticsearch.index.shard.ShardPath; -import org.elasticsearch.index.store.DirectoryService; -import org.elasticsearch.index.store.IndexStore; - -public class SmbSimpleFsIndexStore extends IndexStore { - - public SmbSimpleFsIndexStore(IndexSettings indexSettings) { - super(indexSettings); - } - - @Override - public DirectoryService newDirectoryService(ShardPath path) { - return new SmbSimpleFsDirectoryService(indexSettings, path); - } -} - diff --git a/plugins/store-smb/src/main/java/org/elasticsearch/plugin/store/smb/SMBStorePlugin.java b/plugins/store-smb/src/main/java/org/elasticsearch/plugin/store/smb/SMBStorePlugin.java index a2b0f463452..622aa64f841 100644 --- a/plugins/store-smb/src/main/java/org/elasticsearch/plugin/store/smb/SMBStorePlugin.java +++ b/plugins/store-smb/src/main/java/org/elasticsearch/plugin/store/smb/SMBStorePlugin.java @@ -19,25 +19,22 @@ package org.elasticsearch.plugin.store.smb; -import org.elasticsearch.index.IndexSettings; -import org.elasticsearch.index.store.IndexStore; -import org.elasticsearch.index.store.smbmmapfs.SmbMmapFsIndexStore; -import org.elasticsearch.index.store.smbsimplefs.SmbSimpleFsIndexStore; +import org.elasticsearch.index.store.smbmmapfs.SmbMmapFsDirectoryFactory; +import org.elasticsearch.index.store.smbsimplefs.SmbSimpleFsDirectoryFactory; import org.elasticsearch.plugins.IndexStorePlugin; import org.elasticsearch.plugins.Plugin; import java.util.Collections; import java.util.HashMap; import java.util.Map; -import java.util.function.Function; public class SMBStorePlugin extends Plugin implements IndexStorePlugin { @Override - public Map> getIndexStoreFactories() { - final Map> indexStoreFactories = new HashMap<>(2); - indexStoreFactories.put("smb_mmap_fs", SmbMmapFsIndexStore::new); - indexStoreFactories.put("smb_simple_fs", SmbSimpleFsIndexStore::new); + public Map getDirectoryFactories() { + final Map indexStoreFactories = new HashMap<>(2); + indexStoreFactories.put("smb_mmap_fs", new SmbMmapFsDirectoryFactory()); + indexStoreFactories.put("smb_simple_fs", new SmbSimpleFsDirectoryFactory()); return Collections.unmodifiableMap(indexStoreFactories); } diff --git a/server/src/main/java/org/elasticsearch/common/settings/IndexScopedSettings.java b/server/src/main/java/org/elasticsearch/common/settings/IndexScopedSettings.java index cb3dfa8e598..fa3f6df7844 100644 --- a/server/src/main/java/org/elasticsearch/common/settings/IndexScopedSettings.java +++ b/server/src/main/java/org/elasticsearch/common/settings/IndexScopedSettings.java @@ -38,7 +38,7 @@ import org.elasticsearch.index.fielddata.IndexFieldDataService; import org.elasticsearch.index.mapper.FieldMapper; import org.elasticsearch.index.mapper.MapperService; import org.elasticsearch.index.similarity.SimilarityService; -import org.elasticsearch.index.store.FsDirectoryService; +import org.elasticsearch.index.store.FsDirectoryFactory; import org.elasticsearch.index.store.Store; import org.elasticsearch.indices.IndicesRequestCache; @@ -159,7 +159,7 @@ public final class IndexScopedSettings extends AbstractScopedSettings { IndexModule.INDEX_STORE_TYPE_SETTING, IndexModule.INDEX_STORE_PRE_LOAD_SETTING, IndexModule.INDEX_QUERY_CACHE_ENABLED_SETTING, - FsDirectoryService.INDEX_LOCK_FACTOR_SETTING, + FsDirectoryFactory.INDEX_LOCK_FACTOR_SETTING, Store.FORCE_RAM_TERM_DICT, EngineConfig.INDEX_CODEC_SETTING, EngineConfig.INDEX_OPTIMIZE_AUTO_GENERATED_IDS, diff --git a/server/src/main/java/org/elasticsearch/env/NodeEnvironment.java b/server/src/main/java/org/elasticsearch/env/NodeEnvironment.java index 2593687d55a..c149f262046 100644 --- a/server/src/main/java/org/elasticsearch/env/NodeEnvironment.java +++ b/server/src/main/java/org/elasticsearch/env/NodeEnvironment.java @@ -52,7 +52,7 @@ import org.elasticsearch.index.Index; import org.elasticsearch.index.IndexSettings; import org.elasticsearch.index.shard.ShardId; import org.elasticsearch.index.shard.ShardPath; -import org.elasticsearch.index.store.FsDirectoryService; +import org.elasticsearch.index.store.FsDirectoryFactory; import org.elasticsearch.monitor.fs.FsInfo; import org.elasticsearch.monitor.fs.FsProbe; import org.elasticsearch.monitor.jvm.JvmInfo; @@ -469,7 +469,7 @@ public final class NodeEnvironment implements Closeable { // resolve the directory the shard actually lives in Path p = shardPaths[i].resolve("index"); // open a directory (will be immediately closed) on the shard's location - dirs[i] = new SimpleFSDirectory(p, indexSettings.getValue(FsDirectoryService.INDEX_LOCK_FACTOR_SETTING)); + dirs[i] = new SimpleFSDirectory(p, indexSettings.getValue(FsDirectoryFactory.INDEX_LOCK_FACTOR_SETTING)); // create a lock for the "write.lock" file try { locks[i] = dirs[i].obtainLock(IndexWriter.WRITE_LOCK_NAME); diff --git a/server/src/main/java/org/elasticsearch/index/IndexModule.java b/server/src/main/java/org/elasticsearch/index/IndexModule.java index acec458b8b0..ca0f34803cc 100644 --- a/server/src/main/java/org/elasticsearch/index/IndexModule.java +++ b/server/src/main/java/org/elasticsearch/index/IndexModule.java @@ -45,7 +45,8 @@ import org.elasticsearch.index.shard.IndexSearcherWrapper; import org.elasticsearch.index.shard.IndexingOperationListener; import org.elasticsearch.index.shard.SearchOperationListener; import org.elasticsearch.index.similarity.SimilarityService; -import org.elasticsearch.index.store.IndexStore; +import org.elasticsearch.index.store.DirectoryService; +import org.elasticsearch.index.store.FsDirectoryFactory; import org.elasticsearch.indices.IndicesQueryCache; import org.elasticsearch.indices.breaker.CircuitBreakerService; import org.elasticsearch.indices.fielddata.cache.IndicesFieldDataCache; @@ -75,7 +76,7 @@ import java.util.function.Function; * {@link #addSimilarity(String, TriFunction)} while existing Providers can be referenced through Settings under the * {@link IndexModule#SIMILARITY_SETTINGS_PREFIX} prefix along with the "type" value. For example, to reference the * {@link BM25Similarity}, the configuration {@code "index.similarity.my_similarity.type : "BM25"} can be used. - *
  • {@link IndexStore} - Custom {@link IndexStore} instances can be registered via {@link IndexStorePlugin}
  • + *
  • {@link DirectoryService} - Custom {@link DirectoryService} instances can be registered via {@link IndexStorePlugin}
  • *
  • {@link IndexEventListener} - Custom {@link IndexEventListener} instances can be registered via * {@link #addIndexEventListener(IndexEventListener)}
  • *
  • Settings update listener - Custom settings update listener can be registered via @@ -86,6 +87,8 @@ public final class IndexModule { public static final Setting NODE_STORE_ALLOW_MMAP = Setting.boolSetting("node.store.allow_mmap", true, Property.NodeScope); + private static final FsDirectoryFactory DEFAULT_DIRECTORY_FACTORY = new FsDirectoryFactory(); + public static final Setting INDEX_STORE_TYPE_SETTING = new Setting<>("index.store.type", "", Function.identity(), Property.IndexScope, Property.NodeScope); @@ -112,7 +115,7 @@ public final class IndexModule { private SetOnce indexSearcherWrapper = new SetOnce<>(); private final Set indexEventListeners = new HashSet<>(); private final Map> similarities = new HashMap<>(); - private final Map> indexStoreFactories; + private final Map directoryFactories; private final SetOnce> forceQueryCacheProvider = new SetOnce<>(); private final List searchOperationListeners = new ArrayList<>(); private final List indexOperationListeners = new ArrayList<>(); @@ -125,19 +128,19 @@ public final class IndexModule { * @param indexSettings the index settings * @param analysisRegistry the analysis registry * @param engineFactory the engine factory - * @param indexStoreFactories the available store types + * @param directoryFactories the available store types */ public IndexModule( final IndexSettings indexSettings, final AnalysisRegistry analysisRegistry, final EngineFactory engineFactory, - final Map> indexStoreFactories) { + final Map directoryFactories) { this.indexSettings = indexSettings; this.analysisRegistry = analysisRegistry; this.engineFactory = Objects.requireNonNull(engineFactory); this.searchOperationListeners.add(new SearchSlowLog(indexSettings)); this.indexOperationListeners.add(new IndexingSlowLog(indexSettings)); - this.indexStoreFactories = Collections.unmodifiableMap(indexStoreFactories); + this.directoryFactories = Collections.unmodifiableMap(directoryFactories); } /** @@ -384,7 +387,7 @@ public final class IndexModule { IndexSearcherWrapperFactory searcherWrapperFactory = indexSearcherWrapper.get() == null ? (shard) -> null : indexSearcherWrapper.get(); eventListener.beforeIndexCreated(indexSettings.getIndex(), indexSettings.getSettings()); - final IndexStore store = getIndexStore(indexSettings, indexStoreFactories); + final IndexStorePlugin.DirectoryFactory directoryFactory = getDirectoryFactory(indexSettings, directoryFactories); final QueryCache queryCache; if (indexSettings.getValue(INDEX_QUERY_CACHE_ENABLED_SETTING)) { BiFunction queryCacheProvider = forceQueryCacheProvider.get(); @@ -399,12 +402,12 @@ public final class IndexModule { return new IndexService(indexSettings, indexCreationContext, environment, xContentRegistry, new SimilarityService(indexSettings, scriptService, similarities), shardStoreDeleter, analysisRegistry, engineFactory, circuitBreakerService, bigArrays, threadPool, scriptService, - client, queryCache, store, eventListener, searcherWrapperFactory, mapperRegistry, + client, queryCache, directoryFactory, eventListener, searcherWrapperFactory, mapperRegistry, indicesFieldDataCache, searchOperationListeners, indexOperationListeners, namedWriteableRegistry); } - private static IndexStore getIndexStore( - final IndexSettings indexSettings, final Map> indexStoreFactories) { + private static IndexStorePlugin.DirectoryFactory getDirectoryFactory( + final IndexSettings indexSettings, final Map indexStoreFactories) { final String storeType = indexSettings.getValue(INDEX_STORE_TYPE_SETTING); final Type type; final Boolean allowMmap = NODE_STORE_ALLOW_MMAP.get(indexSettings.getNodeSettings()); @@ -420,20 +423,16 @@ public final class IndexModule { if (allowMmap == false && (type == Type.MMAPFS || type == Type.HYBRIDFS)) { throw new IllegalArgumentException("store type [" + storeType + "] is not allowed because mmap is disabled"); } - final IndexStore store; + final IndexStorePlugin.DirectoryFactory factory; if (storeType.isEmpty() || isBuiltinType(storeType)) { - store = new IndexStore(indexSettings); + factory = DEFAULT_DIRECTORY_FACTORY; } else { - Function factory = indexStoreFactories.get(storeType); + factory = indexStoreFactories.get(storeType); if (factory == null) { throw new IllegalArgumentException("Unknown store type [" + storeType + "]"); } - store = factory.apply(indexSettings); - if (store == null) { - throw new IllegalStateException("store must not be null"); - } } - return store; + return factory; } /** diff --git a/server/src/main/java/org/elasticsearch/index/IndexService.java b/server/src/main/java/org/elasticsearch/index/IndexService.java index 1a49fd41873..d3e7d2df3ee 100644 --- a/server/src/main/java/org/elasticsearch/index/IndexService.java +++ b/server/src/main/java/org/elasticsearch/index/IndexService.java @@ -23,6 +23,7 @@ import org.apache.logging.log4j.message.ParameterizedMessage; import org.apache.lucene.index.IndexReader; import org.apache.lucene.search.Sort; import org.apache.lucene.store.AlreadyClosedException; +import org.apache.lucene.store.Directory; import org.apache.lucene.util.Accountable; import org.elasticsearch.Assertions; import org.elasticsearch.Version; @@ -65,14 +66,13 @@ import org.elasticsearch.index.shard.ShardId; import org.elasticsearch.index.shard.ShardNotFoundException; import org.elasticsearch.index.shard.ShardPath; import org.elasticsearch.index.similarity.SimilarityService; -import org.elasticsearch.index.store.DirectoryService; -import org.elasticsearch.index.store.IndexStore; import org.elasticsearch.index.store.Store; import org.elasticsearch.index.translog.Translog; import org.elasticsearch.indices.breaker.CircuitBreakerService; import org.elasticsearch.indices.cluster.IndicesClusterStateService; import org.elasticsearch.indices.fielddata.cache.IndicesFieldDataCache; import org.elasticsearch.indices.mapper.MapperRegistry; +import org.elasticsearch.plugins.IndexStorePlugin; import org.elasticsearch.script.ScriptService; import org.elasticsearch.threadpool.ThreadPool; @@ -103,7 +103,7 @@ public class IndexService extends AbstractIndexComponent implements IndicesClust private final BitsetFilterCache bitsetFilterCache; private final NodeEnvironment nodeEnv; private final ShardStoreDeleter shardStoreDeleter; - private final IndexStore indexStore; + private final IndexStorePlugin.DirectoryFactory directoryFactory; private final IndexSearcherWrapper searcherWrapper; private final IndexCache indexCache; private final MapperService mapperService; @@ -149,7 +149,7 @@ public class IndexService extends AbstractIndexComponent implements IndicesClust ScriptService scriptService, Client client, QueryCache queryCache, - IndexStore indexStore, + IndexStorePlugin.DirectoryFactory directoryFactory, IndexEventListener eventListener, IndexModule.IndexSearcherWrapperFactory wrapperFactory, MapperRegistry mapperRegistry, @@ -200,7 +200,7 @@ public class IndexService extends AbstractIndexComponent implements IndicesClust this.client = client; this.eventListener = eventListener; this.nodeEnv = nodeEnv; - this.indexStore = indexStore; + this.directoryFactory = directoryFactory; this.engineFactory = Objects.requireNonNull(engineFactory); // initialize this last -- otherwise if the wrapper requires any other member to be non-null we fail with an NPE this.searcherWrapper = wrapperFactory.newWrapper(this); @@ -401,9 +401,8 @@ public class IndexService extends AbstractIndexComponent implements IndicesClust warmer.warm(searcher, shard, IndexService.this.indexSettings); } }; - // TODO we can remove either IndexStore or DirectoryService. All we need is a simple Supplier - DirectoryService directoryService = indexStore.newDirectoryService(path); - store = new Store(shardId, this.indexSettings, directoryService.newDirectory(), lock, + Directory directory = directoryFactory.newDirectory(this.indexSettings, path); + store = new Store(shardId, this.indexSettings, directory, lock, new StoreCloseListener(shardId, () -> eventListener.onStoreClosed(shardId))); eventListener.onStoreCreated(shardId); indexShard = new IndexShard( @@ -753,8 +752,8 @@ public class IndexService extends AbstractIndexComponent implements IndicesClust return searcherWrapper; } // pkg private for testing - final IndexStore getIndexStore() { - return indexStore; + final IndexStorePlugin.DirectoryFactory getDirectoryFactory() { + return directoryFactory; } // pkg private for testing private void maybeFSyncTranslogs() { diff --git a/server/src/main/java/org/elasticsearch/index/store/FsDirectoryService.java b/server/src/main/java/org/elasticsearch/index/store/FsDirectoryFactory.java similarity index 94% rename from server/src/main/java/org/elasticsearch/index/store/FsDirectoryService.java rename to server/src/main/java/org/elasticsearch/index/store/FsDirectoryFactory.java index a8b50fcc538..84bb4c49b27 100644 --- a/server/src/main/java/org/elasticsearch/index/store/FsDirectoryService.java +++ b/server/src/main/java/org/elasticsearch/index/store/FsDirectoryFactory.java @@ -30,13 +30,13 @@ import org.apache.lucene.store.NIOFSDirectory; import org.apache.lucene.store.NativeFSLockFactory; import org.apache.lucene.store.SimpleFSDirectory; import org.apache.lucene.store.SimpleFSLockFactory; -import org.elasticsearch.common.inject.Inject; import org.elasticsearch.common.settings.Setting; import org.elasticsearch.common.settings.Setting.Property; import org.elasticsearch.core.internal.io.IOUtils; import org.elasticsearch.index.IndexModule; import org.elasticsearch.index.IndexSettings; import org.elasticsearch.index.shard.ShardPath; +import org.elasticsearch.plugins.IndexStorePlugin; import java.io.IOException; import java.nio.file.Files; @@ -44,7 +44,8 @@ import java.nio.file.Path; import java.util.HashSet; import java.util.Set; -public class FsDirectoryService extends DirectoryService { +public class FsDirectoryFactory implements IndexStorePlugin.DirectoryFactory { + public static final Setting INDEX_LOCK_FACTOR_SETTING = new Setting<>("index.store.fs.fs_lock", "native", (s) -> { switch (s) { case "native": @@ -56,27 +57,20 @@ public class FsDirectoryService extends DirectoryService { } // can we set on both - node and index level, some nodes might be running on NFS so they might need simple rather than native }, Property.IndexScope, Property.NodeScope); - private final ShardPath path; - - @Inject - public FsDirectoryService(IndexSettings indexSettings, ShardPath path) { - super(path.getShardId(), indexSettings); - this.path = path; - } @Override - public Directory newDirectory() throws IOException { + public Directory newDirectory(IndexSettings indexSettings, ShardPath path) throws IOException { final Path location = path.resolveIndex(); final LockFactory lockFactory = indexSettings.getValue(INDEX_LOCK_FACTOR_SETTING); Files.createDirectories(location); - Directory wrapped = newFSDirectory(location, lockFactory); + Directory wrapped = newFSDirectory(location, lockFactory, indexSettings); Set preLoadExtensions = new HashSet<>( indexSettings.getValue(IndexModule.INDEX_STORE_PRE_LOAD_SETTING)); wrapped = setPreload(wrapped, location, lockFactory, preLoadExtensions); return wrapped; } - protected Directory newFSDirectory(Path location, LockFactory lockFactory) throws IOException { + protected Directory newFSDirectory(Path location, LockFactory lockFactory, IndexSettings indexSettings) throws IOException { final String storeType = indexSettings.getSettings().get(IndexModule.INDEX_STORE_TYPE_SETTING.getKey(), IndexModule.Type.FS.getSettingsKey()); IndexModule.Type type; diff --git a/server/src/main/java/org/elasticsearch/index/store/IndexStore.java b/server/src/main/java/org/elasticsearch/index/store/IndexStore.java deleted file mode 100644 index 0d41b1ac95d..00000000000 --- a/server/src/main/java/org/elasticsearch/index/store/IndexStore.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * 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. - */ - -package org.elasticsearch.index.store; - -import org.elasticsearch.index.AbstractIndexComponent; -import org.elasticsearch.index.IndexSettings; -import org.elasticsearch.index.shard.ShardPath; - -public class IndexStore extends AbstractIndexComponent { - - public IndexStore(IndexSettings indexSettings) { - super(indexSettings); - } - - /** - * The shard store class that should be used for each shard. - */ - public DirectoryService newDirectoryService(ShardPath path) { - return new FsDirectoryService(indexSettings, path); - } - -} diff --git a/server/src/main/java/org/elasticsearch/indices/IndicesService.java b/server/src/main/java/org/elasticsearch/indices/IndicesService.java index cacc95115d3..22504eee50a 100644 --- a/server/src/main/java/org/elasticsearch/indices/IndicesService.java +++ b/server/src/main/java/org/elasticsearch/indices/IndicesService.java @@ -110,13 +110,13 @@ import org.elasticsearch.index.shard.IndexShardState; import org.elasticsearch.index.shard.IndexingOperationListener; import org.elasticsearch.index.shard.IndexingStats; import org.elasticsearch.index.shard.ShardId; -import org.elasticsearch.index.store.IndexStore; import org.elasticsearch.indices.breaker.CircuitBreakerService; import org.elasticsearch.indices.cluster.IndicesClusterStateService; import org.elasticsearch.indices.fielddata.cache.IndicesFieldDataCache; import org.elasticsearch.indices.mapper.MapperRegistry; import org.elasticsearch.indices.recovery.PeerRecoveryTargetService; import org.elasticsearch.indices.recovery.RecoveryState; +import org.elasticsearch.plugins.IndexStorePlugin; import org.elasticsearch.plugins.PluginsService; import org.elasticsearch.repositories.RepositoriesService; import org.elasticsearch.script.ScriptService; @@ -201,7 +201,7 @@ public class IndicesService extends AbstractLifecycleComponent private final IndicesQueryCache indicesQueryCache; private final MetaStateService metaStateService; private final Collection>> engineFactoryProviders; - private final Map> indexStoreFactories; + private final Map directoryFactories; final AbstractRefCounted indicesRefCount; // pkg-private for testing private final CountDownLatch closeLatch = new CountDownLatch(1); @@ -217,7 +217,7 @@ public class IndicesService extends AbstractLifecycleComponent IndexScopedSettings indexScopedSettings, CircuitBreakerService circuitBreakerService, BigArrays bigArrays, ScriptService scriptService, Client client, MetaStateService metaStateService, Collection>> engineFactoryProviders, - Map> indexStoreFactories) { + Map directoryFactories) { this.settings = settings; this.threadPool = threadPool; this.pluginsService = pluginsService; @@ -252,13 +252,13 @@ public class IndicesService extends AbstractLifecycleComponent this.engineFactoryProviders = engineFactoryProviders; // do not allow any plugin-provided index store type to conflict with a built-in type - for (final String indexStoreType : indexStoreFactories.keySet()) { + for (final String indexStoreType : directoryFactories.keySet()) { if (IndexModule.isBuiltinType(indexStoreType)) { throw new IllegalStateException("registered index store type [" + indexStoreType + "] conflicts with a built-in type"); } } - this.indexStoreFactories = indexStoreFactories; + this.directoryFactories = directoryFactories; // doClose() is called when shutting down a node, yet there might still be ongoing requests // that we need to wait for before closing some resources such as the caches. In order to // avoid closing these resources while ongoing requests are still being processed, we use a @@ -553,7 +553,7 @@ public class IndicesService extends AbstractLifecycleComponent idxSettings.getNumberOfReplicas(), indexCreationContext); - final IndexModule indexModule = new IndexModule(idxSettings, analysisRegistry, getEngineFactory(idxSettings), indexStoreFactories); + final IndexModule indexModule = new IndexModule(idxSettings, analysisRegistry, getEngineFactory(idxSettings), directoryFactories); for (IndexingOperationListener operationListener : indexingOperationListeners) { indexModule.addIndexOperationListener(operationListener); } @@ -620,7 +620,7 @@ public class IndicesService extends AbstractLifecycleComponent */ public synchronized MapperService createIndexMapperService(IndexMetaData indexMetaData) throws IOException { final IndexSettings idxSettings = new IndexSettings(indexMetaData, this.settings, indexScopedSettings); - final IndexModule indexModule = new IndexModule(idxSettings, analysisRegistry, getEngineFactory(idxSettings), indexStoreFactories); + final IndexModule indexModule = new IndexModule(idxSettings, analysisRegistry, getEngineFactory(idxSettings), directoryFactories); pluginsService.onIndexModule(indexModule); return indexModule.newIndexMapperService(xContentRegistry, mapperRegistry, scriptService); } diff --git a/server/src/main/java/org/elasticsearch/node/Node.java b/server/src/main/java/org/elasticsearch/node/Node.java index 6217d2ee565..d131dc7850e 100644 --- a/server/src/main/java/org/elasticsearch/node/Node.java +++ b/server/src/main/java/org/elasticsearch/node/Node.java @@ -100,7 +100,6 @@ import org.elasticsearch.http.HttpServerTransport; import org.elasticsearch.index.IndexSettings; import org.elasticsearch.index.analysis.AnalysisRegistry; import org.elasticsearch.index.engine.EngineFactory; -import org.elasticsearch.index.store.IndexStore; import org.elasticsearch.indices.IndicesModule; import org.elasticsearch.indices.IndicesService; import org.elasticsearch.indices.analysis.AnalysisModule; @@ -410,10 +409,10 @@ public class Node implements Closeable { .collect(Collectors.toList()); - final Map> indexStoreFactories = + final Map indexStoreFactories = pluginsService.filterPlugins(IndexStorePlugin.class) .stream() - .map(IndexStorePlugin::getIndexStoreFactories) + .map(IndexStorePlugin::getDirectoryFactories) .flatMap(m -> m.entrySet().stream()) .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); diff --git a/server/src/main/java/org/elasticsearch/plugins/IndexStorePlugin.java b/server/src/main/java/org/elasticsearch/plugins/IndexStorePlugin.java index 16eec535e4b..2beaf1935e4 100644 --- a/server/src/main/java/org/elasticsearch/plugins/IndexStorePlugin.java +++ b/server/src/main/java/org/elasticsearch/plugins/IndexStorePlugin.java @@ -19,24 +19,40 @@ package org.elasticsearch.plugins; +import org.apache.lucene.store.Directory; import org.elasticsearch.index.IndexSettings; -import org.elasticsearch.index.store.IndexStore; +import org.elasticsearch.index.shard.ShardPath; +import java.io.IOException; import java.util.Map; -import java.util.function.Function; /** - * A plugin that provides alternative index store implementations. + * A plugin that provides alternative directory implementations. */ public interface IndexStorePlugin { /** - * The index store factories for this plugin. When an index is created the store type setting - * {@link org.elasticsearch.index.IndexModule#INDEX_STORE_TYPE_SETTING} on the index will be examined and either use the default or a - * built-in type, or looked up among all the index store factories from {@link IndexStore} plugins. - * - * @return a map from store type to an index store factory + * An interface that describes how to create a new directory instance per shard. */ - Map> getIndexStoreFactories(); + @FunctionalInterface + interface DirectoryFactory { + /** + * Creates a new directory per shard. This method is called once per shard on shard creation. + * @param indexSettings the shards index settings + * @param shardPath the path the shard is using + * @return a new lucene directory instance + * @throws IOException if an IOException occurs while opening the directory + */ + Directory newDirectory(IndexSettings indexSettings, ShardPath shardPath) throws IOException; + } + + /** + * The {@link DirectoryFactory} mappings for this plugin. When an index is created the store type setting + * {@link org.elasticsearch.index.IndexModule#INDEX_STORE_TYPE_SETTING} on the index will be examined and either use the default or a + * built-in type, or looked up among all the directory factories from {@link IndexStorePlugin} plugins. + * + * @return a map from store type to an directory factory + */ + Map getDirectoryFactories(); } diff --git a/server/src/test/java/org/elasticsearch/index/IndexModuleTests.java b/server/src/test/java/org/elasticsearch/index/IndexModuleTests.java index 351cccdff4a..d0f811007a6 100644 --- a/server/src/test/java/org/elasticsearch/index/IndexModuleTests.java +++ b/server/src/test/java/org/elasticsearch/index/IndexModuleTests.java @@ -29,6 +29,7 @@ import org.apache.lucene.search.TermStatistics; import org.apache.lucene.search.Weight; import org.apache.lucene.search.similarities.BM25Similarity; import org.apache.lucene.search.similarities.Similarity; +import org.apache.lucene.store.Directory; import org.apache.lucene.util.SetOnce.AlreadySetException; import org.elasticsearch.Version; import org.elasticsearch.cluster.metadata.IndexMetaData; @@ -60,9 +61,10 @@ import org.elasticsearch.index.shard.IndexSearcherWrapper; import org.elasticsearch.index.shard.IndexingOperationListener; import org.elasticsearch.index.shard.SearchOperationListener; import org.elasticsearch.index.shard.ShardId; +import org.elasticsearch.index.shard.ShardPath; import org.elasticsearch.index.similarity.NonNegativeScoresSimilarity; import org.elasticsearch.index.similarity.SimilarityService; -import org.elasticsearch.index.store.IndexStore; +import org.elasticsearch.index.store.FsDirectoryFactory; import org.elasticsearch.indices.IndicesModule; import org.elasticsearch.indices.IndicesQueryCache; import org.elasticsearch.indices.breaker.CircuitBreakerService; @@ -70,6 +72,7 @@ import org.elasticsearch.indices.breaker.NoneCircuitBreakerService; import org.elasticsearch.indices.cluster.IndicesClusterStateService.AllocatedIndices.IndexRemovalReason; import org.elasticsearch.indices.fielddata.cache.IndicesFieldDataCache; import org.elasticsearch.indices.mapper.MapperRegistry; +import org.elasticsearch.plugins.IndexStorePlugin; import org.elasticsearch.script.ScriptService; import org.elasticsearch.search.internal.SearchContext; import org.elasticsearch.test.ClusterServiceUtils; @@ -86,7 +89,6 @@ import java.util.Collections; import java.util.Map; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; -import java.util.function.Function; import static java.util.Collections.emptyMap; import static org.elasticsearch.index.IndexService.IndexCreationContext.CREATE_INDEX; @@ -174,11 +176,12 @@ public class IndexModuleTests extends ESTestCase { .put(IndexModule.INDEX_STORE_TYPE_SETTING.getKey(), "foo_store") .build(); final IndexSettings indexSettings = IndexSettingsModule.newIndexSettings(index, settings); - final Map> indexStoreFactories = Collections.singletonMap("foo_store", FooStore::new); + final Map indexStoreFactories = Collections.singletonMap( + "foo_store", new FooFunction()); final IndexModule module = new IndexModule(indexSettings, emptyAnalysisRegistry, new InternalEngineFactory(), indexStoreFactories); final IndexService indexService = newIndexService(module); - assertThat(indexService.getIndexStore(), instanceOf(FooStore.class)); + assertThat(indexService.getDirectoryFactory(), instanceOf(FooFunction.class)); indexService.close("simon says", false); } @@ -444,10 +447,11 @@ public class IndexModuleTests extends ESTestCase { } } - public static final class FooStore extends IndexStore { + public static final class FooFunction implements IndexStorePlugin.DirectoryFactory { - public FooStore(IndexSettings indexSettings) { - super(indexSettings); + @Override + public Directory newDirectory(IndexSettings indexSettings, ShardPath shardPath) throws IOException { + return new FsDirectoryFactory().newDirectory(indexSettings, shardPath); } } diff --git a/server/src/test/java/org/elasticsearch/index/shard/IndexShardTests.java b/server/src/test/java/org/elasticsearch/index/shard/IndexShardTests.java index 7e594684ca8..19a1ce4054a 100644 --- a/server/src/test/java/org/elasticsearch/index/shard/IndexShardTests.java +++ b/server/src/test/java/org/elasticsearch/index/shard/IndexShardTests.java @@ -125,7 +125,7 @@ import org.elasticsearch.test.CorruptionUtils; import org.elasticsearch.test.DummyShardLock; import org.elasticsearch.test.FieldMaskingReader; import org.elasticsearch.test.VersionUtils; -import org.elasticsearch.test.store.MockFSDirectoryService; +import org.elasticsearch.test.store.MockFSDirectoryFactory; import org.elasticsearch.threadpool.ThreadPool; import org.junit.Assert; @@ -3827,7 +3827,7 @@ public class IndexShardTests extends IndexShardTestCase { readyToCloseLatch.await(); shard.close("testing", false); // in integration tests, this is done as a listener on IndexService. - MockFSDirectoryService.checkIndex(logger, shard.store(), shard.shardId); + MockFSDirectoryFactory.checkIndex(logger, shard.store(), shard.shardId); } catch (InterruptedException | IOException e) { throw new AssertionError(e); } finally { diff --git a/server/src/test/java/org/elasticsearch/index/store/IndexStoreTests.java b/server/src/test/java/org/elasticsearch/index/store/FsDirectoryFactoryTests.java similarity index 59% rename from server/src/test/java/org/elasticsearch/index/store/IndexStoreTests.java rename to server/src/test/java/org/elasticsearch/index/store/FsDirectoryFactoryTests.java index 21c8d1c1d78..0f24f8f3a5a 100644 --- a/server/src/test/java/org/elasticsearch/index/store/IndexStoreTests.java +++ b/server/src/test/java/org/elasticsearch/index/store/FsDirectoryFactoryTests.java @@ -19,10 +19,12 @@ package org.elasticsearch.index.store; import org.apache.lucene.store.Directory; +import org.apache.lucene.store.FileSwitchDirectory; import org.apache.lucene.store.MMapDirectory; import org.apache.lucene.store.NIOFSDirectory; import org.apache.lucene.store.NoLockFactory; import org.apache.lucene.store.SimpleFSDirectory; +import org.apache.lucene.store.SleepingLockWrapper; import org.apache.lucene.util.Constants; import org.elasticsearch.Version; import org.elasticsearch.cluster.metadata.IndexMetaData; @@ -36,32 +38,68 @@ import org.elasticsearch.test.ESTestCase; import org.elasticsearch.test.IndexSettingsModule; import java.io.IOException; +import java.nio.file.Files; import java.nio.file.Path; +import java.util.Arrays; import java.util.Locale; -public class IndexStoreTests extends ESTestCase { +public class FsDirectoryFactoryTests extends ESTestCase { + + public void testPreload() throws IOException { + doTestPreload(); + doTestPreload("nvd", "dvd", "tim"); + doTestPreload("*"); + } + + private void doTestPreload(String...preload) throws IOException { + Settings build = Settings.builder() + .put(IndexModule.INDEX_STORE_TYPE_SETTING.getKey(), "mmapfs") + .putList(IndexModule.INDEX_STORE_PRE_LOAD_SETTING.getKey(), preload) + .build(); + IndexSettings settings = IndexSettingsModule.newIndexSettings("foo", build); + Path tempDir = createTempDir().resolve(settings.getUUID()).resolve("0"); + Files.createDirectories(tempDir); + ShardPath path = new ShardPath(false, tempDir, tempDir, new ShardId(settings.getIndex(), 0)); + FsDirectoryFactory fsDirectoryFactory = new FsDirectoryFactory(); + Directory directory = fsDirectoryFactory.newDirectory(settings, path); + assertFalse(directory instanceof SleepingLockWrapper); + if (preload.length == 0) { + assertTrue(directory.toString(), directory instanceof MMapDirectory); + assertFalse(((MMapDirectory) directory).getPreload()); + } else if (Arrays.asList(preload).contains("*")) { + assertTrue(directory.toString(), directory instanceof MMapDirectory); + assertTrue(((MMapDirectory) directory).getPreload()); + } else { + assertTrue(directory.toString(), directory instanceof FileSwitchDirectory); + FileSwitchDirectory fsd = (FileSwitchDirectory) directory; + assertTrue(fsd.getPrimaryDir() instanceof MMapDirectory); + assertTrue(((MMapDirectory) fsd.getPrimaryDir()).getPreload()); + assertTrue(fsd.getSecondaryDir() instanceof MMapDirectory); + assertFalse(((MMapDirectory) fsd.getSecondaryDir()).getPreload()); + } + } public void testStoreDirectory() throws IOException { Index index = new Index("foo", "fooUUID"); final Path tempDir = createTempDir().resolve(index.getUUID()).resolve("0"); // default - doTestStoreDirectory(index, tempDir, null, IndexModule.Type.FS); + doTestStoreDirectory(tempDir, null, IndexModule.Type.FS); // explicit directory impls for (IndexModule.Type type : IndexModule.Type.values()) { - doTestStoreDirectory(index, tempDir, type.name().toLowerCase(Locale.ROOT), type); + doTestStoreDirectory(tempDir, type.name().toLowerCase(Locale.ROOT), type); } } - private void doTestStoreDirectory(Index index, Path tempDir, String typeSettingValue, IndexModule.Type type) throws IOException { + private void doTestStoreDirectory(Path tempDir, String typeSettingValue, IndexModule.Type type) throws IOException { Settings.Builder settingsBuilder = Settings.builder() - .put(IndexMetaData.SETTING_VERSION_CREATED, Version.CURRENT); + .put(IndexMetaData.SETTING_VERSION_CREATED, Version.CURRENT); if (typeSettingValue != null) { settingsBuilder.put(IndexModule.INDEX_STORE_TYPE_SETTING.getKey(), typeSettingValue); } Settings settings = settingsBuilder.build(); IndexSettings indexSettings = IndexSettingsModule.newIndexSettings("foo", settings); - FsDirectoryService service = new FsDirectoryService(indexSettings, new ShardPath(false, tempDir, tempDir, new ShardId(index, 0))); - try (Directory directory = service.newFSDirectory(tempDir, NoLockFactory.INSTANCE)) { + FsDirectoryFactory service = new FsDirectoryFactory(); + try (Directory directory = service.newFSDirectory(tempDir, NoLockFactory.INSTANCE, indexSettings)) { switch (type) { case HYBRIDFS: assertHybridDirectory(directory); @@ -91,8 +129,8 @@ public class IndexStoreTests extends ESTestCase { } private void assertHybridDirectory(Directory directory) { - assertTrue(directory.toString(), directory instanceof FsDirectoryService.HybridDirectory); - Directory randomAccessDirectory = ((FsDirectoryService.HybridDirectory) directory).getRandomAccessDirectory(); + assertTrue(directory.toString(), directory instanceof FsDirectoryFactory.HybridDirectory); + Directory randomAccessDirectory = ((FsDirectoryFactory.HybridDirectory) directory).getRandomAccessDirectory(); assertTrue("randomAccessDirectory: " + randomAccessDirectory.toString(), randomAccessDirectory instanceof MMapDirectory); } } diff --git a/server/src/test/java/org/elasticsearch/index/store/FsDirectoryServiceTests.java b/server/src/test/java/org/elasticsearch/index/store/FsDirectoryServiceTests.java deleted file mode 100644 index e84ff3f3284..00000000000 --- a/server/src/test/java/org/elasticsearch/index/store/FsDirectoryServiceTests.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * 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. - */ -package org.elasticsearch.index.store; - -import org.apache.lucene.store.Directory; -import org.apache.lucene.store.FileSwitchDirectory; -import org.apache.lucene.store.MMapDirectory; -import org.apache.lucene.store.SleepingLockWrapper; -import org.elasticsearch.common.settings.Settings; -import org.elasticsearch.index.IndexModule; -import org.elasticsearch.index.IndexSettings; -import org.elasticsearch.index.shard.ShardId; -import org.elasticsearch.index.shard.ShardPath; -import org.elasticsearch.test.ESTestCase; -import org.elasticsearch.test.IndexSettingsModule; - -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.Arrays; - -public class FsDirectoryServiceTests extends ESTestCase { - - public void testPreload() throws IOException { - doTestPreload(); - doTestPreload("nvd", "dvd", "tim"); - doTestPreload("*"); - } - - private void doTestPreload(String...preload) throws IOException { - Settings build = Settings.builder() - .put(IndexModule.INDEX_STORE_TYPE_SETTING.getKey(), "mmapfs") - .putList(IndexModule.INDEX_STORE_PRE_LOAD_SETTING.getKey(), preload) - .build(); - IndexSettings settings = IndexSettingsModule.newIndexSettings("foo", build); - Path tempDir = createTempDir().resolve(settings.getUUID()).resolve("0"); - Files.createDirectories(tempDir); - ShardPath path = new ShardPath(false, tempDir, tempDir, new ShardId(settings.getIndex(), 0)); - FsDirectoryService fsDirectoryService = new FsDirectoryService(settings, path); - Directory directory = fsDirectoryService.newDirectory(); - assertFalse(directory instanceof SleepingLockWrapper); - if (preload.length == 0) { - assertTrue(directory.toString(), directory instanceof MMapDirectory); - assertFalse(((MMapDirectory) directory).getPreload()); - } else if (Arrays.asList(preload).contains("*")) { - assertTrue(directory.toString(), directory instanceof MMapDirectory); - assertTrue(((MMapDirectory) directory).getPreload()); - } else { - assertTrue(directory.toString(), directory instanceof FileSwitchDirectory); - FileSwitchDirectory fsd = (FileSwitchDirectory) directory; - assertTrue(fsd.getPrimaryDir() instanceof MMapDirectory); - assertTrue(((MMapDirectory) fsd.getPrimaryDir()).getPreload()); - assertTrue(fsd.getSecondaryDir() instanceof MMapDirectory); - assertFalse(((MMapDirectory) fsd.getSecondaryDir()).getPreload()); - } - } -} diff --git a/server/src/test/java/org/elasticsearch/plugins/IndexStorePluginTests.java b/server/src/test/java/org/elasticsearch/plugins/IndexStorePluginTests.java index d413c0f0be2..fac270172b0 100644 --- a/server/src/test/java/org/elasticsearch/plugins/IndexStorePluginTests.java +++ b/server/src/test/java/org/elasticsearch/plugins/IndexStorePluginTests.java @@ -22,15 +22,13 @@ package org.elasticsearch.plugins; import org.elasticsearch.bootstrap.JavaVersion; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.index.IndexModule; -import org.elasticsearch.index.IndexSettings; -import org.elasticsearch.index.store.IndexStore; +import org.elasticsearch.index.store.FsDirectoryFactory; import org.elasticsearch.node.MockNode; import org.elasticsearch.test.ESTestCase; import java.util.Arrays; import java.util.Collections; import java.util.Map; -import java.util.function.Function; import static org.elasticsearch.test.hamcrest.RegexMatcher.matches; import static org.hamcrest.Matchers.containsString; @@ -41,8 +39,8 @@ public class IndexStorePluginTests extends ESTestCase { public static class BarStorePlugin extends Plugin implements IndexStorePlugin { @Override - public Map> getIndexStoreFactories() { - return Collections.singletonMap("store", IndexStore::new); + public Map getDirectoryFactories() { + return Collections.singletonMap("store", new FsDirectoryFactory()); } } @@ -50,8 +48,8 @@ public class IndexStorePluginTests extends ESTestCase { public static class FooStorePlugin extends Plugin implements IndexStorePlugin { @Override - public Map> getIndexStoreFactories() { - return Collections.singletonMap("store", IndexStore::new); + public Map getDirectoryFactories() { + return Collections.singletonMap("store", new FsDirectoryFactory()); } } @@ -65,8 +63,8 @@ public class IndexStorePluginTests extends ESTestCase { } @Override - public Map> getIndexStoreFactories() { - return Collections.singletonMap(TYPE, IndexStore::new); + public Map getDirectoryFactories() { + return Collections.singletonMap(TYPE, new FsDirectoryFactory()); } } @@ -86,11 +84,11 @@ public class IndexStorePluginTests extends ESTestCase { if (JavaVersion.current().compareTo(JavaVersion.parse("9")) >= 0) { assertThat(e, hasToString(matches( "java.lang.IllegalStateException: Duplicate key store \\(attempted merging values " + - "org.elasticsearch.plugins.IndexStorePluginTests\\$BarStorePlugin.* " + - "and org.elasticsearch.plugins.IndexStorePluginTests\\$FooStorePlugin.*\\)"))); + "org.elasticsearch.index.store.FsDirectoryFactory@[\\w\\d]+ " + + "and org.elasticsearch.index.store.FsDirectoryFactory@[\\w\\d]+\\)"))); } else { assertThat(e, hasToString(matches( - "java.lang.IllegalStateException: Duplicate key org.elasticsearch.plugins.IndexStorePluginTests\\$BarStorePlugin.*"))); + "java.lang.IllegalStateException: Duplicate key org.elasticsearch.index.store.FsDirectoryFactory@[\\w\\d]+"))); } } diff --git a/server/src/test/java/org/elasticsearch/search/basic/SearchWithRandomIOExceptionsIT.java b/server/src/test/java/org/elasticsearch/search/basic/SearchWithRandomIOExceptionsIT.java index 3d39da60254..e8066ead22e 100644 --- a/server/src/test/java/org/elasticsearch/search/basic/SearchWithRandomIOExceptionsIT.java +++ b/server/src/test/java/org/elasticsearch/search/basic/SearchWithRandomIOExceptionsIT.java @@ -37,7 +37,7 @@ import org.elasticsearch.index.query.QueryBuilders; import org.elasticsearch.plugins.Plugin; import org.elasticsearch.search.sort.SortOrder; import org.elasticsearch.test.ESIntegTestCase; -import org.elasticsearch.test.store.MockFSDirectoryService; +import org.elasticsearch.test.store.MockFSDirectoryFactory; import org.elasticsearch.test.store.MockFSIndexStore; import java.io.IOException; import java.util.Arrays; @@ -104,16 +104,16 @@ public class SearchWithRandomIOExceptionsIT extends ESIntegTestCase { client().admin().indices().prepareFlush("test").execute().get(); client().admin().indices().prepareClose("test").execute().get(); client().admin().indices().prepareUpdateSettings("test").setSettings(Settings.builder() - .put(MockFSDirectoryService.RANDOM_IO_EXCEPTION_RATE_SETTING.getKey(), exceptionRate) - .put(MockFSDirectoryService.RANDOM_IO_EXCEPTION_RATE_ON_OPEN_SETTING.getKey(), exceptionOnOpenRate)); + .put(MockFSDirectoryFactory.RANDOM_IO_EXCEPTION_RATE_SETTING.getKey(), exceptionRate) + .put(MockFSDirectoryFactory.RANDOM_IO_EXCEPTION_RATE_ON_OPEN_SETTING.getKey(), exceptionOnOpenRate)); client().admin().indices().prepareOpen("test").execute().get(); } else { Settings.Builder settings = Settings.builder() .put("index.number_of_replicas", randomIntBetween(0, 1)) .put(MockFSIndexStore.INDEX_CHECK_INDEX_ON_CLOSE_SETTING.getKey(), false) - .put(MockFSDirectoryService.RANDOM_IO_EXCEPTION_RATE_SETTING.getKey(), exceptionRate) + .put(MockFSDirectoryFactory.RANDOM_IO_EXCEPTION_RATE_SETTING.getKey(), exceptionRate) // we cannot expect that the index will be valid - .put(MockFSDirectoryService.RANDOM_IO_EXCEPTION_RATE_ON_OPEN_SETTING.getKey(), exceptionOnOpenRate); + .put(MockFSDirectoryFactory.RANDOM_IO_EXCEPTION_RATE_ON_OPEN_SETTING.getKey(), exceptionOnOpenRate); logger.info("creating index: [test] using settings: [{}]", settings.build()); client().admin().indices().prepareCreate("test") .setSettings(settings) @@ -195,8 +195,8 @@ public class SearchWithRandomIOExceptionsIT extends ESIntegTestCase { // check the index still contains the records that we indexed without errors client().admin().indices().prepareClose("test").execute().get(); client().admin().indices().prepareUpdateSettings("test").setSettings(Settings.builder() - .put(MockFSDirectoryService.RANDOM_IO_EXCEPTION_RATE_SETTING.getKey(), 0) - .put(MockFSDirectoryService.RANDOM_IO_EXCEPTION_RATE_ON_OPEN_SETTING.getKey(), 0)); + .put(MockFSDirectoryFactory.RANDOM_IO_EXCEPTION_RATE_SETTING.getKey(), 0) + .put(MockFSDirectoryFactory.RANDOM_IO_EXCEPTION_RATE_ON_OPEN_SETTING.getKey(), 0)); client().admin().indices().prepareOpen("test").execute().get(); ensureGreen(); SearchResponse searchResponse = client().prepareSearch().setTypes("type") diff --git a/test/framework/src/main/java/org/elasticsearch/test/store/MockFSDirectoryService.java b/test/framework/src/main/java/org/elasticsearch/test/store/MockFSDirectoryFactory.java similarity index 78% rename from test/framework/src/main/java/org/elasticsearch/test/store/MockFSDirectoryService.java rename to test/framework/src/main/java/org/elasticsearch/test/store/MockFSDirectoryFactory.java index 2fcdf9be511..3ea1edea487 100644 --- a/test/framework/src/main/java/org/elasticsearch/test/store/MockFSDirectoryService.java +++ b/test/framework/src/main/java/org/elasticsearch/test/store/MockFSDirectoryFactory.java @@ -19,19 +19,16 @@ package org.elasticsearch.test.store; -import com.carrotsearch.randomizedtesting.SeedUtils; import com.carrotsearch.randomizedtesting.generators.RandomPicks; import org.apache.logging.log4j.Logger; import org.apache.lucene.index.CheckIndex; import org.apache.lucene.store.BaseDirectoryWrapper; import org.apache.lucene.store.Directory; -import org.apache.lucene.store.LockFactory; import org.apache.lucene.store.LockObtainFailedException; import org.apache.lucene.store.MockDirectoryWrapper; import org.apache.lucene.util.LuceneTestCase; import org.apache.lucene.util.TestRuleMarkFailure; import org.elasticsearch.cluster.metadata.IndexMetaData; -import org.elasticsearch.common.inject.Inject; import org.elasticsearch.common.io.stream.BytesStreamOutput; import org.elasticsearch.common.lucene.Lucene; import org.elasticsearch.common.settings.Setting; @@ -41,8 +38,9 @@ import org.elasticsearch.index.IndexModule; import org.elasticsearch.index.IndexSettings; import org.elasticsearch.index.shard.ShardId; import org.elasticsearch.index.shard.ShardPath; -import org.elasticsearch.index.store.FsDirectoryService; +import org.elasticsearch.index.store.FsDirectoryFactory; import org.elasticsearch.index.store.Store; +import org.elasticsearch.plugins.IndexStorePlugin; import org.elasticsearch.test.ESIntegTestCase; import org.elasticsearch.test.ESTestCase; import org.junit.Assert; @@ -51,12 +49,11 @@ import java.io.Closeable; import java.io.IOException; import java.io.PrintStream; import java.nio.charset.StandardCharsets; -import java.nio.file.Path; import java.util.Arrays; import java.util.Random; import java.util.Set; -public class MockFSDirectoryService extends FsDirectoryService { +public class MockFSDirectoryFactory implements IndexStorePlugin.DirectoryFactory { public static final Setting RANDOM_IO_EXCEPTION_RATE_ON_OPEN_SETTING = Setting.doubleSetting("index.store.mock.random.io_exception_rate_on_open", 0.0d, 0.0d, Property.IndexScope, Property.NodeScope); @@ -65,42 +62,12 @@ public class MockFSDirectoryService extends FsDirectoryService { public static final Setting CRASH_INDEX_SETTING = Setting.boolSetting("index.store.mock.random.crash_index", true, Property.IndexScope, Property.NodeScope); - private final FsDirectoryService delegateService; - private final Random random; - private final double randomIOExceptionRate; - private final double randomIOExceptionRateOnOpen; - private final MockDirectoryWrapper.Throttling throttle; - private final boolean crashIndex; - - @Inject - public MockFSDirectoryService(IndexSettings idxSettings, final ShardPath path) { - super(idxSettings, path); + @Override + public Directory newDirectory(IndexSettings idxSettings, ShardPath path) throws IOException { Settings indexSettings = idxSettings.getSettings(); - final long seed = idxSettings.getValue(ESIntegTestCase.INDEX_TEST_SEED_SETTING); - this.random = new Random(seed); - - randomIOExceptionRate = RANDOM_IO_EXCEPTION_RATE_SETTING.get(indexSettings); - randomIOExceptionRateOnOpen = RANDOM_IO_EXCEPTION_RATE_ON_OPEN_SETTING.get(indexSettings); - random.nextInt(shardId.getId() + 1); // some randomness per shard - throttle = MockDirectoryWrapper.Throttling.NEVER; - crashIndex = CRASH_INDEX_SETTING.get(indexSettings); - - if (logger.isDebugEnabled()) { - logger.debug("Using MockDirWrapper with seed [{}] throttle: [{}] crashIndex: [{}]", SeedUtils.formatSeed(seed), - throttle, crashIndex); - } - delegateService = randomDirectoryService(idxSettings, path); - } - - - @Override - public Directory newDirectory() throws IOException { - return wrap(delegateService.newDirectory()); - } - - @Override - protected synchronized Directory newFSDirectory(Path location, LockFactory lockFactory) throws IOException { - throw new UnsupportedOperationException(); + Random random = new Random(idxSettings.getValue(ESIntegTestCase.INDEX_TEST_SEED_SETTING)); + return wrap(randomDirectoryService(random, idxSettings, path), random, indexSettings, + path.getShardId()); } public static void checkIndex(Logger logger, Store store, ShardId shardId) { @@ -138,8 +105,14 @@ public class MockFSDirectoryService extends FsDirectoryService { } } - private Directory wrap(Directory dir) { - final ElasticsearchMockDirectoryWrapper w = new ElasticsearchMockDirectoryWrapper(random, dir, this.crashIndex); + private Directory wrap(Directory dir, Random random, Settings indexSettings, ShardId shardId) { + + double randomIOExceptionRate = RANDOM_IO_EXCEPTION_RATE_SETTING.get(indexSettings); + double randomIOExceptionRateOnOpen = RANDOM_IO_EXCEPTION_RATE_ON_OPEN_SETTING.get(indexSettings); + random.nextInt(shardId.getId() + 1); // some randomness per shard + MockDirectoryWrapper.Throttling throttle = MockDirectoryWrapper.Throttling.NEVER; + boolean crashIndex = CRASH_INDEX_SETTING.get(indexSettings); + final ElasticsearchMockDirectoryWrapper w = new ElasticsearchMockDirectoryWrapper(random, dir, crashIndex); w.setRandomIOExceptionRate(randomIOExceptionRate); w.setRandomIOExceptionRateOnOpen(randomIOExceptionRateOnOpen); w.setThrottling(throttle); @@ -151,7 +124,7 @@ public class MockFSDirectoryService extends FsDirectoryService { return w; } - private FsDirectoryService randomDirectoryService(IndexSettings indexSettings, ShardPath path) { + private Directory randomDirectoryService(Random random, IndexSettings indexSettings, ShardPath path) throws IOException { final IndexMetaData build = IndexMetaData.builder(indexSettings.getIndexMetaData()) .settings(Settings.builder() // don't use the settings from indexSettings#getSettings() they are merged with node settings and might contain @@ -161,7 +134,7 @@ public class MockFSDirectoryService extends FsDirectoryService { RandomPicks.randomFrom(random, IndexModule.Type.values()).getSettingsKey())) .build(); final IndexSettings newIndexSettings = new IndexSettings(build, indexSettings.getNodeSettings()); - return new FsDirectoryService(newIndexSettings, path); + return new FsDirectoryFactory().newDirectory(newIndexSettings, path); } public static final class ElasticsearchMockDirectoryWrapper extends MockDirectoryWrapper { diff --git a/test/framework/src/main/java/org/elasticsearch/test/store/MockFSIndexStore.java b/test/framework/src/main/java/org/elasticsearch/test/store/MockFSIndexStore.java index 1ec50876055..47a20803f7a 100644 --- a/test/framework/src/main/java/org/elasticsearch/test/store/MockFSIndexStore.java +++ b/test/framework/src/main/java/org/elasticsearch/test/store/MockFSIndexStore.java @@ -26,14 +26,10 @@ import org.elasticsearch.common.settings.Setting; import org.elasticsearch.common.settings.Setting.Property; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.index.IndexModule; -import org.elasticsearch.index.IndexSettings; import org.elasticsearch.index.shard.IndexEventListener; import org.elasticsearch.index.shard.IndexShard; import org.elasticsearch.index.shard.IndexShardState; import org.elasticsearch.index.shard.ShardId; -import org.elasticsearch.index.shard.ShardPath; -import org.elasticsearch.index.store.DirectoryService; -import org.elasticsearch.index.store.IndexStore; import org.elasticsearch.plugins.IndexStorePlugin; import org.elasticsearch.plugins.Plugin; @@ -43,9 +39,8 @@ import java.util.EnumSet; import java.util.IdentityHashMap; import java.util.List; import java.util.Map; -import java.util.function.Function; -public class MockFSIndexStore extends IndexStore { +public final class MockFSIndexStore { public static final Setting INDEX_CHECK_INDEX_ON_CLOSE_SETTING = Setting.boolSetting("index.store.mock.check_index_on_close", true, Property.IndexScope, Property.NodeScope); @@ -59,14 +54,14 @@ public class MockFSIndexStore extends IndexStore { @Override public List> getSettings() { return Arrays.asList(INDEX_CHECK_INDEX_ON_CLOSE_SETTING, - MockFSDirectoryService.CRASH_INDEX_SETTING, - MockFSDirectoryService.RANDOM_IO_EXCEPTION_RATE_SETTING, - MockFSDirectoryService.RANDOM_IO_EXCEPTION_RATE_ON_OPEN_SETTING); + MockFSDirectoryFactory.CRASH_INDEX_SETTING, + MockFSDirectoryFactory.RANDOM_IO_EXCEPTION_RATE_SETTING, + MockFSDirectoryFactory.RANDOM_IO_EXCEPTION_RATE_ON_OPEN_SETTING); } @Override - public Map> getIndexStoreFactories() { - return Collections.singletonMap("mock", MockFSIndexStore::new); + public Map getDirectoryFactories() { + return Collections.singletonMap("mock", new MockFSDirectoryFactory()); } @Override @@ -80,15 +75,6 @@ public class MockFSIndexStore extends IndexStore { } } - MockFSIndexStore(IndexSettings indexSettings) { - super(indexSettings); - } - - @Override - public DirectoryService newDirectoryService(ShardPath path) { - return new MockFSDirectoryService(indexSettings, path); - } - private static final EnumSet validCheckIndexStates = EnumSet.of( IndexShardState.STARTED, IndexShardState.POST_RECOVERY ); @@ -101,7 +87,7 @@ public class MockFSIndexStore extends IndexStore { Boolean remove = shardSet.remove(indexShard); if (remove == Boolean.TRUE) { Logger logger = Loggers.getLogger(getClass(), indexShard.shardId()); - MockFSDirectoryService.checkIndex(logger, indexShard.store(), indexShard.shardId()); + MockFSDirectoryFactory.checkIndex(logger, indexShard.store(), indexShard.shardId()); } } } @@ -115,5 +101,4 @@ public class MockFSIndexStore extends IndexStore { } } - }