diff --git a/plugins/store-smb/src/main/java/org/elasticsearch/index/store/smb/SmbMmapFsDirectoryFactory.java b/plugins/store-smb/src/main/java/org/elasticsearch/index/store/smb/SmbMmapFsDirectoryFactory.java index b9f4943b1dab6..711cb8178eee0 100644 --- a/plugins/store-smb/src/main/java/org/elasticsearch/index/store/smb/SmbMmapFsDirectoryFactory.java +++ b/plugins/store-smb/src/main/java/org/elasticsearch/index/store/smb/SmbMmapFsDirectoryFactory.java @@ -25,7 +25,7 @@ public final class SmbMmapFsDirectoryFactory extends FsDirectoryFactory { @Override protected Directory newFSDirectory(Path location, LockFactory lockFactory, IndexSettings indexSettings) throws IOException { return new SmbDirectoryWrapper( - setPreload( + setMMapFunctions( new MMapDirectory(location, lockFactory), new HashSet<>(indexSettings.getValue(IndexModule.INDEX_STORE_PRE_LOAD_SETTING)) ) diff --git a/server/src/main/java/org/elasticsearch/index/StandardIOBehaviorHint.java b/server/src/main/java/org/elasticsearch/index/StandardIOBehaviorHint.java new file mode 100644 index 0000000000000..ed32d6def7a32 --- /dev/null +++ b/server/src/main/java/org/elasticsearch/index/StandardIOBehaviorHint.java @@ -0,0 +1,19 @@ +/* + * 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", the "GNU Affero General Public License v3.0 only", and the "Server Side + * Public License v 1"; you may not use this file except in compliance with, at + * your election, the "Elastic License 2.0", the "GNU Affero General Public + * License v3.0 only", or the "Server Side Public License, v 1". + */ + +package org.elasticsearch.index; + +import org.apache.lucene.store.IOContext; + +/** + * A hint that no special behavior should be set on open files + */ +public enum StandardIOBehaviorHint implements IOContext.FileOpenHint { + INSTANCE +} diff --git a/server/src/main/java/org/elasticsearch/index/store/FsDirectoryFactory.java b/server/src/main/java/org/elasticsearch/index/store/FsDirectoryFactory.java index bc1d469ab3486..f02c7b6c16158 100644 --- a/server/src/main/java/org/elasticsearch/index/store/FsDirectoryFactory.java +++ b/server/src/main/java/org/elasticsearch/index/store/FsDirectoryFactory.java @@ -20,12 +20,14 @@ import org.apache.lucene.store.MMapDirectory; import org.apache.lucene.store.NIOFSDirectory; import org.apache.lucene.store.NativeFSLockFactory; +import org.apache.lucene.store.ReadAdvice; import org.apache.lucene.store.SimpleFSLockFactory; import org.elasticsearch.common.settings.Setting; import org.elasticsearch.common.settings.Setting.Property; import org.elasticsearch.core.IOUtils; import org.elasticsearch.index.IndexModule; import org.elasticsearch.index.IndexSettings; +import org.elasticsearch.index.StandardIOBehaviorHint; import org.elasticsearch.index.codec.vectors.es818.DirectIOHint; import org.elasticsearch.index.shard.ShardPath; import org.elasticsearch.logging.LogManager; @@ -36,6 +38,7 @@ import java.nio.file.Files; import java.nio.file.Path; import java.util.HashSet; +import java.util.Optional; import java.util.OptionalLong; import java.util.Set; import java.util.function.BiPredicate; @@ -75,12 +78,12 @@ protected Directory newFSDirectory(Path location, LockFactory lockFactory, Index // Use Lucene defaults final FSDirectory primaryDirectory = FSDirectory.open(location, lockFactory); if (primaryDirectory instanceof MMapDirectory mMapDirectory) { - return new HybridDirectory(lockFactory, setPreload(mMapDirectory, preLoadExtensions)); + return new HybridDirectory(lockFactory, setMMapFunctions(mMapDirectory, preLoadExtensions)); } else { return primaryDirectory; } case MMAPFS: - return setPreload(new MMapDirectory(location, lockFactory), preLoadExtensions); + return setMMapFunctions(new MMapDirectory(location, lockFactory), preLoadExtensions); case SIMPLEFS: case NIOFS: return new NIOFSDirectory(location, lockFactory); @@ -89,10 +92,18 @@ protected Directory newFSDirectory(Path location, LockFactory lockFactory, Index } } + private static Optional overrideReadAdvice(String name, IOContext context) { + if (context.hints().contains(StandardIOBehaviorHint.INSTANCE)) { + return Optional.of(ReadAdvice.NORMAL); + } + return Optional.empty(); + } + /** Sets the preload, if any, on the given directory based on the extensions. Returns the same directory instance. */ // visibility and extensibility for testing - public MMapDirectory setPreload(MMapDirectory mMapDirectory, Set preLoadExtensions) { + public MMapDirectory setMMapFunctions(MMapDirectory mMapDirectory, Set preLoadExtensions) { mMapDirectory.setPreload(getPreloadFunc(preLoadExtensions)); + mMapDirectory.setReadAdviceOverride(FsDirectoryFactory::overrideReadAdvice); return mMapDirectory; } diff --git a/server/src/test/java/org/elasticsearch/index/store/FsDirectoryFactoryTests.java b/server/src/test/java/org/elasticsearch/index/store/FsDirectoryFactoryTests.java index b0a14515f2fbc..83109c4f83a63 100644 --- a/server/src/test/java/org/elasticsearch/index/store/FsDirectoryFactoryTests.java +++ b/server/src/test/java/org/elasticsearch/index/store/FsDirectoryFactoryTests.java @@ -88,7 +88,7 @@ static class PreLoadExposingFsDirectoryFactory extends FsDirectoryFactory { final Map> preLoadFuncMap = new HashMap<>(); @Override - public MMapDirectory setPreload(MMapDirectory mMapDirectory, Set preLoadExtensions) { + public MMapDirectory setMMapFunctions(MMapDirectory mMapDirectory, Set preLoadExtensions) { var preLoadFunc = FsDirectoryFactory.getPreloadFunc(preLoadExtensions); mMapDirectory.setPreload(preLoadFunc); preLoadFuncMap.put(mMapDirectory, preLoadFunc); diff --git a/x-pack/plugin/searchable-snapshots/src/main/java/org/elasticsearch/xpack/searchablesnapshots/store/input/CachedBlobContainerIndexInput.java b/x-pack/plugin/searchable-snapshots/src/main/java/org/elasticsearch/xpack/searchablesnapshots/store/input/CachedBlobContainerIndexInput.java index e54fe892ecaab..f82cba61013df 100644 --- a/x-pack/plugin/searchable-snapshots/src/main/java/org/elasticsearch/xpack/searchablesnapshots/store/input/CachedBlobContainerIndexInput.java +++ b/x-pack/plugin/searchable-snapshots/src/main/java/org/elasticsearch/xpack/searchablesnapshots/store/input/CachedBlobContainerIndexInput.java @@ -9,12 +9,10 @@ import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; -import org.apache.lucene.store.FlushInfo; import org.apache.lucene.store.IOContext; -import org.apache.lucene.store.MergeInfo; -import org.apache.lucene.store.ReadAdvice; import org.elasticsearch.blobcache.BlobCacheUtils; import org.elasticsearch.blobcache.common.ByteRange; +import org.elasticsearch.index.StandardIOBehaviorHint; import org.elasticsearch.index.snapshots.blobstore.BlobStoreIndexShardSnapshot.FileInfo; import org.elasticsearch.xpack.searchablesnapshots.cache.common.CacheFile; import org.elasticsearch.xpack.searchablesnapshots.store.IndexInputStats; @@ -23,8 +21,6 @@ import java.io.IOException; import java.io.InputStream; import java.nio.ByteBuffer; -import java.util.Optional; -import java.util.Set; import java.util.concurrent.atomic.AtomicLong; import java.util.function.Predicate; import java.util.function.Supplier; @@ -40,42 +36,7 @@ public class CachedBlobContainerIndexInput extends MetadataCachingIndexInput { * a complete part of the {@link #fileInfo} at once in the cache and should not be * used for anything else than what the {@link #prefetchPart(int, Supplier)} method does. */ - public static final IOContext CACHE_WARMING_CONTEXT = new IOContext() { - @Override - public Context context() { - return Context.DEFAULT; - } - - @Override - public MergeInfo mergeInfo() { - return null; - } - - @Override - public FlushInfo flushInfo() { - return null; - } - - @Override - public Set hints() { - return Set.of(); - } - - @Override - public IOContext withHints(FileOpenHint... hints) { - return this; - } - - @Override - public Optional readAdvice() { - return Optional.of(ReadAdvice.NORMAL); - } - - @Override - public IOContext withReadAdvice(ReadAdvice advice) { - return this; - } - }; + public static final IOContext CACHE_WARMING_CONTEXT = IOContext.DEFAULT.withHints(StandardIOBehaviorHint.INSTANCE); private static final Logger logger = LogManager.getLogger(CachedBlobContainerIndexInput.class); @@ -141,7 +102,7 @@ private CachedBlobContainerIndexInput( @Override protected void readWithoutBlobCache(ByteBuffer b) throws Exception { - ensureContext(ctx -> ctx != CACHE_WARMING_CONTEXT); + ensureContext(ctx -> ctx.hints().contains(StandardIOBehaviorHint.INSTANCE) == false); final long position = getAbsolutePosition(); final int length = b.remaining(); @@ -178,7 +139,7 @@ public long getPersistentCacheInitialLength() throws Exception { * or {@code -1} if the prewarming was cancelled */ public long prefetchPart(final int part, Supplier isCancelled) throws IOException { - ensureContext(ctx -> ctx == CACHE_WARMING_CONTEXT); + ensureContext(ctx -> ctx.hints().contains(StandardIOBehaviorHint.INSTANCE)); if (part >= fileInfo.numberOfParts()) { throw new IllegalArgumentException("Unexpected part number [" + part + "]"); }