Browse Source

Refactor index engines to manage readers instead of searchers (#43860)

This commit changes the way we manage refreshes in the index engines.
Instead of relying on a SearcherManager, this change uses a ReaderManager that
creates ElasticsearchDirectoryReader when needed. Searchers are now created on-demand
(when acquireSearcher is called) from the current ElasticsearchDirectoryReader.
It also slightly changes the Engine.Searcher to extend IndexSearcher in order
to simplify the usage in the consumer.
Jim Ferenczi 6 years ago
parent
commit
399d53e5c0
36 changed files with 488 additions and 501 deletions
  1. 4 6
      modules/percolator/src/test/java/org/elasticsearch/percolator/PercolatorQuerySearchTests.java
  2. 2 2
      server/src/main/java/org/elasticsearch/index/IndexService.java
  3. 6 8
      server/src/main/java/org/elasticsearch/index/IndexWarmer.java
  4. 4 4
      server/src/main/java/org/elasticsearch/index/cache/bitset/BitsetFilterCache.java
  5. 82 0
      server/src/main/java/org/elasticsearch/index/engine/ElasticsearchReaderManager.java
  6. 43 56
      server/src/main/java/org/elasticsearch/index/engine/Engine.java
  7. 0 48
      server/src/main/java/org/elasticsearch/index/engine/EngineSearcherFactory.java
  8. 79 88
      server/src/main/java/org/elasticsearch/index/engine/InternalEngine.java
  9. 6 13
      server/src/main/java/org/elasticsearch/index/engine/RamAccountingRefreshListener.java
  10. 15 19
      server/src/main/java/org/elasticsearch/index/engine/ReadOnlyEngine.java
  11. 8 12
      server/src/main/java/org/elasticsearch/index/shard/IndexShard.java
  12. 1 1
      server/src/main/java/org/elasticsearch/index/termvectors/TermVectorsService.java
  13. 3 4
      server/src/main/java/org/elasticsearch/search/DefaultSearchContext.java
  14. 2 2
      server/src/main/java/org/elasticsearch/search/SearchService.java
  15. 1 6
      server/src/main/java/org/elasticsearch/search/internal/ContextIndexSearcher.java
  16. 3 3
      server/src/test/java/org/elasticsearch/index/IndexServiceTests.java
  17. 1 1
      server/src/test/java/org/elasticsearch/index/engine/EngineSearcherTotalHitsMatcher.java
  18. 92 93
      server/src/test/java/org/elasticsearch/index/engine/InternalEngineTests.java
  19. 4 4
      server/src/test/java/org/elasticsearch/index/engine/LuceneChangesSnapshotTests.java
  20. 2 2
      server/src/test/java/org/elasticsearch/index/engine/ReadOnlyEngineTests.java
  21. 1 1
      server/src/test/java/org/elasticsearch/index/replication/IndexLevelReplicationTests.java
  22. 1 1
      server/src/test/java/org/elasticsearch/index/search/MultiMatchQueryTests.java
  23. 14 8
      server/src/test/java/org/elasticsearch/index/shard/IndexReaderWrapperTests.java
  24. 1 1
      server/src/test/java/org/elasticsearch/index/shard/IndexShardIT.java
  25. 12 12
      server/src/test/java/org/elasticsearch/index/shard/IndexShardTests.java
  26. 3 3
      server/src/test/java/org/elasticsearch/index/shard/ShardGetServiceTests.java
  27. 11 11
      server/src/test/java/org/elasticsearch/indices/IndicesServiceCloseTests.java
  28. 3 2
      server/src/test/java/org/elasticsearch/search/DefaultSearchContextTests.java
  29. 33 33
      server/src/test/java/org/elasticsearch/search/aggregations/support/ValuesSourceConfigTests.java
  30. 4 4
      test/framework/src/main/java/org/elasticsearch/index/engine/EngineTestCase.java
  31. 1 2
      test/framework/src/main/java/org/elasticsearch/index/shard/IndexShardTestCase.java
  32. 16 24
      test/framework/src/main/java/org/elasticsearch/test/engine/MockEngineSupport.java
  33. 3 2
      test/framework/src/main/java/org/elasticsearch/test/engine/MockInternalEngine.java
  34. 13 11
      x-pack/plugin/core/src/main/java/org/elasticsearch/index/engine/FrozenEngine.java
  35. 8 8
      x-pack/plugin/core/src/test/java/org/elasticsearch/index/engine/FrozenEngineTests.java
  36. 6 6
      x-pack/plugin/core/src/test/java/org/elasticsearch/snapshots/SourceOnlySnapshotShardTests.java

+ 4 - 6
modules/percolator/src/test/java/org/elasticsearch/percolator/PercolatorQuerySearchTests.java

@@ -18,7 +18,6 @@
  */
 package org.elasticsearch.percolator;
 
-import org.apache.lucene.search.IndexSearcher;
 import org.apache.lucene.search.Query;
 import org.apache.lucene.search.join.ScoreMode;
 import org.elasticsearch.action.search.SearchResponse;
@@ -256,11 +255,10 @@ public class PercolatorQuerySearchTests extends ESSingleNodeTestCase {
             .get();
         client().admin().indices().prepareRefresh().get();
 
-        try (Engine.Searcher engineSearcher = indexService.getShard(0).acquireSearcher("test")) {
-            IndexSearcher indexSearcher = engineSearcher.searcher();
+        try (Engine.Searcher searcher = indexService.getShard(0).acquireSearcher("test")) {
             long[] currentTime = new long[] {System.currentTimeMillis()};
             QueryShardContext queryShardContext =
-                indexService.newQueryShardContext(0, engineSearcher.reader(), () -> currentTime[0], null);
+                indexService.newQueryShardContext(0, searcher.getIndexReader(), () -> currentTime[0], null);
 
             BytesReference source = BytesReference.bytes(jsonBuilder().startObject()
                 .field("field1", "value")
@@ -268,7 +266,7 @@ public class PercolatorQuerySearchTests extends ESSingleNodeTestCase {
                 .endObject());
             QueryBuilder queryBuilder = new PercolateQueryBuilder("query", source, XContentType.JSON);
             Query query = queryBuilder.toQuery(queryShardContext);
-            assertThat(indexSearcher.count(query), equalTo(3));
+            assertThat(searcher.count(query), equalTo(3));
 
             currentTime[0] = currentTime[0] + 10800000; // + 3 hours
             source = BytesReference.bytes(jsonBuilder().startObject()
@@ -277,7 +275,7 @@ public class PercolatorQuerySearchTests extends ESSingleNodeTestCase {
                 .endObject());
             queryBuilder = new PercolateQueryBuilder("query", source, XContentType.JSON);
             query = queryBuilder.toQuery(queryShardContext);
-            assertThat(indexSearcher.count(query), equalTo(3));
+            assertThat(searcher.count(query), equalTo(3));
         }
     }
 

+ 2 - 2
server/src/main/java/org/elasticsearch/index/IndexService.java

@@ -398,10 +398,10 @@ public class IndexService extends AbstractIndexComponent implements IndicesClust
 
             logger.debug("creating shard_id {}", shardId);
             // if we are on a shared FS we only own the shard (ie. we can safely delete it) if we are the primary.
-            final Engine.Warmer engineWarmer = (searcher) -> {
+            final Engine.Warmer engineWarmer = (reader) -> {
                 IndexShard shard =  getShardOrNull(shardId.getId());
                 if (shard != null) {
-                    warmer.warm(searcher, shard, IndexService.this.indexSettings);
+                    warmer.warm(reader, shard, IndexService.this.indexSettings);
                 }
             };
             Directory directory = directoryFactory.newDirectory(this.indexSettings, path);

+ 6 - 8
server/src/main/java/org/elasticsearch/index/IndexWarmer.java

@@ -22,9 +22,8 @@ package org.elasticsearch.index;
 import org.apache.logging.log4j.LogManager;
 import org.apache.logging.log4j.Logger;
 import org.apache.logging.log4j.message.ParameterizedMessage;
-import org.apache.lucene.index.DirectoryReader;
+import org.elasticsearch.common.lucene.index.ElasticsearchDirectoryReader;
 import org.elasticsearch.common.unit.TimeValue;
-import org.elasticsearch.index.engine.Engine;
 import org.elasticsearch.index.fielddata.IndexFieldData;
 import org.elasticsearch.index.fielddata.IndexFieldDataService;
 import org.elasticsearch.index.mapper.MappedFieldType;
@@ -58,7 +57,7 @@ public final class IndexWarmer {
         this.listeners = Collections.unmodifiableList(list);
     }
 
-    void warm(Engine.Searcher searcher, IndexShard shard, IndexSettings settings) {
+    void warm(ElasticsearchDirectoryReader reader, IndexShard shard, IndexSettings settings) {
         if (shard.state() == IndexShardState.CLOSED) {
             return;
         }
@@ -66,14 +65,14 @@ public final class IndexWarmer {
             return;
         }
         if (logger.isTraceEnabled()) {
-            logger.trace("{} top warming [{}]", shard.shardId(), searcher.reader());
+            logger.trace("{} top warming [{}]", shard.shardId(), reader);
         }
         shard.warmerService().onPreWarm();
         long time = System.nanoTime();
         final List<TerminationHandle> terminationHandles = new ArrayList<>();
         // get a handle on pending tasks
         for (final Listener listener : listeners) {
-            terminationHandles.add(listener.warmReader(shard, searcher));
+            terminationHandles.add(listener.warmReader(shard, reader));
         }
         // wait for termination
         for (TerminationHandle terminationHandle : terminationHandles) {
@@ -103,7 +102,7 @@ public final class IndexWarmer {
     public interface Listener {
         /** Queue tasks to warm-up the given segments and return handles that allow to wait for termination of the
          *  execution of those tasks. */
-        TerminationHandle warmReader(IndexShard indexShard, Engine.Searcher searcher);
+        TerminationHandle warmReader(IndexShard indexShard, ElasticsearchDirectoryReader reader);
     }
 
     private static class FieldDataWarmer implements IndexWarmer.Listener {
@@ -117,7 +116,7 @@ public final class IndexWarmer {
         }
 
         @Override
-        public TerminationHandle warmReader(final IndexShard indexShard, final Engine.Searcher searcher) {
+        public TerminationHandle warmReader(final IndexShard indexShard, final ElasticsearchDirectoryReader reader) {
             final MapperService mapperService = indexShard.mapperService();
             final Map<String, MappedFieldType> warmUpGlobalOrdinals = new HashMap<>();
             for (MappedFieldType fieldType : mapperService.fieldTypes()) {
@@ -133,7 +132,6 @@ public final class IndexWarmer {
                     try {
                         final long start = System.nanoTime();
                         IndexFieldData.Global ifd = indexFieldDataService.getForField(fieldType);
-                        DirectoryReader reader = searcher.getDirectoryReader();
                         IndexFieldData<?> global = ifd.loadGlobal(reader);
                         if (reader.leaves().isEmpty() == false) {
                             global.load(reader.leaves().get(0));

+ 4 - 4
server/src/main/java/org/elasticsearch/index/cache/bitset/BitsetFilterCache.java

@@ -38,6 +38,7 @@ import org.elasticsearch.common.cache.Cache;
 import org.elasticsearch.common.cache.CacheBuilder;
 import org.elasticsearch.common.cache.RemovalListener;
 import org.elasticsearch.common.cache.RemovalNotification;
+import org.elasticsearch.common.lucene.index.ElasticsearchDirectoryReader;
 import org.elasticsearch.common.lucene.search.Queries;
 import org.elasticsearch.common.settings.Setting;
 import org.elasticsearch.common.settings.Setting.Property;
@@ -46,7 +47,6 @@ import org.elasticsearch.index.AbstractIndexComponent;
 import org.elasticsearch.index.IndexSettings;
 import org.elasticsearch.index.IndexWarmer;
 import org.elasticsearch.index.IndexWarmer.TerminationHandle;
-import org.elasticsearch.index.engine.Engine;
 import org.elasticsearch.index.mapper.DocumentMapper;
 import org.elasticsearch.index.mapper.MapperService;
 import org.elasticsearch.index.mapper.ObjectMapper;
@@ -222,7 +222,7 @@ public final class BitsetFilterCache extends AbstractIndexComponent
         }
 
         @Override
-        public IndexWarmer.TerminationHandle warmReader(final IndexShard indexShard, final Engine.Searcher searcher) {
+        public IndexWarmer.TerminationHandle warmReader(final IndexShard indexShard, final ElasticsearchDirectoryReader reader) {
             if (indexSettings.getIndex().equals(indexShard.indexSettings().getIndex()) == false) {
                 // this is from a different index
                 return TerminationHandle.NO_WAIT;
@@ -254,8 +254,8 @@ public final class BitsetFilterCache extends AbstractIndexComponent
                 warmUp.add(Queries.newNonNestedFilter());
             }
 
-            final CountDownLatch latch = new CountDownLatch(searcher.reader().leaves().size() * warmUp.size());
-            for (final LeafReaderContext ctx : searcher.reader().leaves()) {
+            final CountDownLatch latch = new CountDownLatch(reader.leaves().size() * warmUp.size());
+            for (final LeafReaderContext ctx : reader.leaves()) {
                 for (final Query filterToWarm : warmUp) {
                     executor.execute(() -> {
                         try {

+ 82 - 0
server/src/main/java/org/elasticsearch/index/engine/ElasticsearchReaderManager.java

@@ -0,0 +1,82 @@
+/*
+ * 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.engine;
+
+import java.io.IOException;
+import java.util.function.BiConsumer;
+
+import org.apache.lucene.index.DirectoryReader;
+import org.apache.lucene.search.ReferenceManager;
+
+import org.apache.lucene.search.SearcherManager;
+import org.elasticsearch.common.SuppressForbidden;
+import org.elasticsearch.common.lucene.index.ElasticsearchDirectoryReader;
+
+/**
+ * Utility class to safely share {@link ElasticsearchDirectoryReader} instances across
+ * multiple threads, while periodically reopening. This class ensures each
+ * reader is closed only once all threads have finished using it.
+ *
+ * @see SearcherManager
+ *
+ */
+@SuppressForbidden(reason = "reference counting is required here")
+class ElasticsearchReaderManager extends ReferenceManager<ElasticsearchDirectoryReader> {
+    private final BiConsumer<ElasticsearchDirectoryReader, ElasticsearchDirectoryReader> refreshListener;
+
+    /**
+     * Creates and returns a new ElasticsearchReaderManager from the given
+     * already-opened {@link ElasticsearchDirectoryReader}, stealing
+     * the incoming reference.
+     *
+     * @param reader            the directoryReader to use for future reopens
+     * @param refreshListener   A consumer that is called every time a new reader is opened
+     */
+    ElasticsearchReaderManager(ElasticsearchDirectoryReader reader,
+                               BiConsumer<ElasticsearchDirectoryReader, ElasticsearchDirectoryReader> refreshListener) {
+        this.current = reader;
+        this.refreshListener = refreshListener;
+        refreshListener.accept(current, null);
+    }
+
+    @Override
+    protected void decRef(ElasticsearchDirectoryReader reference) throws IOException {
+        reference.decRef();
+    }
+
+    @Override
+    protected ElasticsearchDirectoryReader refreshIfNeeded(ElasticsearchDirectoryReader referenceToRefresh) throws IOException {
+        final ElasticsearchDirectoryReader reader = (ElasticsearchDirectoryReader) DirectoryReader.openIfChanged(referenceToRefresh);
+        if (reader != null) {
+            refreshListener.accept(reader, referenceToRefresh);
+        }
+        return reader;
+    }
+
+    @Override
+    protected boolean tryIncRef(ElasticsearchDirectoryReader reference) {
+        return reference.tryIncRef();
+    }
+
+    @Override
+    protected int getRefCount(ElasticsearchDirectoryReader reference) {
+        return reference.getRefCount();
+    }
+}

+ 43 - 56
server/src/main/java/org/elasticsearch/index/engine/Engine.java

@@ -27,7 +27,6 @@ import org.apache.lucene.index.FieldInfo;
 import org.apache.lucene.index.IndexCommit;
 import org.apache.lucene.index.IndexFileNames;
 import org.apache.lucene.index.IndexReader;
-import org.apache.lucene.index.IndexWriter;
 import org.apache.lucene.index.LeafReader;
 import org.apache.lucene.index.LeafReaderContext;
 import org.apache.lucene.index.SegmentCommitInfo;
@@ -36,7 +35,10 @@ import org.apache.lucene.index.SegmentReader;
 import org.apache.lucene.index.Term;
 import org.apache.lucene.index.Terms;
 import org.apache.lucene.search.IndexSearcher;
+import org.apache.lucene.search.QueryCache;
+import org.apache.lucene.search.QueryCachingPolicy;
 import org.apache.lucene.search.ReferenceManager;
+import org.apache.lucene.search.similarities.Similarity;
 import org.apache.lucene.search.suggest.document.CompletionTerms;
 import org.apache.lucene.store.AlreadyClosedException;
 import org.apache.lucene.store.Directory;
@@ -58,6 +60,7 @@ import org.elasticsearch.common.lease.Releasable;
 import org.elasticsearch.common.lease.Releasables;
 import org.elasticsearch.common.logging.Loggers;
 import org.elasticsearch.common.lucene.Lucene;
+import org.elasticsearch.common.lucene.index.ElasticsearchDirectoryReader;
 import org.elasticsearch.common.lucene.uid.Versions;
 import org.elasticsearch.common.lucene.uid.VersionsAndSeqNoResolver;
 import org.elasticsearch.common.lucene.uid.VersionsAndSeqNoResolver.DocIdAndVersion;
@@ -162,18 +165,6 @@ public abstract class Engine implements Closeable {
         return a.ramBytesUsed();
     }
 
-    /**
-     * Returns whether a leaf reader comes from a merge (versus flush or addIndexes).
-     */
-    protected static boolean isMergedSegment(LeafReader reader) {
-        // We expect leaves to be segment readers
-        final Map<String, String> diagnostics = Lucene.segmentReader(reader).getSegmentInfo().info.getDiagnostics();
-        final String source = diagnostics.get(IndexWriter.SOURCE);
-        assert Arrays.asList(IndexWriter.SOURCE_ADDINDEXES_READERS, IndexWriter.SOURCE_FLUSH,
-                IndexWriter.SOURCE_MERGE).contains(source) : "Unknown source " + source;
-        return IndexWriter.SOURCE_MERGE.equals(source);
-    }
-
     public final EngineConfig config() {
         return engineConfig;
     }
@@ -194,13 +185,13 @@ public abstract class Engine implements Closeable {
      * Returns the {@link CompletionStats} for this engine
      */
     public CompletionStats completionStats(String... fieldNamePatterns) throws IOException {
-        try (Engine.Searcher currentSearcher = acquireSearcher("completion_stats", SearcherScope.INTERNAL)) {
+        try (Searcher currentSearcher = acquireSearcher("completion_stats", SearcherScope.INTERNAL)) {
             long sizeInBytes = 0;
             ObjectLongHashMap<String> completionFields = null;
             if (fieldNamePatterns != null && fieldNamePatterns.length > 0) {
                 completionFields = new ObjectLongHashMap<>(fieldNamePatterns.length);
             }
-            for (LeafReaderContext atomicReaderContext : currentSearcher.reader().leaves()) {
+            for (LeafReaderContext atomicReaderContext : currentSearcher.getIndexReader().leaves()) {
                 LeafReader atomicReader = atomicReaderContext.reader();
                 for (FieldInfo info : atomicReader.getFieldInfos()) {
                     Terms terms = atomicReader.terms(info.name);
@@ -222,13 +213,13 @@ public abstract class Engine implements Closeable {
      * Returns the {@link DocsStats} for this engine
      */
     public DocsStats docStats() {
-        // we calculate the doc stats based on the internal reader that is more up-to-date and not subject
-        // to external refreshes. For instance we don't refresh an external reader if we flush and indices with
+        // we calculate the doc stats based on the internal searcher that is more up-to-date and not subject
+        // to external refreshes. For instance we don't refresh an external searcher if we flush and indices with
         // index.refresh_interval=-1 won't see any doc stats updates at all. This change will give more accurate statistics
-        // when indexing but not refreshing in general. Yet, if a refresh happens the internal reader is refresh as well so we are
+        // when indexing but not refreshing in general. Yet, if a refresh happens the internal searcher is refresh as well so we are
         // safe here.
-        try (Engine.Searcher searcher = acquireSearcher("docStats", Engine.SearcherScope.INTERNAL)) {
-           return docsStats(searcher.reader());
+        try (Searcher searcher = acquireSearcher("docStats", SearcherScope.INTERNAL)) {
+           return docsStats(searcher.getIndexReader());
         }
     }
 
@@ -607,12 +598,12 @@ public abstract class Engine implements Closeable {
         PENDING_OPERATIONS
     }
 
-    protected final GetResult getFromSearcher(Get get, BiFunction<String, SearcherScope, Searcher> searcherFactory,
-                                              SearcherScope scope) throws EngineException {
-        final Searcher searcher = searcherFactory.apply("get", scope);
+    protected final GetResult getFromSearcher(Get get, BiFunction<String, SearcherScope, Engine.Searcher> searcherFactory,
+                                                SearcherScope scope) throws EngineException {
+        final Engine.Searcher searcher = searcherFactory.apply("get", scope);
         final DocIdAndVersion docIdAndVersion;
         try {
-            docIdAndVersion = VersionsAndSeqNoResolver.loadDocIdAndVersion(searcher.reader(), get.uid(), true);
+            docIdAndVersion = VersionsAndSeqNoResolver.loadDocIdAndVersion(searcher.getIndexReader(), get.uid(), true);
         } catch (Exception e) {
             Releasables.closeWhileHandlingException(searcher);
             //TODO: A better exception goes here
@@ -679,10 +670,11 @@ public abstract class Engine implements Closeable {
         }
         Releasable releasable = store::decRef;
         try {
-            ReferenceManager<IndexSearcher> referenceManager = getReferenceManager(scope);
-            IndexSearcher acquire = referenceManager.acquire();
+            ReferenceManager<ElasticsearchDirectoryReader> referenceManager = getReferenceManager(scope);
+            final ElasticsearchDirectoryReader acquire = referenceManager.acquire();
             AtomicBoolean released = new AtomicBoolean(false);
             Searcher engineSearcher = new Searcher(source, acquire,
+                engineConfig.getSimilarity(), engineConfig.getQueryCache(), engineConfig.getQueryCachingPolicy(),
                 () -> {
                 if (released.compareAndSet(false, true)) {
                     try {
@@ -691,13 +683,13 @@ public abstract class Engine implements Closeable {
                         store.decRef();
                     }
                 } else {
-                    /* In general, searchers should never be released twice or this would break reference counting. There is one rare case
+                    /* In general, readers should never be released twice or this would break reference counting. There is one rare case
                      * when it might happen though: when the request and the Reaper thread would both try to release it in a very short
                      * amount of time, this is why we only log a warning instead of throwing an exception. */
                     logger.warn("Searcher was released twice", new IllegalStateException("Double release"));
                 }
               });
-            releasable = null; // success - hand over the reference to the engine searcher
+            releasable = null; // success - hand over the reference to the engine reader
             return engineSearcher;
         } catch (AlreadyClosedException ex) {
             throw ex;
@@ -711,7 +703,7 @@ public abstract class Engine implements Closeable {
         }
     }
 
-    protected abstract ReferenceManager<IndexSearcher> getReferenceManager(SearcherScope scope);
+    protected abstract ReferenceManager<ElasticsearchDirectoryReader> getReferenceManager(SearcherScope scope);
 
     public enum SearcherScope {
         EXTERNAL, INTERNAL
@@ -815,7 +807,7 @@ public abstract class Engine implements Closeable {
         Set<String> segmentName = new HashSet<>();
         SegmentsStats stats = new SegmentsStats();
         try (Searcher searcher = acquireSearcher("segments_stats", SearcherScope.INTERNAL)) {
-            for (LeafReaderContext ctx : searcher.reader().getContext().leaves()) {
+            for (LeafReaderContext ctx : searcher.getIndexReader().getContext().leaves()) {
                 SegmentReader segmentReader = Lucene.segmentReader(ctx.reader());
                 fillSegmentStats(segmentReader, includeSegmentFileSizes, stats);
                 segmentName.add(segmentReader.getSegmentName());
@@ -823,7 +815,7 @@ public abstract class Engine implements Closeable {
         }
 
         try (Searcher searcher = acquireSearcher("segments_stats", SearcherScope.EXTERNAL)) {
-            for (LeafReaderContext ctx : searcher.reader().getContext().leaves()) {
+            for (LeafReaderContext ctx : searcher.getIndexReader().getContext().leaves()) {
                 SegmentReader segmentReader = Lucene.segmentReader(ctx.reader());
                 if (segmentName.contains(segmentReader.getSegmentName()) == false) {
                     fillSegmentStats(segmentReader, includeSegmentFileSizes, stats);
@@ -938,13 +930,13 @@ public abstract class Engine implements Closeable {
         Map<String, Segment> segments = new HashMap<>();
         // first, go over and compute the search ones...
         try (Searcher searcher = acquireSearcher("segments", SearcherScope.EXTERNAL)){
-            for (LeafReaderContext ctx : searcher.reader().getContext().leaves()) {
+            for (LeafReaderContext ctx : searcher.getIndexReader().getContext().leaves()) {
                 fillSegmentInfo(Lucene.segmentReader(ctx.reader()), verbose, true, segments);
             }
         }
 
         try (Searcher searcher = acquireSearcher("segments", SearcherScope.INTERNAL)){
-            for (LeafReaderContext ctx : searcher.reader().getContext().leaves()) {
+            for (LeafReaderContext ctx : searcher.getIndexReader().getContext().leaves()) {
                 SegmentReader segmentReader = Lucene.segmentReader(ctx.reader());
                 if (segments.containsKey(segmentReader.getSegmentName()) == false) {
                     fillSegmentInfo(segmentReader, verbose, false, segments);
@@ -1222,14 +1214,18 @@ public abstract class Engine implements Closeable {
         }
     }
 
-    public static final class Searcher implements Releasable {
+    public static final class Searcher extends IndexSearcher implements Releasable {
         private final String source;
-        private final IndexSearcher searcher;
         private final Closeable onClose;
 
-        public Searcher(String source, IndexSearcher searcher, Closeable onClose) {
+        public Searcher(String source, IndexReader reader,
+                        Similarity similarity, QueryCache queryCache, QueryCachingPolicy queryCachingPolicy,
+                        Closeable onClose) {
+            super(reader);
+            setSimilarity(similarity);
+            setQueryCache(queryCache);
+            setQueryCachingPolicy(queryCachingPolicy);
             this.source = source;
-            this.searcher = searcher;
             this.onClose = onClose;
         }
 
@@ -1240,19 +1236,11 @@ public abstract class Engine implements Closeable {
             return source;
         }
 
-        public IndexReader reader() {
-            return searcher.getIndexReader();
-        }
-
         public DirectoryReader getDirectoryReader() {
-            if (reader() instanceof DirectoryReader) {
-                return (DirectoryReader) reader();
+            if (getIndexReader() instanceof DirectoryReader) {
+                return (DirectoryReader) getIndexReader();
             }
-            throw new IllegalStateException("Can't use " + reader().getClass() + " as a directory reader");
-        }
-
-        public IndexSearcher searcher() {
-            return searcher;
+            throw new IllegalStateException("Can't use " + getIndexReader().getClass() + " as a directory reader");
         }
 
         @Override
@@ -1266,7 +1254,6 @@ public abstract class Engine implements Closeable {
                 throw new AssertionError(e);
             }
         }
-
     }
 
     public abstract static class Operation {
@@ -1647,11 +1634,11 @@ public abstract class Engine implements Closeable {
         private final boolean exists;
         private final long version;
         private final DocIdAndVersion docIdAndVersion;
-        private final Searcher searcher;
+        private final Engine.Searcher searcher;
 
         public static final GetResult NOT_EXISTS = new GetResult(false, Versions.NOT_FOUND, null, null);
 
-        private GetResult(boolean exists, long version, DocIdAndVersion docIdAndVersion, Searcher searcher) {
+        private GetResult(boolean exists, long version, DocIdAndVersion docIdAndVersion, Engine.Searcher searcher) {
             this.exists = exists;
             this.version = version;
             this.docIdAndVersion = docIdAndVersion;
@@ -1661,7 +1648,7 @@ public abstract class Engine implements Closeable {
         /**
          * Build a non-realtime get result from the searcher.
          */
-        public GetResult(Searcher searcher, DocIdAndVersion docIdAndVersion) {
+        public GetResult(Engine.Searcher searcher, DocIdAndVersion docIdAndVersion) {
             this(true, docIdAndVersion.version, docIdAndVersion, searcher);
         }
 
@@ -1673,7 +1660,7 @@ public abstract class Engine implements Closeable {
             return this.version;
         }
 
-        public Searcher searcher() {
+        public Engine.Searcher searcher() {
             return this.searcher;
         }
 
@@ -1830,15 +1817,15 @@ public abstract class Engine implements Closeable {
     }
 
     /**
-     * Called for each new opened engine searcher to warm new segments
+     * Called for each new opened engine reader to warm new segments
      *
      * @see EngineConfig#getWarmer()
      */
     public interface Warmer {
         /**
-         * Called once a new Searcher is opened on the top-level searcher.
+         * Called once a new top-level reader is opened.
          */
-        void warm(Engine.Searcher searcher);
+        void warm(ElasticsearchDirectoryReader reader);
     }
 
     /**

+ 0 - 48
server/src/main/java/org/elasticsearch/index/engine/EngineSearcherFactory.java

@@ -1,48 +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.engine;
-
-import org.apache.lucene.index.IndexReader;
-import org.apache.lucene.search.IndexSearcher;
-import org.apache.lucene.search.SearcherFactory;
-
-import java.io.IOException;
-
-/**
- * Basic Searcher factory that allows returning an {@link IndexSearcher}
- * given an {@link IndexReader}
- */
-public class EngineSearcherFactory extends SearcherFactory {
-
-    private final EngineConfig engineConfig;
-
-    public EngineSearcherFactory(EngineConfig engineConfig) {
-        this.engineConfig = engineConfig;
-    }
-
-    @Override
-    public IndexSearcher newSearcher(IndexReader reader, IndexReader previousReader) throws IOException {
-        IndexSearcher searcher = super.newSearcher(reader, previousReader);
-        searcher.setQueryCache(engineConfig.getQueryCache());
-        searcher.setQueryCachingPolicy(engineConfig.getQueryCachingPolicy());
-        searcher.setSimilarity(engineConfig.getSimilarity());
-        return searcher;
-    }
-}

+ 79 - 88
server/src/main/java/org/elasticsearch/index/engine/InternalEngine.java

@@ -31,7 +31,6 @@ import org.apache.lucene.index.IndexReader;
 import org.apache.lucene.index.IndexWriter;
 import org.apache.lucene.index.IndexWriterConfig;
 import org.apache.lucene.index.IndexableField;
-import org.apache.lucene.index.LeafReader;
 import org.apache.lucene.index.LeafReaderContext;
 import org.apache.lucene.index.LiveIndexWriterConfig;
 import org.apache.lucene.index.MergePolicy;
@@ -45,8 +44,6 @@ import org.apache.lucene.search.Query;
 import org.apache.lucene.search.ReferenceManager;
 import org.apache.lucene.search.ScoreMode;
 import org.apache.lucene.search.Scorer;
-import org.apache.lucene.search.SearcherFactory;
-import org.apache.lucene.search.SearcherManager;
 import org.apache.lucene.search.TermQuery;
 import org.apache.lucene.search.Weight;
 import org.apache.lucene.store.AlreadyClosedException;
@@ -115,6 +112,7 @@ import java.util.concurrent.atomic.AtomicInteger;
 import java.util.concurrent.atomic.AtomicLong;
 import java.util.concurrent.locks.Lock;
 import java.util.concurrent.locks.ReentrantLock;
+import java.util.function.BiConsumer;
 import java.util.function.BiFunction;
 import java.util.function.LongConsumer;
 import java.util.function.LongSupplier;
@@ -133,8 +131,8 @@ public class InternalEngine extends Engine {
 
     private final IndexWriter indexWriter;
 
-    private final ExternalSearcherManager externalSearcherManager;
-    private final SearcherManager internalSearcherManager;
+    private final ExternalReaderManager externalReaderManager;
+    private final ElasticsearchReaderManager internalReaderManager;
 
     private final Lock flushLock = new ReentrantLock();
     private final ReentrantLock optimizeLock = new ReentrantLock();
@@ -195,8 +193,8 @@ public class InternalEngine extends Engine {
         store.incRef();
         IndexWriter writer = null;
         Translog translog = null;
-        ExternalSearcherManager externalSearcherManager = null;
-        SearcherManager internalSearcherManager = null;
+        ExternalReaderManager externalReaderManager = null;
+        ElasticsearchReaderManager internalReaderManager = null;
         EngineMergeScheduler scheduler = null;
         boolean success = false;
         try {
@@ -235,25 +233,26 @@ public class InternalEngine extends Engine {
                     throw e;
                 }
             }
-            externalSearcherManager = createSearcherManager(new SearchFactory(logger, isClosed, engineConfig));
-            internalSearcherManager = externalSearcherManager.internalSearcherManager;
-            this.internalSearcherManager = internalSearcherManager;
-            this.externalSearcherManager = externalSearcherManager;
-            internalSearcherManager.addListener(versionMap);
+            externalReaderManager = createReaderManager(new RefreshWarmerListener(logger, isClosed, engineConfig));
+            internalReaderManager = externalReaderManager.internalReaderManager;
+            this.internalReaderManager = internalReaderManager;
+            this.externalReaderManager = externalReaderManager;
+            internalReaderManager.addListener(versionMap);
             assert pendingTranslogRecovery.get() == false : "translog recovery can't be pending before we set it";
             // don't allow commits until we are done with recovering
             pendingTranslogRecovery.set(true);
             for (ReferenceManager.RefreshListener listener: engineConfig.getExternalRefreshListener()) {
-                this.externalSearcherManager.addListener(listener);
+                this.externalReaderManager.addListener(listener);
             }
             for (ReferenceManager.RefreshListener listener: engineConfig.getInternalRefreshListener()) {
-                this.internalSearcherManager.addListener(listener);
+                this.internalReaderManager.addListener(listener);
             }
             this.lastRefreshedCheckpointListener = new LastRefreshedCheckpointListener(localCheckpointTracker.getProcessedCheckpoint());
-            this.internalSearcherManager.addListener(lastRefreshedCheckpointListener);
+            this.internalReaderManager.addListener(lastRefreshedCheckpointListener);
             maxSeqNoOfUpdatesOrDeletes = new AtomicLong(SequenceNumbers.max(localCheckpointTracker.getMaxSeqNo(), translog.getMaxSeqNo()));
             if (softDeleteEnabled && localCheckpointTracker.getPersistedCheckpoint() < localCheckpointTracker.getMaxSeqNo()) {
-                try (Searcher searcher = acquireSearcher("restore_version_map_and_checkpoint_tracker", SearcherScope.INTERNAL)) {
+                try (Searcher searcher =
+                         acquireSearcher("restore_version_map_and_checkpoint_tracker", SearcherScope.INTERNAL)) {
                     restoreVersionMapAndCheckpointTracker(Lucene.wrapAllDocsLive(searcher.getDirectoryReader()));
                 } catch (IOException e) {
                     throw new EngineCreationFailureException(config().getShardId(),
@@ -263,7 +262,7 @@ public class InternalEngine extends Engine {
             success = true;
         } finally {
             if (success == false) {
-                IOUtils.closeWhileHandlingException(writer, translog, internalSearcherManager, externalSearcherManager, scheduler);
+                IOUtils.closeWhileHandlingException(writer, translog, internalReaderManager, externalReaderManager, scheduler);
                 if (isClosed.get() == false) {
                     // failure we need to dec the store reference
                     store.decRef();
@@ -301,7 +300,7 @@ public class InternalEngine extends Engine {
     }
 
     /**
-     * This reference manager delegates all it's refresh calls to another (internal) SearcherManager
+     * This reference manager delegates all it's refresh calls to another (internal) ReaderManager
      * The main purpose for this is that if we have external refreshes happening we don't issue extra
      * refreshes to clear version map memory etc. this can cause excessive segment creation if heavy indexing
      * is happening and the refresh interval is low (ie. 1 sec)
@@ -312,62 +311,64 @@ public class InternalEngine extends Engine {
      * and old segments can be released in the same way previous version did this (as a side-effect of _refresh)
      */
     @SuppressForbidden(reason = "reference counting is required here")
-    private static final class ExternalSearcherManager extends ReferenceManager<IndexSearcher> {
-        private final SearcherFactory searcherFactory;
-        private final SearcherManager internalSearcherManager;
-
-        ExternalSearcherManager(SearcherManager internalSearcherManager, SearcherFactory searcherFactory) throws IOException {
-            IndexSearcher acquire = internalSearcherManager.acquire();
+    private static final class ExternalReaderManager extends ReferenceManager<ElasticsearchDirectoryReader> {
+        private final BiConsumer<ElasticsearchDirectoryReader, ElasticsearchDirectoryReader> refreshListener;
+        private final ElasticsearchReaderManager internalReaderManager;
+
+        ExternalReaderManager(ElasticsearchReaderManager internalReaderManager,
+                              BiConsumer<ElasticsearchDirectoryReader, ElasticsearchDirectoryReader> refreshListener) throws IOException {
+            this.refreshListener = refreshListener;
+            this.internalReaderManager = internalReaderManager;
+            ElasticsearchDirectoryReader acquire = internalReaderManager.acquire();
             try {
-                IndexReader indexReader = acquire.getIndexReader();
-                assert indexReader instanceof ElasticsearchDirectoryReader:
-                    "searcher's IndexReader should be an ElasticsearchDirectoryReader, but got " + indexReader;
-                indexReader.incRef(); // steal the reader - getSearcher will decrement if it fails
-                current = SearcherManager.getSearcher(searcherFactory, indexReader, null);
+                incrementAndNotify(acquire, null);
+                current = acquire;
             } finally {
-                internalSearcherManager.release(acquire);
+                internalReaderManager.release(acquire);
             }
-            this.searcherFactory = searcherFactory;
-            this.internalSearcherManager = internalSearcherManager;
         }
 
         @Override
-        protected IndexSearcher refreshIfNeeded(IndexSearcher referenceToRefresh) throws IOException {
+        protected ElasticsearchDirectoryReader refreshIfNeeded(ElasticsearchDirectoryReader referenceToRefresh) throws IOException {
             // we simply run a blocking refresh on the internal reference manager and then steal it's reader
             // it's a save operation since we acquire the reader which incs it's reference but then down the road
             // steal it by calling incRef on the "stolen" reader
-            internalSearcherManager.maybeRefreshBlocking();
-            IndexSearcher acquire = internalSearcherManager.acquire();
+            internalReaderManager.maybeRefreshBlocking();
+            ElasticsearchDirectoryReader acquire = internalReaderManager.acquire();
             try {
-                final IndexReader previousReader = referenceToRefresh.getIndexReader();
-                assert previousReader instanceof ElasticsearchDirectoryReader:
-                    "searcher's IndexReader should be an ElasticsearchDirectoryReader, but got " + previousReader;
-
-                final IndexReader newReader = acquire.getIndexReader();
-                if (newReader == previousReader) {
+                if (acquire == referenceToRefresh) {
                     // nothing has changed - both ref managers share the same instance so we can use reference equality
                     return null;
                 } else {
-                    newReader.incRef(); // steal the reader - getSearcher will decrement if it fails
-                    return SearcherManager.getSearcher(searcherFactory, newReader, previousReader);
+                    incrementAndNotify(acquire, referenceToRefresh);
+                    return acquire;
                 }
             } finally {
-                internalSearcherManager.release(acquire);
+                internalReaderManager.release(acquire);
+            }
+        }
+
+        private void incrementAndNotify(ElasticsearchDirectoryReader reader,
+                                            ElasticsearchDirectoryReader previousReader) throws IOException {
+            reader.incRef(); // steal the reference
+            try (Closeable c = reader::decRef) {
+                refreshListener.accept(reader, previousReader);
+                reader.incRef(); // double inc-ref if we were successful
             }
         }
 
         @Override
-        protected boolean tryIncRef(IndexSearcher reference) {
-            return reference.getIndexReader().tryIncRef();
+        protected boolean tryIncRef(ElasticsearchDirectoryReader reference) {
+            return reference.tryIncRef();
         }
 
         @Override
-        protected int getRefCount(IndexSearcher reference) {
-            return reference.getIndexReader().getRefCount();
+        protected int getRefCount(ElasticsearchDirectoryReader reference) {
+            return reference.getRefCount();
         }
 
         @Override
-        protected void decRef(IndexSearcher reference) throws IOException { reference.getIndexReader().decRef(); }
+        protected void decRef(ElasticsearchDirectoryReader reference) throws IOException { reference.decRef(); }
     }
 
     @Override
@@ -586,19 +587,19 @@ public class InternalEngine extends Engine {
         return uuid;
     }
 
-    private ExternalSearcherManager createSearcherManager(SearchFactory externalSearcherFactory) throws EngineException {
+    private ExternalReaderManager createReaderManager(RefreshWarmerListener externalRefreshListener) throws EngineException {
         boolean success = false;
-        SearcherManager internalSearcherManager = null;
+        ElasticsearchReaderManager internalReaderManager = null;
         try {
             try {
-                final DirectoryReader directoryReader = ElasticsearchDirectoryReader.wrap(DirectoryReader.open(indexWriter), shardId);
-                internalSearcherManager = new SearcherManager(directoryReader,
-                        new RamAccountingSearcherFactory(engineConfig.getCircuitBreakerService()));
+                final ElasticsearchDirectoryReader directoryReader =
+                    ElasticsearchDirectoryReader.wrap(DirectoryReader.open(indexWriter), shardId);
+                internalReaderManager = new ElasticsearchReaderManager(directoryReader,
+                       new RamAccountingRefreshListener(engineConfig.getCircuitBreakerService()));
                 lastCommittedSegmentInfos = store.readLastCommittedSegmentsInfo();
-                ExternalSearcherManager externalSearcherManager = new ExternalSearcherManager(internalSearcherManager,
-                    externalSearcherFactory);
+                ExternalReaderManager externalReaderManager = new ExternalReaderManager(internalReaderManager, externalRefreshListener);
                 success = true;
-                return externalSearcherManager;
+                return externalReaderManager;
             } catch (IOException e) {
                 maybeFailEngine("start", e);
                 try {
@@ -610,13 +611,13 @@ public class InternalEngine extends Engine {
             }
         } finally {
             if (success == false) { // release everything we created on a failure
-                IOUtils.closeWhileHandlingException(internalSearcherManager, indexWriter);
+                IOUtils.closeWhileHandlingException(internalReaderManager, indexWriter);
             }
         }
     }
 
     @Override
-    public GetResult get(Get get, BiFunction<String, SearcherScope, Searcher> searcherFactory) throws EngineException {
+    public GetResult get(Get get, BiFunction<String, SearcherScope, Engine.Searcher> searcherFactory) throws EngineException {
         assert Objects.equals(get.uid().field(), IdFieldMapper.NAME) : get.uid().field();
         try (ReleasableLock ignored = readLock.acquire()) {
             ensureOpen();
@@ -651,7 +652,8 @@ public class InternalEngine extends Engine {
                                     // in the case of a already pruned translog generation we might get null here - yet very unlikely
                                     final Translog.Index index = (Translog.Index) operation;
                                     TranslogLeafReader reader = new TranslogLeafReader(index);
-                                    return new GetResult(new Searcher("realtime_get", new IndexSearcher(reader), reader),
+                                    return new GetResult(new Engine.Searcher("realtime_get", reader,
+                                        IndexSearcher.getDefaultSimilarity(), null, IndexSearcher.getDefaultQueryCachingPolicy(), reader),
                                         new VersionsAndSeqNoResolver.DocIdAndVersion(0, index.version(), index.seqNo(), index.primaryTerm(),
                                             reader, 0));
                                 }
@@ -713,7 +715,7 @@ public class InternalEngine extends Engine {
             // load from index
             assert incrementIndexVersionLookup();
             try (Searcher searcher = acquireSearcher("load_seq_no", SearcherScope.INTERNAL)) {
-                final DocIdAndSeqNo docAndSeqNo = VersionsAndSeqNoResolver.loadDocIdAndSeqNo(searcher.reader(), op.uid());
+                final DocIdAndSeqNo docAndSeqNo = VersionsAndSeqNoResolver.loadDocIdAndSeqNo(searcher.getIndexReader(), op.uid());
                 if (docAndSeqNo == null) {
                     status = OpVsLuceneDocStatus.LUCENE_DOC_NOT_FOUND;
                 } else if (op.seqNo() > docAndSeqNo.seqNo) {
@@ -738,7 +740,7 @@ public class InternalEngine extends Engine {
             assert incrementIndexVersionLookup(); // used for asserting in tests
             final VersionsAndSeqNoResolver.DocIdAndVersion docIdAndVersion;
             try (Searcher searcher = acquireSearcher("load_version", SearcherScope.INTERNAL)) {
-                 docIdAndVersion = VersionsAndSeqNoResolver.loadDocIdAndVersion(searcher.reader(), op.uid(), loadSeqNo);
+                 docIdAndVersion = VersionsAndSeqNoResolver.loadDocIdAndVersion(searcher.getIndexReader(), op.uid(), loadSeqNo);
             }
             if (docIdAndVersion != null) {
                 versionValue = new IndexVersionValue(null, docIdAndVersion.version, docIdAndVersion.seqNo, docIdAndVersion.primaryTerm);
@@ -1214,7 +1216,7 @@ public class InternalEngine extends Engine {
             }
         } else {
             try (Searcher searcher = acquireSearcher("assert doc doesn't exist", SearcherScope.INTERNAL)) {
-                final long docsWithId = searcher.searcher().count(new TermQuery(index.uid()));
+                final long docsWithId = searcher.count(new TermQuery(index.uid()));
                 if (docsWithId > 0) {
                     throw new AssertionError("doc [" + index.type() + "][" + index.id() + "] exists [" + docsWithId +
                         "] times in index");
@@ -1567,7 +1569,7 @@ public class InternalEngine extends Engine {
                 try {
                     // even though we maintain 2 managers we really do the heavy-lifting only once.
                     // the second refresh will only do the extra work we have to do for warming caches etc.
-                    ReferenceManager<IndexSearcher> referenceManager = getReferenceManager(scope);
+                    ReferenceManager<ElasticsearchDirectoryReader> referenceManager = getReferenceManager(scope);
                     // it is intentional that we never refresh both internal / external together
                     if (block) {
                         referenceManager.maybeRefreshBlocking();
@@ -1669,7 +1671,7 @@ public class InternalEngine extends Engine {
         }
         if (renewed) {
             // refresh outside of the write lock
-            // we have to refresh internal searcher here to ensure we release unreferenced segments.
+            // we have to refresh internal reader here to ensure we release unreferenced segments.
             refresh("renew sync commit", SearcherScope.INTERNAL, true);
         }
         return renewed;
@@ -2104,13 +2106,13 @@ public class InternalEngine extends Engine {
                 "Either the write lock must be held or the engine must be currently be failing itself";
             try {
                 this.versionMap.clear();
-                if (internalSearcherManager != null) {
-                    internalSearcherManager.removeListener(versionMap);
+                if (internalReaderManager != null) {
+                    internalReaderManager.removeListener(versionMap);
                 }
                 try {
-                    IOUtils.close(externalSearcherManager, internalSearcherManager);
+                    IOUtils.close(externalReaderManager, internalReaderManager);
                 } catch (Exception e) {
-                    logger.warn("Failed to close SearcherManager", e);
+                    logger.warn("Failed to close ReaderManager", e);
                 }
                 try {
                     IOUtils.close(translog);
@@ -2140,12 +2142,12 @@ public class InternalEngine extends Engine {
     }
 
     @Override
-    protected final ReferenceManager<IndexSearcher> getReferenceManager(SearcherScope scope) {
+    protected final ReferenceManager<ElasticsearchDirectoryReader> getReferenceManager(SearcherScope scope) {
         switch (scope) {
             case INTERNAL:
-                return internalSearcherManager;
+                return internalReaderManager;
             case EXTERNAL:
-                return externalSearcherManager;
+                return externalReaderManager;
             default:
                 throw new IllegalStateException("unknown scope: " + scope);
         }
@@ -2215,40 +2217,29 @@ public class InternalEngine extends Engine {
         return iwc;
     }
 
-    /** Extended SearcherFactory that warms the segments if needed when acquiring a new searcher */
-    static final class SearchFactory extends EngineSearcherFactory {
+    /** A listener that warms the segments if needed when acquiring a new reader */
+    static final class RefreshWarmerListener implements BiConsumer<ElasticsearchDirectoryReader, ElasticsearchDirectoryReader> {
         private final Engine.Warmer warmer;
         private final Logger logger;
         private final AtomicBoolean isEngineClosed;
 
-        SearchFactory(Logger logger, AtomicBoolean isEngineClosed, EngineConfig engineConfig) {
-            super(engineConfig);
+        RefreshWarmerListener(Logger logger, AtomicBoolean isEngineClosed, EngineConfig engineConfig) {
             warmer = engineConfig.getWarmer();
             this.logger = logger;
             this.isEngineClosed = isEngineClosed;
         }
 
         @Override
-        public IndexSearcher newSearcher(IndexReader reader, IndexReader previousReader) throws IOException {
-            IndexSearcher searcher = super.newSearcher(reader, previousReader);
-            if (reader instanceof LeafReader && isMergedSegment((LeafReader) reader)) {
-                // we call newSearcher from the IndexReaderWarmer which warms segments during merging
-                // in that case the reader is a LeafReader and all we need to do is to build a new Searcher
-                // and return it since it does it's own warming for that particular reader.
-                return searcher;
-            }
+        public void accept(ElasticsearchDirectoryReader reader, ElasticsearchDirectoryReader previousReader) {
             if (warmer != null) {
                 try {
-                    assert searcher.getIndexReader() instanceof ElasticsearchDirectoryReader :
-                        "this class needs an ElasticsearchDirectoryReader but got: " + searcher.getIndexReader().getClass();
-                    warmer.warm(new Searcher("top_reader_warming", searcher, () -> {}));
+                    warmer.warm(reader);
                 } catch (Exception e) {
                     if (isEngineClosed.get() == false) {
                         logger.warn("failed to prepare/warm", e);
                     }
                 }
             }
-            return searcher;
         }
     }
 

+ 6 - 13
server/src/main/java/org/elasticsearch/index/engine/RamAccountingSearcherFactory.java → server/src/main/java/org/elasticsearch/index/engine/RamAccountingRefreshListener.java

@@ -22,37 +22,30 @@ package org.elasticsearch.index.engine;
 import org.apache.lucene.index.IndexReader;
 import org.apache.lucene.index.LeafReaderContext;
 import org.apache.lucene.index.SegmentReader;
-import org.apache.lucene.search.IndexSearcher;
-import org.apache.lucene.search.SearcherFactory;
 import org.elasticsearch.common.breaker.CircuitBreaker;
 import org.elasticsearch.common.lucene.Lucene;
+import org.elasticsearch.common.lucene.index.ElasticsearchDirectoryReader;
 import org.elasticsearch.indices.breaker.CircuitBreakerService;
 
-import java.io.IOException;
 import java.util.Collections;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
+import java.util.function.BiConsumer;
 
 /**
- * Searcher factory extending {@link EngineSearcherFactory} that tracks the
- * amount of memory used by segments in the accounting circuit breaker.
+ * A refresh listener that tracks the amount of memory used by segments in the accounting circuit breaker.
  */
-final class RamAccountingSearcherFactory extends SearcherFactory {
+final class RamAccountingRefreshListener implements BiConsumer<ElasticsearchDirectoryReader, ElasticsearchDirectoryReader> {
 
     private final CircuitBreakerService breakerService;
 
-    RamAccountingSearcherFactory(CircuitBreakerService breakerService) {
+    RamAccountingRefreshListener(CircuitBreakerService breakerService) {
         this.breakerService = breakerService;
     }
 
     @Override
-    public IndexSearcher newSearcher(IndexReader reader, IndexReader previousReader) throws IOException {
-        processReaders(reader, previousReader);
-        return super.newSearcher(reader, previousReader);
-    }
-
-    public void processReaders(IndexReader reader, IndexReader previousReader) {
+    public void accept(ElasticsearchDirectoryReader reader, ElasticsearchDirectoryReader previousReader) {
         final CircuitBreaker breaker = breakerService.getBreaker(CircuitBreaker.ACCOUNTING);
 
         // Construct a list of the previous segment readers, we only want to track memory used

+ 15 - 19
server/src/main/java/org/elasticsearch/index/engine/ReadOnlyEngine.java

@@ -21,14 +21,11 @@ package org.elasticsearch.index.engine;
 import org.apache.lucene.codecs.blocktree.BlockTreeTermsReader;
 import org.apache.lucene.index.DirectoryReader;
 import org.apache.lucene.index.IndexCommit;
-import org.apache.lucene.index.IndexReader;
 import org.apache.lucene.index.IndexWriter;
 import org.apache.lucene.index.SegmentCommitInfo;
 import org.apache.lucene.index.SegmentInfos;
 import org.apache.lucene.index.SoftDeletesDirectoryReaderWrapper;
-import org.apache.lucene.search.IndexSearcher;
 import org.apache.lucene.search.ReferenceManager;
-import org.apache.lucene.search.SearcherManager;
 import org.apache.lucene.store.Directory;
 import org.apache.lucene.store.Lock;
 import org.elasticsearch.Version;
@@ -75,11 +72,11 @@ public class ReadOnlyEngine extends Engine {
         BlockTreeTermsReader.FSTLoadMode.AUTO.name());
     private final SegmentInfos lastCommittedSegmentInfos;
     private final SeqNoStats seqNoStats;
-    private final SearcherManager searcherManager;
+    private final ElasticsearchReaderManager readerManager;
     private final IndexCommit indexCommit;
     private final Lock indexWriterLock;
     private final DocsStats docsStats;
-    private final RamAccountingSearcherFactory searcherFactory;
+    private final RamAccountingRefreshListener refreshListener;
 
     protected volatile TranslogStats translogStats;
 
@@ -98,11 +95,11 @@ public class ReadOnlyEngine extends Engine {
     public ReadOnlyEngine(EngineConfig config, SeqNoStats seqNoStats, TranslogStats translogStats, boolean obtainLock,
                    Function<DirectoryReader, DirectoryReader> readerWrapperFunction) {
         super(config);
-        this.searcherFactory = new RamAccountingSearcherFactory(engineConfig.getCircuitBreakerService());
+        this.refreshListener = new RamAccountingRefreshListener(engineConfig.getCircuitBreakerService());
         try {
             Store store = config.getStore();
             store.incRef();
-            DirectoryReader reader = null;
+            ElasticsearchDirectoryReader reader = null;
             Directory directory = store.directory();
             Lock indexWriterLock = null;
             boolean success = false;
@@ -117,9 +114,8 @@ public class ReadOnlyEngine extends Engine {
                 }
                 this.seqNoStats = seqNoStats;
                 this.indexCommit = Lucene.getIndexCommit(lastCommittedSegmentInfos, directory);
-                reader = open(indexCommit);
-                reader = wrapReader(reader, readerWrapperFunction);
-                searcherManager = new SearcherManager(reader, searcherFactory);
+                reader = wrapReader(open(indexCommit), readerWrapperFunction);
+                readerManager = new ElasticsearchReaderManager(reader, refreshListener);
                 this.docsStats = docsStats(lastCommittedSegmentInfos);
                 assert translogStats != null || obtainLock : "mutiple translogs instances should not be opened at the same time";
                 this.translogStats = translogStats != null ? translogStats : translogStats(config, lastCommittedSegmentInfos);
@@ -168,7 +164,7 @@ public class ReadOnlyEngine extends Engine {
         // reopened as an internal engine, which would be the path to fix the issue.
     }
 
-    protected final DirectoryReader wrapReader(DirectoryReader reader,
+    protected final ElasticsearchDirectoryReader wrapReader(DirectoryReader reader,
                                                     Function<DirectoryReader, DirectoryReader> readerWrapperFunction) throws IOException {
         if (engineConfig.getIndexSettings().isSoftDeleteEnabled()) {
             reader = new SoftDeletesDirectoryReaderWrapper(reader, Lucene.SOFT_DELETES_FIELD);
@@ -203,9 +199,9 @@ public class ReadOnlyEngine extends Engine {
     protected void closeNoLock(String reason, CountDownLatch closedLatch) {
         if (isClosed.compareAndSet(false, true)) {
             try {
-                IOUtils.close(searcherManager, indexWriterLock, store::decRef);
+                IOUtils.close(readerManager, indexWriterLock, store::decRef);
             } catch (Exception ex) {
-                logger.warn("failed to close searcher", ex);
+                logger.warn("failed to close reader", ex);
             } finally {
                 closedLatch.countDown();
             }
@@ -241,13 +237,13 @@ public class ReadOnlyEngine extends Engine {
     }
 
     @Override
-    public GetResult get(Get get, BiFunction<String, SearcherScope, Searcher> searcherFactory) throws EngineException {
+    public GetResult get(Get get, BiFunction<String, SearcherScope, Engine.Searcher> searcherFactory) throws EngineException {
         return getFromSearcher(get, searcherFactory, SearcherScope.EXTERNAL);
     }
 
     @Override
-    protected ReferenceManager<IndexSearcher> getReferenceManager(SearcherScope scope) {
-        return searcherManager;
+    protected ReferenceManager<ElasticsearchDirectoryReader> getReferenceManager(SearcherScope scope) {
+        return readerManager;
     }
 
     @Override
@@ -379,7 +375,7 @@ public class ReadOnlyEngine extends Engine {
 
     @Override
     public void refresh(String source) {
-        // we could allow refreshes if we want down the road the searcher manager will then reflect changes to a rw-engine
+        // we could allow refreshes if we want down the road the reader manager will then reflect changes to a rw-engine
         // opened side-by-side
     }
 
@@ -490,8 +486,8 @@ public class ReadOnlyEngine extends Engine {
 
     }
 
-    protected void processReader(IndexReader reader) {
-        searcherFactory.processReaders(reader, null);
+    protected void processReader(ElasticsearchDirectoryReader reader) {
+        refreshListener.accept(reader, null);
     }
 
     @Override

+ 8 - 12
server/src/main/java/org/elasticsearch/index/shard/IndexShard.java

@@ -29,7 +29,6 @@ import org.apache.lucene.index.IndexCommit;
 import org.apache.lucene.index.LeafReader;
 import org.apache.lucene.index.SegmentInfos;
 import org.apache.lucene.index.Term;
-import org.apache.lucene.search.IndexSearcher;
 import org.apache.lucene.search.Query;
 import org.apache.lucene.search.QueryCachingPolicy;
 import org.apache.lucene.search.ReferenceManager;
@@ -1220,6 +1219,7 @@ public class IndexShard extends AbstractIndexShardComponent implements IndicesCl
         // fail the engine. This will cause this shard to also be removed from the node's index service.
         getEngine().failEngine(reason, e);
     }
+
     public Engine.Searcher acquireSearcher(String source) {
         return acquireSearcher(source, Engine.SearcherScope.EXTERNAL);
     }
@@ -1237,10 +1237,10 @@ public class IndexShard extends AbstractIndexShardComponent implements IndicesCl
             != null : "DirectoryReader must be an instance or ElasticsearchDirectoryReader";
         boolean success = false;
         try {
-            final Engine.Searcher wrappedSearcher = readerWrapper == null ? searcher : wrapSearcher(searcher, readerWrapper);
-            assert wrappedSearcher != null;
+            final Engine.Searcher newSearcher = readerWrapper == null ? searcher : wrapSearcher(searcher, readerWrapper);
+            assert newSearcher != null;
             success = true;
-            return wrappedSearcher;
+            return newSearcher;
         } catch (IOException ex) {
             throw new ElasticsearchException("failed to wrap searcher", ex);
         } finally {
@@ -1275,16 +1275,12 @@ public class IndexShard extends AbstractIndexShardComponent implements IndicesCl
         if (reader == nonClosingReaderWrapper) {
             return engineSearcher;
         } else {
-            final IndexSearcher origIndexSearcher = engineSearcher.searcher();
-            final IndexSearcher newIndexSearcher = new IndexSearcher(reader);
-            newIndexSearcher.setQueryCache(origIndexSearcher.getQueryCache());
-            newIndexSearcher.setQueryCachingPolicy(origIndexSearcher.getQueryCachingPolicy());
-            newIndexSearcher.setSimilarity(origIndexSearcher.getSimilarity());
             // we close the reader to make sure wrappers can release resources if needed....
             // our NonClosingReaderWrapper makes sure that our reader is not closed
-            return new Engine.Searcher(engineSearcher.source(), newIndexSearcher, () ->
-                IOUtils.close(newIndexSearcher.getIndexReader(), // this will close the wrappers excluding the NonClosingReaderWrapper
-                    engineSearcher)); // this will run the closeable on the wrapped engine searcher
+            return new Engine.Searcher(engineSearcher.source(), reader,
+                engineSearcher.getSimilarity(), engineSearcher.getQueryCache(), engineSearcher.getQueryCachingPolicy(),
+                () -> IOUtils.close(reader, // this will close the wrappers excluding the NonClosingReaderWrapper
+                    engineSearcher)); // this will run the closeable on the wrapped engine reader
         }
     }
 

+ 1 - 1
server/src/main/java/org/elasticsearch/index/termvectors/TermVectorsService.java

@@ -96,7 +96,7 @@ public class TermVectorsService  {
             request.id(), uidTerm)
                 .version(request.version()).versionType(request.versionType()));
                 Engine.Searcher searcher = indexShard.acquireSearcher("term_vector")) {
-            Fields topLevelFields = fields(get.searcher() != null ? get.searcher().reader() : searcher.reader());
+            Fields topLevelFields = fields(get.searcher() != null ? get.searcher().getIndexReader() : searcher.getIndexReader());
             DocIdAndVersion docIdAndVersion = get.docIdAndVersion();
             /* from an artificial document */
             if (request.doc() != null) {

+ 3 - 4
server/src/main/java/org/elasticsearch/search/DefaultSearchContext.java

@@ -173,8 +173,8 @@ final class DefaultSearchContext extends SearchContext {
         this.indexShard = indexShard;
         this.indexService = indexService;
         this.clusterService = clusterService;
-        this.searcher = new ContextIndexSearcher(engineSearcher.reader(), engineSearcher.searcher().getSimilarity(),
-            indexService.cache().query(), indexShard.getQueryCachingPolicy());
+        this.searcher = new ContextIndexSearcher(engineSearcher.getIndexReader(), engineSearcher.getSimilarity(),
+            engineSearcher.getQueryCache(), engineSearcher.getQueryCachingPolicy());
         this.relativeTimeSupplier = relativeTimeSupplier;
         this.timeout = timeout;
         this.minNodeVersion = minNodeVersion;
@@ -185,8 +185,7 @@ final class DefaultSearchContext extends SearchContext {
 
     @Override
     public void doClose() {
-        // clear and scope phase we have
-        Releasables.close(searcher, engineSearcher);
+        Releasables.close(engineSearcher);
     }
 
     /**

+ 2 - 2
server/src/main/java/org/elasticsearch/search/SearchService.java

@@ -629,10 +629,10 @@ public class SearchService extends AbstractLifecycleComponent implements IndexEv
         IndexShard indexShard = indexService.getShard(request.shardId().getId());
         SearchShardTarget shardTarget = new SearchShardTarget(clusterService.localNode().getId(),
                 indexShard.shardId(), request.getClusterAlias(), OriginalIndices.NONE);
-        Engine.Searcher engineSearcher = indexShard.acquireSearcher(source);
+        Engine.Searcher searcher = indexShard.acquireSearcher(source);
 
         final DefaultSearchContext searchContext = new DefaultSearchContext(idGenerator.incrementAndGet(), request, shardTarget,
-            engineSearcher, clusterService, indexService, indexShard, bigArrays, threadPool::relativeTimeInMillis, timeout,
+            searcher, clusterService, indexService, indexShard, bigArrays, threadPool::relativeTimeInMillis, timeout,
             fetchPhase, clusterService.state().nodes().getMinNodeVersion());
         boolean success = false;
         try {

+ 1 - 6
server/src/main/java/org/elasticsearch/search/internal/ContextIndexSearcher.java

@@ -46,7 +46,6 @@ import org.apache.lucene.util.BitSetIterator;
 import org.apache.lucene.util.Bits;
 import org.apache.lucene.util.CombinedBitSet;
 import org.apache.lucene.util.SparseFixedBitSet;
-import org.elasticsearch.common.lease.Releasable;
 import org.elasticsearch.search.dfs.AggregatedDfs;
 import org.elasticsearch.search.profile.Timer;
 import org.elasticsearch.search.profile.query.ProfileWeight;
@@ -62,7 +61,7 @@ import java.util.Set;
 /**
  * Context-aware extension of {@link IndexSearcher}.
  */
-public class ContextIndexSearcher extends IndexSearcher implements Releasable {
+public class ContextIndexSearcher extends IndexSearcher {
     /**
      * The interval at which we check for search cancellation when we cannot use
      * a {@link CancellableBulkScorer}. See {@link #intersectScorerAndBitSet}.
@@ -80,10 +79,6 @@ public class ContextIndexSearcher extends IndexSearcher implements Releasable {
         setQueryCachingPolicy(queryCachingPolicy);
     }
 
-    @Override
-    public void close() {
-    }
-
     public void setProfiler(QueryProfiler profiler) {
         this.profiler = profiler;
     }

+ 3 - 3
server/src/test/java/org/elasticsearch/index/IndexServiceTests.java

@@ -287,7 +287,7 @@ public class IndexServiceTests extends ESSingleNodeTestCase {
             // this one either becomes visible due to a concurrently running scheduled refresh OR due to the force refresh
             // we are running on updateMetaData if the interval changes
             try (Engine.Searcher searcher = shard.acquireSearcher("test")) {
-                TopDocs search = searcher.searcher().search(new MatchAllDocsQuery(), 10);
+                TopDocs search = searcher.search(new MatchAllDocsQuery(), 10);
                 assertEquals(1, search.totalHits.value);
             }
         });
@@ -300,7 +300,7 @@ public class IndexServiceTests extends ESSingleNodeTestCase {
         assertBusy(() -> {
             // this one becomes visible due to the force refresh we are running on updateMetaData if the interval changes
             try (Engine.Searcher searcher = shard.acquireSearcher("test")) {
-                TopDocs search = searcher.searcher().search(new MatchAllDocsQuery(), 10);
+                TopDocs search = searcher.search(new MatchAllDocsQuery(), 10);
                 assertEquals(2, search.totalHits.value);
             }
         });
@@ -308,7 +308,7 @@ public class IndexServiceTests extends ESSingleNodeTestCase {
         assertBusy(() -> {
             // this one becomes visible due to the scheduled refresh
             try (Engine.Searcher searcher = shard.acquireSearcher("test")) {
-                TopDocs search = searcher.searcher().search(new MatchAllDocsQuery(), 10);
+                TopDocs search = searcher.search(new MatchAllDocsQuery(), 10);
                 assertEquals(3, search.totalHits.value);
             }
         });

+ 1 - 1
server/src/test/java/org/elasticsearch/index/engine/EngineSearcherTotalHitsMatcher.java

@@ -42,7 +42,7 @@ public final class EngineSearcherTotalHitsMatcher extends TypeSafeMatcher<Engine
     @Override
     public boolean matchesSafely(Engine.Searcher searcher) {
         try {
-            this.count = (int) searcher.searcher().count(query);
+            this.count = searcher.count(query);
             return count == totalHits;
         } catch (IOException e) {
             return false;

+ 92 - 93
server/src/test/java/org/elasticsearch/index/engine/InternalEngineTests.java

@@ -106,7 +106,6 @@ import org.elasticsearch.index.IndexModule;
 import org.elasticsearch.index.IndexSettings;
 import org.elasticsearch.index.VersionType;
 import org.elasticsearch.index.codec.CodecService;
-import org.elasticsearch.index.engine.Engine.Searcher;
 import org.elasticsearch.index.fieldvisitor.FieldsVisitor;
 import org.elasticsearch.index.mapper.ContentPath;
 import org.elasticsearch.index.mapper.IdFieldMapper;
@@ -223,13 +222,13 @@ public class InternalEngineTests extends EngineTestCase {
         assertTrue(engine.isSafeAccessRequired());
         assertThat(engine.getVersionMap().values(), hasSize(1));
         try (Engine.Searcher searcher = engine.acquireSearcher("test")) {
-            assertEquals(0, searcher.reader().numDocs());
+            assertEquals(0, searcher.getIndexReader().numDocs());
         }
 
         try (Engine.Searcher searcher = engine.acquireSearcher("test", Engine.SearcherScope.INTERNAL)) {
-            assertEquals(1, searcher.reader().numDocs());
-            TopDocs search = searcher.searcher().search(new MatchAllDocsQuery(), 1);
-            org.apache.lucene.document.Document luceneDoc = searcher.searcher().doc(search.scoreDocs[0].doc);
+            assertEquals(1, searcher.getIndexReader().numDocs());
+            TopDocs search = searcher.search(new MatchAllDocsQuery(), 1);
+            org.apache.lucene.document.Document luceneDoc = searcher.doc(search.scoreDocs[0].doc);
             assertEquals("test", luceneDoc.get("value"));
         }
 
@@ -240,9 +239,9 @@ public class InternalEngineTests extends EngineTestCase {
         }
         assertTrue("safe access should be required we carried it over", engine.isSafeAccessRequired());
         try (Engine.Searcher searcher = engine.acquireSearcher("test")) {
-            assertEquals(1, searcher.reader().numDocs());
-            TopDocs search = searcher.searcher().search(new MatchAllDocsQuery(), 1);
-            org.apache.lucene.document.Document luceneDoc = searcher.searcher().doc(search.scoreDocs[0].doc);
+            assertEquals(1, searcher.getIndexReader().numDocs());
+            TopDocs search = searcher.search(new MatchAllDocsQuery(), 1);
+            org.apache.lucene.document.Document luceneDoc = searcher.doc(search.scoreDocs[0].doc);
             assertEquals("updated", luceneDoc.get("value"));
         }
 
@@ -259,7 +258,7 @@ public class InternalEngineTests extends EngineTestCase {
             engine.refresh("test");
         }
         try (Engine.Searcher searcher = engine.acquireSearcher("test")) {
-            assertEquals(2, searcher.reader().numDocs());
+            assertEquals(2, searcher.getIndexReader().numDocs());
         }
         assertFalse("safe access should NOT be required last indexing round was only append only", engine.isSafeAccessRequired());
         engine.delete(new Engine.Delete(operation.type(), operation.id(), operation.uid(), primaryTerm.get()));
@@ -267,7 +266,7 @@ public class InternalEngineTests extends EngineTestCase {
         engine.refresh("test");
         assertTrue("safe access should be required", engine.isSafeAccessRequired());
         try (Engine.Searcher searcher = engine.acquireSearcher("test")) {
-            assertEquals(1, searcher.reader().numDocs());
+            assertEquals(1, searcher.getIndexReader().numDocs());
         }
     }
 
@@ -765,7 +764,7 @@ public class InternalEngineTests extends EngineTestCase {
             recoveringEngine.recoverFromTranslog(translogHandler, Long.MAX_VALUE);
             try (Engine.Searcher searcher = recoveringEngine.acquireSearcher("test")) {
                 final TotalHitCountCollector collector = new TotalHitCountCollector();
-                searcher.searcher().search(new MatchAllDocsQuery(), collector);
+                searcher.search(new MatchAllDocsQuery(), collector);
                 assertThat(collector.getTotalHits(), equalTo(operations.get(operations.size() - 1) instanceof Engine.Delete ? 0 : 1));
             }
         }
@@ -832,7 +831,7 @@ public class InternalEngineTests extends EngineTestCase {
             recoveringEngine = new InternalEngine(initialEngine.config());
             recoveringEngine.recoverFromTranslog(translogHandler, Long.MAX_VALUE);
             try (Engine.Searcher searcher = recoveringEngine.acquireSearcher("test")) {
-                TopDocs topDocs = searcher.searcher().search(new MatchAllDocsQuery(), docs);
+                TopDocs topDocs = searcher.search(new MatchAllDocsQuery(), docs);
                 assertEquals(docs, topDocs.totalHits.value);
             }
         } finally {
@@ -882,7 +881,7 @@ public class InternalEngineTests extends EngineTestCase {
         engine.index(indexForDoc(doc));
 
         final AtomicReference<Engine.GetResult> latestGetResult = new AtomicReference<>();
-        final BiFunction<String, Engine.SearcherScope, Searcher> searcherFactory = engine::acquireSearcher;
+        final BiFunction<String, Engine.SearcherScope, Engine.Searcher> searcherFactory = engine::acquireSearcher;
         latestGetResult.set(engine.get(newGet(true, doc), searcherFactory));
         final AtomicBoolean flushFinished = new AtomicBoolean(false);
         final CyclicBarrier barrier = new CyclicBarrier(2);
@@ -917,7 +916,7 @@ public class InternalEngineTests extends EngineTestCase {
         MatcherAssert.assertThat(searchResult, EngineSearcherTotalHitsMatcher.engineSearcherTotalHits(0));
         searchResult.close();
 
-        final BiFunction<String, Engine.SearcherScope, Searcher> searcherFactory = engine::acquireSearcher;
+        final BiFunction<String, Engine.SearcherScope, Engine.Searcher> searcherFactory = engine::acquireSearcher;
 
         // create a document
         Document document = testDocumentWithTextField();
@@ -1355,12 +1354,12 @@ public class InternalEngineTests extends EngineTestCase {
         assertThat(updateResult.getVersion(), equalTo(2L));
         assertFalse(updateResult.isCreated());
         replicaEngine.refresh("test");
-        try (Searcher searcher = replicaEngine.acquireSearcher("test")) {
+        try (Engine.Searcher searcher = replicaEngine.acquireSearcher("test")) {
             assertEquals(1, searcher.getDirectoryReader().numDocs());
         }
 
         engine.refresh("test");
-        try (Searcher searcher = engine.acquireSearcher("test")) {
+        try (Engine.Searcher searcher = engine.acquireSearcher("test")) {
             assertEquals(1, searcher.getDirectoryReader().numDocs());
         }
     }
@@ -1369,7 +1368,7 @@ public class InternalEngineTests extends EngineTestCase {
      * simulates what an upsert / update API does
      */
     public void testVersionedUpdate() throws IOException {
-        final BiFunction<String, Engine.SearcherScope, Searcher> searcherFactory = engine::acquireSearcher;
+        final BiFunction<String, Engine.SearcherScope, Engine.Searcher> searcherFactory = engine::acquireSearcher;
 
         ParsedDocument doc = testParsedDocument("1", null, testDocument(), B_1, null);
         Engine.Index create = new Engine.Index(newUid(doc), primaryTerm.get(), doc, Versions.MATCH_DELETED);
@@ -1401,7 +1400,7 @@ public class InternalEngineTests extends EngineTestCase {
     }
 
     public void testGetIfSeqNoIfPrimaryTerm() throws IOException {
-        final BiFunction<String, Engine.SearcherScope, Searcher> searcherFactory = engine::acquireSearcher;
+        final BiFunction<String, Engine.SearcherScope, Engine.Searcher> searcherFactory = engine::acquireSearcher;
 
         ParsedDocument doc = testParsedDocument("1", null, testDocument(), B_1, null);
         Engine.Index create = new Engine.Index(newUid(doc), primaryTerm.get(), doc, Versions.MATCH_DELETED);
@@ -1460,7 +1459,7 @@ public class InternalEngineTests extends EngineTestCase {
                 engine.refresh("test");
             }
             try (Engine.Searcher test = engine.acquireSearcher("test")) {
-                assertEquals(numDocs, test.reader().numDocs());
+                assertEquals(numDocs, test.getIndexReader().numDocs());
             }
             engine.forceMerge(true, 1, false, false, false);
             engine.refresh("test");
@@ -1475,8 +1474,8 @@ public class InternalEngineTests extends EngineTestCase {
 
             assertEquals(engine.segments(true).size(), 1);
             try (Engine.Searcher test = engine.acquireSearcher("test")) {
-                assertEquals(numDocs - 1, test.reader().numDocs());
-                assertEquals(engine.config().getMergePolicy().toString(), numDocs - 1, test.reader().maxDoc());
+                assertEquals(numDocs - 1, test.getIndexReader().numDocs());
+                assertEquals(engine.config().getMergePolicy().toString(), numDocs - 1, test.getIndexReader().maxDoc());
             }
 
             doc = testParsedDocument(Integer.toString(1), null, testDocument(), B_1, null);
@@ -1487,8 +1486,8 @@ public class InternalEngineTests extends EngineTestCase {
             engine.refresh("test");
             assertEquals(engine.segments(true).size(), 1);
             try (Engine.Searcher test = engine.acquireSearcher("test")) {
-                assertEquals(numDocs - 2, test.reader().numDocs());
-                assertEquals(numDocs - 1, test.reader().maxDoc());
+                assertEquals(numDocs - 2, test.getIndexReader().numDocs());
+                assertEquals(numDocs - 1, test.getIndexReader().maxDoc());
             }
         }
     }
@@ -1859,16 +1858,16 @@ public class InternalEngineTests extends EngineTestCase {
         engine.refresh("test");
 
         if (lastFieldValueDoc1 != null) {
-            try (Searcher searcher = engine.acquireSearcher("test")) {
+            try (Engine.Searcher searcher = engine.acquireSearcher("test")) {
                 final TotalHitCountCollector collector = new TotalHitCountCollector();
-                searcher.searcher().search(new TermQuery(new Term("value", lastFieldValueDoc1)), collector);
+                searcher.search(new TermQuery(new Term("value", lastFieldValueDoc1)), collector);
                 assertThat(collector.getTotalHits(), equalTo(1));
             }
         }
         if (lastFieldValueDoc2 != null) {
-            try (Searcher searcher = engine.acquireSearcher("test")) {
+            try (Engine.Searcher searcher = engine.acquireSearcher("test")) {
                 final TotalHitCountCollector collector = new TotalHitCountCollector();
-                searcher.searcher().search(new TermQuery(new Term("value", lastFieldValueDoc2)), collector);
+                searcher.search(new TermQuery(new Term("value", lastFieldValueDoc2)), collector);
                 assertThat(collector.getTotalHits(), equalTo(1));
             }
         }
@@ -2032,9 +2031,9 @@ public class InternalEngineTests extends EngineTestCase {
                 // even if doc is not not deleted, lastFieldValue can still be null if this is the
                 // first op and it failed.
                 if (docDeleted == false && lastFieldValue != null) {
-                    try (Searcher searcher = engine.acquireSearcher("test")) {
+                    try (Engine.Searcher searcher = engine.acquireSearcher("test")) {
                         final TotalHitCountCollector collector = new TotalHitCountCollector();
-                        searcher.searcher().search(new TermQuery(new Term("value", lastFieldValue)), collector);
+                        searcher.search(new TermQuery(new Term("value", lastFieldValue)), collector);
                         assertThat(collector.getTotalHits(), equalTo(1));
                     }
                 }
@@ -2058,9 +2057,9 @@ public class InternalEngineTests extends EngineTestCase {
 
         assertVisibleCount(engine, docDeleted ? 0 : 1);
         if (docDeleted == false) {
-            try (Searcher searcher = engine.acquireSearcher("test")) {
+            try (Engine.Searcher searcher = engine.acquireSearcher("test")) {
                 final TotalHitCountCollector collector = new TotalHitCountCollector();
-                searcher.searcher().search(new TermQuery(new Term("value", lastFieldValue)), collector);
+                searcher.search(new TermQuery(new Term("value", lastFieldValue)), collector);
                 assertThat(collector.getTotalHits(), equalTo(1));
             }
         }
@@ -2141,9 +2140,9 @@ public class InternalEngineTests extends EngineTestCase {
         assertVisibleCount(engine, docDeleted ? 0 : 1);
         if (docDeleted == false) {
             logger.info("searching for [{}]", lastFieldValue);
-            try (Searcher searcher = engine.acquireSearcher("test")) {
+            try (Engine.Searcher searcher = engine.acquireSearcher("test")) {
                 final TotalHitCountCollector collector = new TotalHitCountCollector();
-                searcher.searcher().search(new TermQuery(new Term("value", lastFieldValue)), collector);
+                searcher.search(new TermQuery(new Term("value", lastFieldValue)), collector);
                 assertThat(collector.getTotalHits(), equalTo(1));
             }
         }
@@ -2162,9 +2161,9 @@ public class InternalEngineTests extends EngineTestCase {
         final int opsOnPrimary = assertOpsOnPrimary(primaryOps, finalReplicaVersion, deletedOnReplica, replicaEngine);
         final long currentSeqNo = getSequenceID(replicaEngine,
             new Engine.Get(false, false, "type", lastReplicaOp.uid().text(), lastReplicaOp.uid())).v1();
-        try (Searcher searcher = engine.acquireSearcher("test")) {
+        try (Engine.Searcher searcher = engine.acquireSearcher("test")) {
             final TotalHitCountCollector collector = new TotalHitCountCollector();
-            searcher.searcher().search(new MatchAllDocsQuery(), collector);
+            searcher.search(new MatchAllDocsQuery(), collector);
             if (collector.getTotalHits() > 0) {
                 // last op wasn't delete
                 assertThat(currentSeqNo, equalTo(finalReplicaSeqNo + opsOnPrimary));
@@ -2189,9 +2188,9 @@ public class InternalEngineTests extends EngineTestCase {
 
         assertVisibleCount(engine, lastFieldValue == null ? 0 : 1);
         if (lastFieldValue != null) {
-            try (Searcher searcher = engine.acquireSearcher("test")) {
+            try (Engine.Searcher searcher = engine.acquireSearcher("test")) {
                 final TotalHitCountCollector collector = new TotalHitCountCollector();
-                searcher.searcher().search(new TermQuery(new Term("value", lastFieldValue)), collector);
+                searcher.search(new TermQuery(new Term("value", lastFieldValue)), collector);
                 assertThat(collector.getTotalHits(), equalTo(1));
             }
         }
@@ -2217,7 +2216,7 @@ public class InternalEngineTests extends EngineTestCase {
         ParsedDocument doc = testParsedDocument("1", null, testDocument(), bytesArray(""), null);
         final Term uidTerm = newUid(doc);
         engine.index(indexForDoc(doc));
-        final BiFunction<String, Engine.SearcherScope, Searcher> searcherFactory = engine::acquireSearcher;
+        final BiFunction<String, Engine.SearcherScope, Engine.Searcher> searcherFactory = engine::acquireSearcher;
         for (int i = 0; i < thread.length; i++) {
             thread[i] = new Thread(() -> {
                 startGun.countDown();
@@ -2653,7 +2652,7 @@ public class InternalEngineTests extends EngineTestCase {
              Engine engine = createEngine(config(defaultSettings, store, createTempDir(), newMergePolicy(), null))) {
             engine.config().setEnableGcDeletes(false);
 
-            final BiFunction<String, Engine.SearcherScope, Searcher> searcherFactory = engine::acquireSearcher;
+            final BiFunction<String, Engine.SearcherScope, Engine.Searcher> searcherFactory = engine::acquireSearcher;
 
             // Add document
             Document document = testDocument();
@@ -2993,7 +2992,7 @@ public class InternalEngineTests extends EngineTestCase {
         try (InternalEngine engine = new InternalEngine(config)) {
             engine.skipTranslogRecovery();
             try (Engine.Searcher searcher = engine.acquireSearcher("test")) {
-                TopDocs topDocs = searcher.searcher().search(new MatchAllDocsQuery(), randomIntBetween(numDocs, numDocs + 10));
+                TopDocs topDocs = searcher.search(new MatchAllDocsQuery(), randomIntBetween(numDocs, numDocs + 10));
                 assertThat(topDocs.totalHits.value, equalTo(0L));
             }
         }
@@ -3070,7 +3069,7 @@ public class InternalEngineTests extends EngineTestCase {
         engine.refresh("test");
         assertThat(result.getVersion(), equalTo(2L));
         try (Engine.Searcher searcher = engine.acquireSearcher("test")) {
-            TopDocs topDocs = searcher.searcher().search(new MatchAllDocsQuery(), numDocs + 1);
+            TopDocs topDocs = searcher.search(new MatchAllDocsQuery(), numDocs + 1);
             assertThat(topDocs.totalHits.value, equalTo(numDocs + 1L));
         }
 
@@ -3078,7 +3077,7 @@ public class InternalEngineTests extends EngineTestCase {
         translogHandler = createTranslogHandler(engine.engineConfig.getIndexSettings());
         engine = createEngine(store, primaryTranslogDir, inSyncGlobalCheckpointSupplier);
         try (Engine.Searcher searcher = engine.acquireSearcher("test")) {
-            TopDocs topDocs = searcher.searcher().search(new MatchAllDocsQuery(), numDocs + 1);
+            TopDocs topDocs = searcher.search(new MatchAllDocsQuery(), numDocs + 1);
             assertThat(topDocs.totalHits.value, equalTo(numDocs + 1L));
         }
         assertEquals(flush ? 1 : 2, translogHandler.appliedOperations());
@@ -3090,7 +3089,7 @@ public class InternalEngineTests extends EngineTestCase {
             engine = createEngine(store, primaryTranslogDir, inSyncGlobalCheckpointSupplier);
         }
         try (Engine.Searcher searcher = engine.acquireSearcher("test")) {
-            TopDocs topDocs = searcher.searcher().search(new MatchAllDocsQuery(), numDocs);
+            TopDocs topDocs = searcher.search(new MatchAllDocsQuery(), numDocs);
             assertThat(topDocs.totalHits.value, equalTo((long) numDocs));
         }
     }
@@ -3426,7 +3425,7 @@ public class InternalEngineTests extends EngineTestCase {
 
         engine.refresh("test");
         try (Engine.Searcher searcher = engine.acquireSearcher("test")) {
-            TopDocs topDocs = searcher.searcher().search(new MatchAllDocsQuery(), 10);
+            TopDocs topDocs = searcher.search(new MatchAllDocsQuery(), 10);
             assertEquals(1, topDocs.totalHits.value);
         }
         operation = appendOnlyPrimary(doc, false, 1);
@@ -3447,7 +3446,7 @@ public class InternalEngineTests extends EngineTestCase {
 
         engine.refresh("test");
         try (Engine.Searcher searcher = engine.acquireSearcher("test")) {
-            TopDocs topDocs = searcher.searcher().search(new MatchAllDocsQuery(), 10);
+            TopDocs topDocs = searcher.search(new MatchAllDocsQuery(), 10);
             assertEquals(1, topDocs.totalHits.value);
         }
     }
@@ -3491,7 +3490,7 @@ public class InternalEngineTests extends EngineTestCase {
 
         engine.refresh("test");
         try (Engine.Searcher searcher = engine.acquireSearcher("test")) {
-            TopDocs topDocs = searcher.searcher().search(new MatchAllDocsQuery(), 10);
+            TopDocs topDocs = searcher.search(new MatchAllDocsQuery(), 10);
             assertEquals(0, topDocs.totalHits.value);
         }
     }
@@ -3536,7 +3535,7 @@ public class InternalEngineTests extends EngineTestCase {
 
         engine.refresh("test");
         try (Engine.Searcher searcher = engine.acquireSearcher("test")) {
-            TopDocs topDocs = searcher.searcher().search(new MatchAllDocsQuery(), 10);
+            TopDocs topDocs = searcher.search(new MatchAllDocsQuery(), 10);
             assertEquals(1, topDocs.totalHits.value);
         }
         operation = randomAppendOnly(doc.get(), false, 1);
@@ -3557,7 +3556,7 @@ public class InternalEngineTests extends EngineTestCase {
 
         engine.refresh("test");
         try (Engine.Searcher searcher = engine.acquireSearcher("test")) {
-            TopDocs topDocs = searcher.searcher().search(new MatchAllDocsQuery(), 10);
+            TopDocs topDocs = searcher.search(new MatchAllDocsQuery(), 10);
             assertEquals(1, topDocs.totalHits.value);
         }
     }
@@ -3597,12 +3596,12 @@ public class InternalEngineTests extends EngineTestCase {
 
         engine.refresh("test");
         try (Engine.Searcher searcher = engine.acquireSearcher("test")) {
-            TopDocs topDocs = searcher.searcher().search(new MatchAllDocsQuery(), 10);
+            TopDocs topDocs = searcher.search(new MatchAllDocsQuery(), 10);
             assertEquals(1, topDocs.totalHits.value);
         }
         engine.refresh("test");
         try (Engine.Searcher searcher = engine.acquireSearcher("test")) {
-            TopDocs topDocs = searcher.searcher().search(new MatchAllDocsQuery(), 10);
+            TopDocs topDocs = searcher.search(new MatchAllDocsQuery(), 10);
             assertEquals(1, topDocs.totalHits.value);
         }
         if (engine.engineConfig.getIndexSettings().isSoftDeleteEnabled()) {
@@ -3635,7 +3634,7 @@ public class InternalEngineTests extends EngineTestCase {
         assertThat(indexResult.getVersion(), equalTo(1L));
         engine.refresh("test");
         try (Engine.Searcher searcher = engine.acquireSearcher("test")) {
-            TopDocs topDocs = searcher.searcher().search(new MatchAllDocsQuery(), 10);
+            TopDocs topDocs = searcher.search(new MatchAllDocsQuery(), 10);
             assertEquals(1, topDocs.totalHits.value);
         }
 
@@ -3645,7 +3644,7 @@ public class InternalEngineTests extends EngineTestCase {
         assertThat(indexResult.getResultType(), equalTo(Engine.Result.Type.SUCCESS));
         replicaEngine.refresh("test");
         try (Engine.Searcher searcher = replicaEngine.acquireSearcher("test")) {
-            TopDocs topDocs = searcher.searcher().search(new MatchAllDocsQuery(), 10);
+            TopDocs topDocs = searcher.search(new MatchAllDocsQuery(), 10);
             assertEquals(1, topDocs.totalHits.value);
         }
     }
@@ -3674,7 +3673,7 @@ public class InternalEngineTests extends EngineTestCase {
         assertTrue(indexResult.isCreated());
         engine.refresh("test");
         try (Engine.Searcher searcher = engine.acquireSearcher("test")) {
-            TopDocs topDocs = searcher.searcher().search(new MatchAllDocsQuery(), 10);
+            TopDocs topDocs = searcher.search(new MatchAllDocsQuery(), 10);
             assertEquals(1, topDocs.totalHits.value);
         }
 
@@ -3683,7 +3682,7 @@ public class InternalEngineTests extends EngineTestCase {
         replicaEngine.index(secondIndexRequestReplica);
         replicaEngine.refresh("test");
         try (Engine.Searcher searcher = replicaEngine.acquireSearcher("test")) {
-            TopDocs topDocs = searcher.searcher().search(new MatchAllDocsQuery(), 10);
+            TopDocs topDocs = searcher.search(new MatchAllDocsQuery(), 10);
             assertEquals(1, topDocs.totalHits.value);
         }
     }
@@ -3761,7 +3760,7 @@ public class InternalEngineTests extends EngineTestCase {
         }
         engine.refresh("test");
         try (Engine.Searcher searcher = engine.acquireSearcher("test")) {
-            int count = searcher.searcher().count(new MatchAllDocsQuery());
+            int count = searcher.count(new MatchAllDocsQuery());
             assertEquals(numDocs, count);
         }
         if (primary) {
@@ -3859,7 +3858,7 @@ public class InternalEngineTests extends EngineTestCase {
             thread[i].start();
         }
         try (Engine.Searcher searcher = engine.acquireSearcher("test", Engine.SearcherScope.INTERNAL)) {
-            assertEquals("unexpected refresh", 0, searcher.reader().maxDoc());
+            assertEquals("unexpected refresh", 0, searcher.getIndexReader().maxDoc());
         }
         for (int i = 0; i < thread.length; i++) {
             thread[i].join();
@@ -3867,7 +3866,7 @@ public class InternalEngineTests extends EngineTestCase {
 
         engine.refresh("test");
         try (Engine.Searcher searcher = engine.acquireSearcher("test")) {
-            int count = searcher.searcher().count(new MatchAllDocsQuery());
+            int count = searcher.count(new MatchAllDocsQuery());
             assertEquals(docs.size(), count);
         }
         assertEquals(0, engine.getNumVersionLookups());
@@ -4036,7 +4035,7 @@ public class InternalEngineTests extends EngineTestCase {
         try (Store store = createStore();
              InternalEngine engine = createEngine(config(indexSettings, store, createTempDir(), newMergePolicy(), null))) {
             CheckedRunnable<IOException> lookupAndCheck = () -> {
-                try (Searcher searcher = engine.acquireSearcher("test", Engine.SearcherScope.INTERNAL)) {
+                try (Engine.Searcher searcher = engine.acquireSearcher("test", Engine.SearcherScope.INTERNAL)) {
                     Map<String, Long> liveOps = latestOps.entrySet().stream()
                         .filter(e -> e.getValue().operationType() == Engine.Operation.TYPE.INDEX)
                         .collect(Collectors.toMap(e -> e.getKey(), e -> e.getValue().seqNo()));
@@ -4044,7 +4043,7 @@ public class InternalEngineTests extends EngineTestCase {
                         equalTo(liveOps));
                     for (String id : latestOps.keySet()) {
                         String msg = "latestOps=" + latestOps + " op=" + id;
-                        DocIdAndSeqNo docIdAndSeqNo = VersionsAndSeqNoResolver.loadDocIdAndSeqNo(searcher.reader(), newUid(id));
+                        DocIdAndSeqNo docIdAndSeqNo = VersionsAndSeqNoResolver.loadDocIdAndSeqNo(searcher.getIndexReader(), newUid(id));
                         if (liveOps.containsKey(id) == false) {
                             assertNull(msg, docIdAndSeqNo);
                         } else {
@@ -4053,7 +4052,7 @@ public class InternalEngineTests extends EngineTestCase {
                         }
                     }
                     String notFoundId = randomValueOtherThanMany(liveOps::containsKey, () -> Long.toString(randomNonNegativeLong()));
-                    assertNull(VersionsAndSeqNoResolver.loadDocIdAndSeqNo(searcher.reader(), newUid(notFoundId)));
+                    assertNull(VersionsAndSeqNoResolver.loadDocIdAndSeqNo(searcher.getIndexReader(), newUid(notFoundId)));
                 }
             };
             for (Engine.Operation op : operations) {
@@ -4190,7 +4189,7 @@ public class InternalEngineTests extends EngineTestCase {
             return testParsedDocument("1", null, document, B_1, null);
         };
         final Term uid = newUid("1");
-        final BiFunction<String, Engine.SearcherScope, Searcher> searcherFactory = engine::acquireSearcher;
+        final BiFunction<String, Engine.SearcherScope, Engine.Searcher> searcherFactory = engine::acquireSearcher;
         for (int i = 0; i < numberOfOperations; i++) {
             if (randomBoolean()) {
                 final Engine.Index index = new Engine.Index(
@@ -4456,10 +4455,10 @@ public class InternalEngineTests extends EngineTestCase {
      * second is the primary term.
      */
     private Tuple<Long, Long> getSequenceID(Engine engine, Engine.Get get) throws EngineException {
-        try (Searcher searcher = engine.acquireSearcher("get")) {
+        try (Engine.Searcher searcher = engine.acquireSearcher("get")) {
             final long primaryTerm;
             final long seqNo;
-            DocIdAndSeqNo docIdAndSeqNo = VersionsAndSeqNoResolver.loadDocIdAndSeqNo(searcher.reader(), get.uid());
+            DocIdAndSeqNo docIdAndSeqNo = VersionsAndSeqNoResolver.loadDocIdAndSeqNo(searcher.getIndexReader(), get.uid());
             if (docIdAndSeqNo == null) {
                 primaryTerm = UNASSIGNED_PRIMARY_TERM;
                 seqNo = UNASSIGNED_SEQ_NO;
@@ -4609,7 +4608,7 @@ public class InternalEngineTests extends EngineTestCase {
     }
 
 
-    public void assertSameReader(Searcher left, Searcher right) {
+    public void assertSameReader(Engine.Searcher left, Engine.Searcher right) {
         List<LeafReaderContext> leftLeaves = ElasticsearchDirectoryReader.unwrap(left.getDirectoryReader()).leaves();
         List<LeafReaderContext> rightLeaves = ElasticsearchDirectoryReader.unwrap(right.getDirectoryReader()).leaves();
         assertEquals(rightLeaves.size(), leftLeaves.size());
@@ -4618,7 +4617,7 @@ public class InternalEngineTests extends EngineTestCase {
         }
     }
 
-    public void assertNotSameReader(Searcher left, Searcher right) {
+    public void assertNotSameReader(Engine.Searcher left, Engine.Searcher right) {
         List<LeafReaderContext> leftLeaves = ElasticsearchDirectoryReader.unwrap(left.getDirectoryReader()).leaves();
         List<LeafReaderContext> rightLeaves = ElasticsearchDirectoryReader.unwrap(right.getDirectoryReader()).leaves();
         if (rightLeaves.size() == leftLeaves.size()) {
@@ -4637,8 +4636,8 @@ public class InternalEngineTests extends EngineTestCase {
                  // disable merges to make sure that the reader doesn't change unexpectedly during the test
                  createEngine(defaultSettings, store, createTempDir(), NoMergePolicy.INSTANCE)) {
 
-            try (Searcher getSearcher = engine.acquireSearcher("test", Engine.SearcherScope.INTERNAL);
-                 Searcher searchSearcher = engine.acquireSearcher("test", Engine.SearcherScope.EXTERNAL)) {
+            try (Engine.Searcher getSearcher = engine.acquireSearcher("test", Engine.SearcherScope.INTERNAL);
+                 Engine.Searcher searchSearcher = engine.acquireSearcher("test", Engine.SearcherScope.EXTERNAL)) {
                 assertSameReader(getSearcher, searchSearcher);
             }
             for (int i = 0; i < 10; i++) {
@@ -4650,18 +4649,18 @@ public class InternalEngineTests extends EngineTestCase {
             }
             assertTrue(engine.refreshNeeded());
             engine.refresh("test", Engine.SearcherScope.INTERNAL, true);
-            try (Searcher getSearcher = engine.acquireSearcher("test", Engine.SearcherScope.INTERNAL);
-                 Searcher searchSearcher = engine.acquireSearcher("test", Engine.SearcherScope.EXTERNAL)) {
-                assertEquals(10, getSearcher.reader().numDocs());
-                assertEquals(0, searchSearcher.reader().numDocs());
+            try (Engine.Searcher getSearcher = engine.acquireSearcher("test", Engine.SearcherScope.INTERNAL);
+                 Engine.Searcher searchSearcher = engine.acquireSearcher("test", Engine.SearcherScope.EXTERNAL)) {
+                assertEquals(10, getSearcher.getIndexReader().numDocs());
+                assertEquals(0, searchSearcher.getIndexReader().numDocs());
                 assertNotSameReader(getSearcher, searchSearcher);
             }
             engine.refresh("test", Engine.SearcherScope.EXTERNAL, true);
 
-            try (Searcher getSearcher = engine.acquireSearcher("test", Engine.SearcherScope.INTERNAL);
-                 Searcher searchSearcher = engine.acquireSearcher("test", Engine.SearcherScope.EXTERNAL)) {
-                assertEquals(10, getSearcher.reader().numDocs());
-                assertEquals(10, searchSearcher.reader().numDocs());
+            try (Engine.Searcher getSearcher = engine.acquireSearcher("test", Engine.SearcherScope.INTERNAL);
+                 Engine.Searcher searchSearcher = engine.acquireSearcher("test", Engine.SearcherScope.EXTERNAL)) {
+                assertEquals(10, getSearcher.getIndexReader().numDocs());
+                assertEquals(10, searchSearcher.getIndexReader().numDocs());
                 assertSameReader(getSearcher, searchSearcher);
             }
 
@@ -4674,24 +4673,24 @@ public class InternalEngineTests extends EngineTestCase {
 
             engine.refresh("test", Engine.SearcherScope.EXTERNAL, true);
 
-            try (Searcher getSearcher = engine.acquireSearcher("test", Engine.SearcherScope.INTERNAL);
-                 Searcher searchSearcher = engine.acquireSearcher("test", Engine.SearcherScope.EXTERNAL)) {
-                assertEquals(11, getSearcher.reader().numDocs());
-                assertEquals(11, searchSearcher.reader().numDocs());
+            try (Engine.Searcher getSearcher = engine.acquireSearcher("test", Engine.SearcherScope.INTERNAL);
+                 Engine.Searcher searchSearcher = engine.acquireSearcher("test", Engine.SearcherScope.EXTERNAL)) {
+                assertEquals(11, getSearcher.getIndexReader().numDocs());
+                assertEquals(11, searchSearcher.getIndexReader().numDocs());
                 assertSameReader(getSearcher, searchSearcher);
             }
 
-            try (Searcher searcher = engine.acquireSearcher("test", Engine.SearcherScope.INTERNAL)) {
+            try (Engine.Searcher searcher = engine.acquireSearcher("test", Engine.SearcherScope.INTERNAL)) {
                 engine.refresh("test", Engine.SearcherScope.INTERNAL, true);
-                try (Searcher nextSearcher = engine.acquireSearcher("test", Engine.SearcherScope.INTERNAL)) {
-                    assertSame(searcher.searcher(), nextSearcher.searcher());
+                try (Engine.Searcher nextSearcher = engine.acquireSearcher("test", Engine.SearcherScope.INTERNAL)) {
+                    assertSame(searcher.getIndexReader(), nextSearcher.getIndexReader());
                 }
             }
 
-            try (Searcher searcher = engine.acquireSearcher("test", Engine.SearcherScope.EXTERNAL)) {
+            try (Engine.Searcher searcher = engine.acquireSearcher("test", Engine.SearcherScope.EXTERNAL)) {
                 engine.refresh("test", Engine.SearcherScope.EXTERNAL, true);
-                try (Searcher nextSearcher = engine.acquireSearcher("test", Engine.SearcherScope.EXTERNAL)) {
-                    assertSame(searcher.searcher(), nextSearcher.searcher());
+                try (Engine.Searcher nextSearcher = engine.acquireSearcher("test", Engine.SearcherScope.EXTERNAL)) {
+                    assertSame(searcher.getIndexReader(), nextSearcher.getIndexReader());
                 }
             }
         }
@@ -4869,13 +4868,13 @@ public class InternalEngineTests extends EngineTestCase {
         thread.join();
         engine.refresh("test", Engine.SearcherScope.INTERNAL, true);
         try (Engine.Searcher searcher = engine.acquireSearcher("test", Engine.SearcherScope.INTERNAL)) {
-            TopDocs search = searcher.searcher().search(new MatchAllDocsQuery(), searcher.reader().numDocs());
+            TopDocs search = searcher.search(new MatchAllDocsQuery(), searcher.getIndexReader().numDocs());
             for (int i = 0; i < search.scoreDocs.length; i++) {
-                org.apache.lucene.document.Document luceneDoc = searcher.searcher().doc(search.scoreDocs[i].doc);
+                org.apache.lucene.document.Document luceneDoc = searcher.doc(search.scoreDocs[i].doc);
                 assertEquals("updated", luceneDoc.get("value"));
             }
             int totalNumDocs = numDocs - numDeletes.get();
-            assertEquals(totalNumDocs, searcher.reader().numDocs());
+            assertEquals(totalNumDocs, searcher.getIndexReader().numDocs());
         }
     }
 
@@ -5762,7 +5761,7 @@ public class InternalEngineTests extends EngineTestCase {
                 engine.index(appendOnlyPrimary(doc, false, 1));
                 engine.refresh("test");
                 try (Engine.Searcher searcher = engine.acquireSearcher("test")) {
-                    LeafReader leafReader = getOnlyLeafReader(searcher.reader());
+                    LeafReader leafReader = getOnlyLeafReader(searcher.getIndexReader());
                     assertEquals(createdVersion.luceneVersion.major, leafReader.getMetaData().getCreatedVersionMajor());
                 }
             }
@@ -5921,8 +5920,8 @@ public class InternalEngineTests extends EngineTestCase {
             engine.delete(new Engine.Delete("_doc", "0", newUid("0"), primaryTerm.get()));
             engine.refresh("test");
             // now we have 2 segments since we now added a tombstone plus the old segment with the delete
-            try (Searcher searcher = engine.acquireSearcher("test")) {
-                IndexReader reader = searcher.reader();
+            try (Engine.Searcher searcher = engine.acquireSearcher("test")) {
+                IndexReader reader = searcher.getIndexReader();
                 assertEquals(2, reader.leaves().size());
                 LeafReaderContext leafReaderContext = reader.leaves().get(0);
                 LeafReader leafReader = leafReaderContext.reader();
@@ -5938,8 +5937,8 @@ public class InternalEngineTests extends EngineTestCase {
             // lets force merge the tombstone and the original segment and make sure the doc is still there but the ID term is gone
             engine.forceMerge(true);
             engine.refresh("test");
-            try (Searcher searcher = engine.acquireSearcher("test")) {
-                IndexReader reader = searcher.reader();
+            try (Engine.Searcher searcher = engine.acquireSearcher("test")) {
+                IndexReader reader = searcher.getIndexReader();
                 assertEquals(1, reader.leaves().size());
                 LeafReaderContext leafReaderContext = reader.leaves().get(0);
                 LeafReader leafReader = leafReaderContext.reader();

+ 4 - 4
server/src/test/java/org/elasticsearch/index/engine/LuceneChangesSnapshotTests.java

@@ -93,7 +93,7 @@ public class LuceneChangesSnapshotTests extends EngineTestCase {
 
             Engine.Searcher searcher = engine.acquireSearcher("test", Engine.SearcherScope.INTERNAL);
             try (Translog.Snapshot snapshot = new LuceneChangesSnapshot(
-                searcher, mapperService, between(1, LuceneChangesSnapshot.DEFAULT_BATCH_SIZE), fromSeqNo, toSeqNo, false)) {
+                    searcher, mapperService, between(1, LuceneChangesSnapshot.DEFAULT_BATCH_SIZE), fromSeqNo, toSeqNo, false)) {
                 searcher = null;
                 assertThat(snapshot, SnapshotMatchers.size(0));
             } finally {
@@ -115,7 +115,7 @@ public class LuceneChangesSnapshotTests extends EngineTestCase {
             toSeqNo = randomLongBetween(refreshedSeqNo + 1, numOps * 2);
             Engine.Searcher searcher = engine.acquireSearcher("test", Engine.SearcherScope.INTERNAL);
             try (Translog.Snapshot snapshot = new LuceneChangesSnapshot(
-                searcher, mapperService, between(1, LuceneChangesSnapshot.DEFAULT_BATCH_SIZE), fromSeqNo, toSeqNo, false)) {
+                    searcher, mapperService, between(1, LuceneChangesSnapshot.DEFAULT_BATCH_SIZE), fromSeqNo, toSeqNo, false)) {
                 searcher = null;
                 assertThat(snapshot, SnapshotMatchers.containsSeqNoRange(fromSeqNo, refreshedSeqNo));
             } finally {
@@ -134,7 +134,7 @@ public class LuceneChangesSnapshotTests extends EngineTestCase {
             toSeqNo = randomLongBetween(fromSeqNo, refreshedSeqNo);
             searcher = engine.acquireSearcher("test", Engine.SearcherScope.INTERNAL);
             try (Translog.Snapshot snapshot = new LuceneChangesSnapshot(
-                searcher, mapperService, between(1, LuceneChangesSnapshot.DEFAULT_BATCH_SIZE), fromSeqNo, toSeqNo, true)) {
+                    searcher, mapperService, between(1, LuceneChangesSnapshot.DEFAULT_BATCH_SIZE), fromSeqNo, toSeqNo, true)) {
                 searcher = null;
                 assertThat(snapshot, SnapshotMatchers.containsSeqNoRange(fromSeqNo, toSeqNo));
             } finally {
@@ -184,7 +184,7 @@ public class LuceneChangesSnapshotTests extends EngineTestCase {
         engine.refresh("test");
         Engine.Searcher searcher = engine.acquireSearcher("test", Engine.SearcherScope.INTERNAL);
         try (Translog.Snapshot snapshot = new LuceneChangesSnapshot(searcher, mapperService, between(1, 100), 0, maxSeqNo, false)) {
-            searcher = null;
+                searcher = null;
             Translog.Operation op;
             while ((op = snapshot.next()) != null) {
                 assertThat(op.toString(), op.primaryTerm(), equalTo(seqNoToTerm.get(op.seqNo())));

+ 2 - 2
server/src/test/java/org/elasticsearch/index/engine/ReadOnlyEngineTests.java

@@ -87,8 +87,8 @@ public class ReadOnlyEngineTests extends EngineTestCase {
                 }
                 Engine.Searcher external = readOnlyEngine.acquireSearcher("test", Engine.SearcherScope.EXTERNAL);
                 Engine.Searcher internal = readOnlyEngine.acquireSearcher("test", Engine.SearcherScope.INTERNAL);
-                assertSame(external.reader(), internal.reader());
-                assertThat(external.reader(), instanceOf(DirectoryReader.class));
+                assertSame(external.getIndexReader(), internal.getIndexReader());
+                assertThat(external.getIndexReader(), instanceOf(DirectoryReader.class));
                 DirectoryReader dirReader = external.getDirectoryReader();
                 ElasticsearchDirectoryReader esReader = getElasticsearchDirectoryReader(dirReader);
                 IndexReader.CacheHelper helper = esReader.getReaderCacheHelper();

+ 1 - 1
server/src/test/java/org/elasticsearch/index/replication/IndexLevelReplicationTests.java

@@ -307,7 +307,7 @@ public class IndexLevelReplicationTests extends ESIndexLevelReplicationTestCase
             shards.refresh("test");
             for (IndexShard shard : shards) {
                 try (Engine.Searcher searcher = shard.acquireSearcher("test")) {
-                    TopDocs search = searcher.searcher().search(new TermQuery(new Term("f", "2")), 10);
+                    TopDocs search = searcher.search(new TermQuery(new Term("f", "2")), 10);
                     assertEquals("shard " + shard.routingEntry() + " misses new version", 1, search.totalHits.value);
                 }
             }

+ 1 - 1
server/src/test/java/org/elasticsearch/index/search/MultiMatchQueryTests.java

@@ -110,7 +110,7 @@ public class MultiMatchQueryTests extends ESSingleNodeTestCase {
                 .tieBreaker(tieBreaker)
                 .toQuery(queryShardContext);
             try (Engine.Searcher searcher = indexService.getShard(0).acquireSearcher("test")) {
-                Query rewrittenQuery = searcher.searcher().rewrite(parsedQuery);
+                Query rewrittenQuery = searcher.rewrite(parsedQuery);
                 Query tq1 = new BoostQuery(new TermQuery(new Term("name.last", "banon")), 3);
                 Query tq2 = new BoostQuery(new TermQuery(new Term("name.first", "banon")), 2);
                 Query expected = new DisjunctionMaxQuery(Arrays.asList(tq2, tq1), tieBreaker);

+ 14 - 8
server/src/test/java/org/elasticsearch/index/shard/IndexReaderWrapperTests.java

@@ -65,17 +65,19 @@ public class IndexReaderWrapperTests extends ESTestCase {
         final AtomicInteger count = new AtomicInteger();
         final AtomicInteger outerCount = new AtomicInteger();
         final AtomicBoolean closeCalled = new AtomicBoolean(false);
-        final Engine.Searcher wrap =  IndexShard.wrapSearcher(new Engine.Searcher("foo", searcher, () -> closeCalled.set(true)), wrapper);
-        assertEquals(1, wrap.reader().getRefCount());
+        final Engine.Searcher wrap =  IndexShard.wrapSearcher(new Engine.Searcher("foo", open,
+            IndexSearcher.getDefaultSimilarity(), IndexSearcher.getDefaultQueryCache(), IndexSearcher.getDefaultQueryCachingPolicy(),
+            () -> closeCalled.set(true)), wrapper);
+        assertEquals(1, wrap.getIndexReader().getRefCount());
         ElasticsearchDirectoryReader.addReaderCloseListener(wrap.getDirectoryReader(), key -> {
             if (key == open.getReaderCacheHelper().getKey()) {
                 count.incrementAndGet();
             }
             outerCount.incrementAndGet();
         });
-        assertEquals(0, wrap.searcher().search(new TermQuery(new Term("field", "doc")), 1).totalHits.value);
+        assertEquals(0, wrap.search(new TermQuery(new Term("field", "doc")), 1).totalHits.value);
         wrap.close();
-        assertFalse("wrapped reader is closed", wrap.reader().tryIncRef());
+        assertFalse("wrapped reader is closed", wrap.getIndexReader().tryIncRef());
         assertEquals(sourceRefCount, open.getRefCount());
         assertTrue(closeCalled.get());
         assertEquals(1, closeCalls.get());
@@ -104,12 +106,14 @@ public class IndexReaderWrapperTests extends ESTestCase {
             reader -> new FieldMaskingReader("field", reader, closeCalls);
         final ConcurrentHashMap<Object, TopDocs> cache = new ConcurrentHashMap<>();
         AtomicBoolean closeCalled = new AtomicBoolean(false);
-        try (Engine.Searcher wrap = IndexShard.wrapSearcher(new Engine.Searcher("foo", searcher, () -> closeCalled.set(true)), wrapper)) {
+        try (Engine.Searcher wrap =  IndexShard.wrapSearcher(new Engine.Searcher("foo", open,
+                IndexSearcher.getDefaultSimilarity(), IndexSearcher.getDefaultQueryCache(), IndexSearcher.getDefaultQueryCachingPolicy(),
+                () -> closeCalled.set(true)), wrapper)) {
             ElasticsearchDirectoryReader.addReaderCloseListener(wrap.getDirectoryReader(), key -> {
                 cache.remove(key);
             });
-            TopDocs search = wrap.searcher().search(new TermQuery(new Term("field", "doc")), 1);
-            cache.put(wrap.reader().getReaderCacheHelper().getKey(), search);
+            TopDocs search = wrap.search(new TermQuery(new Term("field", "doc")), 1);
+            cache.put(wrap.getIndexReader().getReaderCacheHelper().getKey(), search);
         }
         assertTrue(closeCalled.get());
         assertEquals(1, closeCalls.get());
@@ -133,7 +137,9 @@ public class IndexReaderWrapperTests extends ESTestCase {
         assertEquals(1, searcher.search(new TermQuery(new Term("field", "doc")), 1).totalHits.value);
         searcher.setSimilarity(iwc.getSimilarity());
         CheckedFunction<DirectoryReader, DirectoryReader, IOException> wrapper = directoryReader -> directoryReader;
-        try (Engine.Searcher engineSearcher = new Engine.Searcher("foo", searcher, open::close)) {
+        try (Engine.Searcher engineSearcher =  IndexShard.wrapSearcher(new Engine.Searcher("foo", open,
+                IndexSearcher.getDefaultSimilarity(), IndexSearcher.getDefaultQueryCache(), IndexSearcher.getDefaultQueryCachingPolicy(),
+                open::close), wrapper)) {
             final Engine.Searcher wrap = IndexShard.wrapSearcher(engineSearcher, wrapper);
             assertSame(wrap, engineSearcher);
         }

+ 1 - 1
server/src/test/java/org/elasticsearch/index/shard/IndexShardIT.java

@@ -901,7 +901,7 @@ public class IndexShardIT extends ESSingleNodeTestCase {
         shard.refresh("test");
         try (Engine.Searcher searcher = shard.acquireSearcher("test")) {
             assertThat("numDocs=" + numDocs + " moreDocs=" + moreDocs,
-                (long) searcher.reader().numDocs(), equalTo(numDocs + moreDocs));
+                (long) searcher.getIndexReader().numDocs(), equalTo(numDocs + moreDocs));
         }
         assertThat("numDocs=" + numDocs + " moreDocs=" + moreDocs,
             client().search(countRequest).actionGet().getHits().getTotalHits().value, equalTo(numDocs + moreDocs));

+ 12 - 12
server/src/test/java/org/elasticsearch/index/shard/IndexShardTests.java

@@ -2373,9 +2373,9 @@ public class IndexShardTests extends IndexShardTestCase {
             assertNotNull(getResult.searcher());
         }
         try (Engine.Searcher searcher = shard.acquireSearcher("test")) {
-            TopDocs search = searcher.searcher().search(new TermQuery(new Term("foo", "bar")), 10);
+            TopDocs search = searcher.search(new TermQuery(new Term("foo", "bar")), 10);
             assertEquals(search.totalHits.value, 1);
-            search = searcher.searcher().search(new TermQuery(new Term("foobar", "bar")), 10);
+            search = searcher.search(new TermQuery(new Term("foobar", "bar")), 10);
             assertEquals(search.totalHits.value, 1);
         }
         CheckedFunction<DirectoryReader, DirectoryReader, IOException> wrapper = reader -> new FieldMaskingReader("foo", reader);
@@ -2394,9 +2394,9 @@ public class IndexShardTests extends IndexShardTestCase {
         recoverShardFromStore(newShard);
 
         try (Engine.Searcher searcher = newShard.acquireSearcher("test")) {
-            TopDocs search = searcher.searcher().search(new TermQuery(new Term("foo", "bar")), 10);
+            TopDocs search = searcher.search(new TermQuery(new Term("foo", "bar")), 10);
             assertEquals(search.totalHits.value, 0);
-            search = searcher.searcher().search(new TermQuery(new Term("foobar", "bar")), 10);
+            search = searcher.search(new TermQuery(new Term("foobar", "bar")), 10);
             assertEquals(search.totalHits.value, 1);
         }
         try (Engine.GetResult getResult = newShard
@@ -2404,7 +2404,7 @@ public class IndexShardTests extends IndexShardTestCase {
                     new Term(IdFieldMapper.NAME, Uid.encodeId("1"))))) {
             assertTrue(getResult.exists());
             assertNotNull(getResult.searcher()); // make sure get uses the wrapped reader
-            assertTrue(getResult.searcher().reader() instanceof FieldMaskingReader);
+            assertTrue(getResult.searcher().getIndexReader() instanceof FieldMaskingReader);
         }
 
         closeShards(newShard);
@@ -2900,7 +2900,7 @@ public class IndexShardTests extends IndexShardTestCase {
                 assertThat("searcher was marked as accessed", shard.getLastSearcherAccess(), equalTo(prevAccessTime));
                 assertThat(docsStats.getCount(), equalTo(numDocs));
                 try (Engine.Searcher searcher = indexShard.acquireSearcher("test")) {
-                    assertTrue(searcher.reader().numDocs() <= docsStats.getCount());
+                    assertTrue(searcher.getIndexReader().numDocs() <= docsStats.getCount());
                 }
                 assertThat(docsStats.getDeleted(), equalTo(0L));
                 assertThat(docsStats.getAverageSizeInBytes(), greaterThan(0L));
@@ -2938,7 +2938,7 @@ public class IndexShardTests extends IndexShardTestCase {
             {
                 final DocsStats docStats = indexShard.docStats();
                 try (Engine.Searcher searcher = indexShard.acquireSearcher("test")) {
-                    assertTrue(searcher.reader().numDocs() <= docStats.getCount());
+                    assertTrue(searcher.getIndexReader().numDocs() <= docStats.getCount());
                 }
                 assertThat(docStats.getCount(), equalTo(numDocs));
             }
@@ -3385,7 +3385,7 @@ public class IndexShardTests extends IndexShardTestCase {
             primary.awaitShardSearchActive(refreshed -> {
                 assertTrue(refreshed);
                 try (Engine.Searcher searcher = primary.acquireSearcher("test")) {
-                    assertEquals(2, searcher.reader().numDocs());
+                    assertEquals(2, searcher.getIndexReader().numDocs());
                 } finally {
                     latch.countDown();
                 }
@@ -3395,7 +3395,7 @@ public class IndexShardTests extends IndexShardTestCase {
             primary.getLastSearcherAccess());
         assertTrue(lastSearchAccess < primary.getLastSearcherAccess());
         try (Engine.Searcher searcher = primary.acquireSearcher("test")) {
-            assertEquals(1, searcher.reader().numDocs());
+            assertEquals(1, searcher.getIndexReader().numDocs());
         }
         assertTrue(primary.getEngine().refreshNeeded());
         assertTrue(primary.scheduledRefresh());
@@ -3404,7 +3404,7 @@ public class IndexShardTests extends IndexShardTestCase {
         primary.awaitShardSearchActive(refreshed -> {
             assertFalse(refreshed);
             try (Engine.Searcher searcher = primary.acquireSearcher("test")) {
-                assertEquals(2, searcher.reader().numDocs());
+                assertEquals(2, searcher.getIndexReader().numDocs());
             } finally {
                 latch1.countDown();
             }
@@ -3418,7 +3418,7 @@ public class IndexShardTests extends IndexShardTestCase {
         primary.checkIdle(0);
         assertTrue(primary.scheduledRefresh()); // make sure we refresh once the shard is inactive
         try (Engine.Searcher searcher = primary.acquireSearcher("test")) {
-            assertEquals(3, searcher.reader().numDocs());
+            assertEquals(3, searcher.getIndexReader().numDocs());
         }
         closeShards(primary);
     }
@@ -3573,7 +3573,7 @@ public class IndexShardTests extends IndexShardTestCase {
                         }
 
                         if (randomBoolean() && searchers.size() > 1) {
-                            // Close one of the searchers at random
+                            // Close one of the readers at random
                             synchronized (searchers) {
                                 // re-check because it could have decremented after the check
                                 if (searchers.size() > 1) {

+ 3 - 3
server/src/test/java/org/elasticsearch/index/shard/ShardGetServiceTests.java

@@ -53,7 +53,7 @@ public class ShardGetServiceTests extends IndexShardTestCase {
         assertFalse(testGet.getFields().containsKey(RoutingFieldMapper.NAME));
         assertEquals(new String(testGet.source(), StandardCharsets.UTF_8), "{\"foo\" : \"bar\"}");
         try (Engine.Searcher searcher = primary.getEngine().acquireSearcher("test", Engine.SearcherScope.INTERNAL)) {
-            assertEquals(searcher.reader().maxDoc(), 1); // we refreshed
+            assertEquals(searcher.getIndexReader().maxDoc(), 1); // we refreshed
         }
 
         Engine.IndexResult test1 = indexDoc(primary, "test", "1", "{\"foo\" : \"baz\"}",  XContentType.JSON, "foobar");
@@ -63,11 +63,11 @@ public class ShardGetServiceTests extends IndexShardTestCase {
         assertTrue(testGet1.getFields().containsKey(RoutingFieldMapper.NAME));
         assertEquals("foobar", testGet1.getFields().get(RoutingFieldMapper.NAME).getValue());
         try (Engine.Searcher searcher = primary.getEngine().acquireSearcher("test", Engine.SearcherScope.INTERNAL)) {
-            assertEquals(searcher.reader().maxDoc(), 1); // we read from the translog
+            assertEquals(searcher.getIndexReader().maxDoc(), 1); // we read from the translog
         }
         primary.getEngine().refresh("test");
         try (Engine.Searcher searcher = primary.getEngine().acquireSearcher("test", Engine.SearcherScope.INTERNAL)) {
-            assertEquals(searcher.reader().maxDoc(), 2);
+            assertEquals(searcher.getIndexReader().maxDoc(), 2);
         }
 
         // now again from the reader

+ 11 - 11
server/src/test/java/org/elasticsearch/indices/IndicesServiceCloseTests.java

@@ -32,7 +32,7 @@ import org.elasticsearch.env.Environment;
 import org.elasticsearch.env.NodeEnvironment;
 import org.elasticsearch.index.IndexModule;
 import org.elasticsearch.index.IndexService;
-import org.elasticsearch.index.engine.Engine.Searcher;
+import org.elasticsearch.index.engine.Engine;
 import org.elasticsearch.index.shard.IndexShard;
 import org.elasticsearch.indices.IndicesRequestCache.Key;
 import org.elasticsearch.indices.breaker.HierarchyCircuitBreakerService;
@@ -156,8 +156,8 @@ public class IndicesServiceCloseTests extends ESTestCase {
 
         IndexService indexService = indicesService.iterator().next();
         IndexShard shard = indexService.getShard(0);
-        Searcher searcher = shard.acquireSearcher("test");
-        assertEquals(1, searcher.reader().maxDoc());
+        Engine.Searcher searcher = shard.acquireSearcher("test");
+        assertEquals(1, searcher.getIndexReader().maxDoc());
 
         node.close();
         assertEquals(1, indicesService.indicesRefCount.refCount());
@@ -184,12 +184,12 @@ public class IndicesServiceCloseTests extends ESTestCase {
 
         IndexService indexService = indicesService.iterator().next();
         IndexShard shard = indexService.getShard(0);
-        Searcher searcher = shard.acquireSearcher("test");
-        assertEquals(1, searcher.reader().maxDoc());
+        Engine.Searcher searcher = shard.acquireSearcher("test");
+        assertEquals(1, searcher.getIndexReader().maxDoc());
 
         Query query = LongPoint.newRangeQuery("foo", 0, 5);
         assertEquals(0L, cache.getStats(shard.shardId()).getCacheSize());
-        searcher.searcher().count(query);
+        searcher.count(query);
         assertEquals(1L, cache.getStats(shard.shardId()).getCacheSize());
 
         searcher.close();
@@ -219,15 +219,15 @@ public class IndicesServiceCloseTests extends ESTestCase {
 
         IndexService indexService = indicesService.iterator().next();
         IndexShard shard = indexService.getShard(0);
-        Searcher searcher = shard.acquireSearcher("test");
-        assertEquals(1, searcher.reader().maxDoc());
+        Engine.Searcher searcher = shard.acquireSearcher("test");
+        assertEquals(1, searcher.getIndexReader().maxDoc());
 
         node.close();
         assertEquals(1, indicesService.indicesRefCount.refCount());
 
         Query query = LongPoint.newRangeQuery("foo", 0, 5);
         assertEquals(0L, cache.getStats(shard.shardId()).getCacheSize());
-        searcher.searcher().count(query);
+        searcher.count(query);
         assertEquals(1L, cache.getStats(shard.shardId()).getCacheSize());
 
         searcher.close();
@@ -253,8 +253,8 @@ public class IndicesServiceCloseTests extends ESTestCase {
 
         IndexService indexService = indicesService.iterator().next();
         IndexShard shard = indexService.getShard(0);
-        Searcher searcher = shard.acquireSearcher("test");
-        assertEquals(1, searcher.reader().maxDoc());
+        Engine.Searcher searcher = shard.acquireSearcher("test");
+        assertEquals(1, searcher.getIndexReader().maxDoc());
 
         node.close();
         assertEquals(1, indicesService.indicesRefCount.refCount());

+ 3 - 2
server/src/test/java/org/elasticsearch/search/DefaultSearchContextTests.java

@@ -63,7 +63,6 @@ import static org.mockito.Matchers.eq;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
 
-
 public class DefaultSearchContextTests extends ESTestCase {
 
     public void testPreProcess() throws Exception {
@@ -110,7 +109,9 @@ public class DefaultSearchContextTests extends ESTestCase {
         try (Directory dir = newDirectory();
              RandomIndexWriter w = new RandomIndexWriter(random(), dir);
              IndexReader reader = w.getReader();
-             Engine.Searcher searcher = new Engine.Searcher("test", new IndexSearcher(reader), reader)) {
+             Engine.Searcher searcher = new Engine.Searcher("test", reader,
+                 IndexSearcher.getDefaultSimilarity(), IndexSearcher.getDefaultQueryCache(),
+                 IndexSearcher.getDefaultQueryCachingPolicy(), reader)) {
 
             SearchShardTarget target = new SearchShardTarget("node", shardId, null, OriginalIndices.NONE);
 

+ 33 - 33
server/src/test/java/org/elasticsearch/search/aggregations/support/ValuesSourceConfigTests.java

@@ -25,7 +25,7 @@ import org.apache.lucene.util.BytesRef;
 import org.elasticsearch.action.support.WriteRequest;
 import org.elasticsearch.common.settings.Settings;
 import org.elasticsearch.index.IndexService;
-import org.elasticsearch.index.engine.Engine.Searcher;
+import org.elasticsearch.index.engine.Engine;
 import org.elasticsearch.index.fielddata.SortedBinaryDocValues;
 import org.elasticsearch.index.mapper.TypeFieldMapper;
 import org.elasticsearch.index.query.QueryShardContext;
@@ -41,13 +41,13 @@ public class ValuesSourceConfigTests extends ESSingleNodeTestCase {
                 .setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE)
                 .get();
 
-        try (Searcher searcher = indexService.getShard(0).acquireSearcher("test")) {
-            QueryShardContext context = indexService.newQueryShardContext(0, searcher.reader(), () -> 42L, null);
+        try (Engine.Searcher searcher = indexService.getShard(0).acquireSearcher("test")) {
+            QueryShardContext context = indexService.newQueryShardContext(0, searcher.getIndexReader(), () -> 42L, null);
 
             ValuesSourceConfig<ValuesSource.Bytes> config = ValuesSourceConfig.resolve(
                     context, null, "bytes", null, null, null, null);
             ValuesSource.Bytes valuesSource = config.toValuesSource(context);
-            LeafReaderContext ctx = searcher.reader().leaves().get(0);
+            LeafReaderContext ctx = searcher.getIndexReader().leaves().get(0);
             SortedBinaryDocValues values = valuesSource.bytesValues(ctx);
             assertTrue(values.advanceExact(0));
             assertEquals(1, values.docValueCount());
@@ -63,13 +63,13 @@ public class ValuesSourceConfigTests extends ESSingleNodeTestCase {
                 .setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE)
                 .get();
 
-        try (Searcher searcher = indexService.getShard(0).acquireSearcher("test")) {
-            QueryShardContext context = indexService.newQueryShardContext(0, searcher.reader(), () -> 42L, null);
+        try (Engine.Searcher searcher = indexService.getShard(0).acquireSearcher("test")) {
+            QueryShardContext context = indexService.newQueryShardContext(0, searcher.getIndexReader(), () -> 42L, null);
 
             ValuesSourceConfig<ValuesSource.Bytes> config = ValuesSourceConfig.resolve(
                     context, null, "bytes", null, null, null, null);
             ValuesSource.Bytes valuesSource = config.toValuesSource(context);
-            LeafReaderContext ctx = searcher.reader().leaves().get(0);
+            LeafReaderContext ctx = searcher.getIndexReader().leaves().get(0);
             SortedBinaryDocValues values = valuesSource.bytesValues(ctx);
             assertFalse(values.advanceExact(0));
 
@@ -90,8 +90,8 @@ public class ValuesSourceConfigTests extends ESSingleNodeTestCase {
                 .setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE)
                 .get();
 
-        try (Searcher searcher = indexService.getShard(0).acquireSearcher("test")) {
-            QueryShardContext context = indexService.newQueryShardContext(0, searcher.reader(), () -> 42L, null);
+        try (Engine.Searcher searcher = indexService.getShard(0).acquireSearcher("test")) {
+            QueryShardContext context = indexService.newQueryShardContext(0, searcher.getIndexReader(), () -> 42L, null);
             ValuesSourceConfig<ValuesSource.Bytes> config = ValuesSourceConfig.resolve(
                     context, ValueType.STRING, "bytes", null, null, null, null);
             ValuesSource.Bytes valuesSource = config.toValuesSource(context);
@@ -100,7 +100,7 @@ public class ValuesSourceConfigTests extends ESSingleNodeTestCase {
             config = ValuesSourceConfig.resolve(
                     context, ValueType.STRING, "bytes", null, "abc", null, null);
             valuesSource = config.toValuesSource(context);
-            LeafReaderContext ctx = searcher.reader().leaves().get(0);
+            LeafReaderContext ctx = searcher.getIndexReader().leaves().get(0);
             SortedBinaryDocValues values = valuesSource.bytesValues(ctx);
             assertTrue(values.advanceExact(0));
             assertEquals(1, values.docValueCount());
@@ -116,13 +116,13 @@ public class ValuesSourceConfigTests extends ESSingleNodeTestCase {
                 .setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE)
                 .get();
 
-        try (Searcher searcher = indexService.getShard(0).acquireSearcher("test")) {
-            QueryShardContext context = indexService.newQueryShardContext(0, searcher.reader(), () -> 42L, null);
+        try (Engine.Searcher searcher = indexService.getShard(0).acquireSearcher("test")) {
+            QueryShardContext context = indexService.newQueryShardContext(0, searcher.getIndexReader(), () -> 42L, null);
 
             ValuesSourceConfig<ValuesSource.Numeric> config = ValuesSourceConfig.resolve(
                     context, null, "long", null, null, null, null);
             ValuesSource.Numeric valuesSource = config.toValuesSource(context);
-            LeafReaderContext ctx = searcher.reader().leaves().get(0);
+            LeafReaderContext ctx = searcher.getIndexReader().leaves().get(0);
             SortedNumericDocValues values = valuesSource.longValues(ctx);
             assertTrue(values.advanceExact(0));
             assertEquals(1, values.docValueCount());
@@ -138,13 +138,13 @@ public class ValuesSourceConfigTests extends ESSingleNodeTestCase {
                 .setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE)
                 .get();
 
-        try (Searcher searcher = indexService.getShard(0).acquireSearcher("test")) {
-            QueryShardContext context = indexService.newQueryShardContext(0, searcher.reader(), () -> 42L, null);
+        try (Engine.Searcher searcher = indexService.getShard(0).acquireSearcher("test")) {
+            QueryShardContext context = indexService.newQueryShardContext(0, searcher.getIndexReader(), () -> 42L, null);
 
             ValuesSourceConfig<ValuesSource.Numeric> config = ValuesSourceConfig.resolve(
                     context, null, "long", null, null, null, null);
             ValuesSource.Numeric valuesSource = config.toValuesSource(context);
-            LeafReaderContext ctx = searcher.reader().leaves().get(0);
+            LeafReaderContext ctx = searcher.getIndexReader().leaves().get(0);
             SortedNumericDocValues values = valuesSource.longValues(ctx);
             assertFalse(values.advanceExact(0));
 
@@ -165,8 +165,8 @@ public class ValuesSourceConfigTests extends ESSingleNodeTestCase {
                 .setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE)
                 .get();
 
-        try (Searcher searcher = indexService.getShard(0).acquireSearcher("test")) {
-            QueryShardContext context = indexService.newQueryShardContext(0, searcher.reader(), () -> 42L, null);
+        try (Engine.Searcher searcher = indexService.getShard(0).acquireSearcher("test")) {
+            QueryShardContext context = indexService.newQueryShardContext(0, searcher.getIndexReader(), () -> 42L, null);
 
             ValuesSourceConfig<ValuesSource.Numeric> config = ValuesSourceConfig.resolve(
                     context, ValueType.NUMBER, "long", null, null, null, null);
@@ -176,7 +176,7 @@ public class ValuesSourceConfigTests extends ESSingleNodeTestCase {
             config = ValuesSourceConfig.resolve(
                     context, ValueType.NUMBER, "long", null, 42, null, null);
             valuesSource = config.toValuesSource(context);
-            LeafReaderContext ctx = searcher.reader().leaves().get(0);
+            LeafReaderContext ctx = searcher.getIndexReader().leaves().get(0);
             SortedNumericDocValues values = valuesSource.longValues(ctx);
             assertTrue(values.advanceExact(0));
             assertEquals(1, values.docValueCount());
@@ -192,13 +192,13 @@ public class ValuesSourceConfigTests extends ESSingleNodeTestCase {
                 .setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE)
                 .get();
 
-        try (Searcher searcher = indexService.getShard(0).acquireSearcher("test")) {
-            QueryShardContext context = indexService.newQueryShardContext(0, searcher.reader(), () -> 42L, null);
+        try (Engine.Searcher searcher = indexService.getShard(0).acquireSearcher("test")) {
+            QueryShardContext context = indexService.newQueryShardContext(0, searcher.getIndexReader(), () -> 42L, null);
 
             ValuesSourceConfig<ValuesSource.Numeric> config = ValuesSourceConfig.resolve(
                     context, null, "bool", null, null, null, null);
             ValuesSource.Numeric valuesSource = config.toValuesSource(context);
-            LeafReaderContext ctx = searcher.reader().leaves().get(0);
+            LeafReaderContext ctx = searcher.getIndexReader().leaves().get(0);
             SortedNumericDocValues values = valuesSource.longValues(ctx);
             assertTrue(values.advanceExact(0));
             assertEquals(1, values.docValueCount());
@@ -214,13 +214,13 @@ public class ValuesSourceConfigTests extends ESSingleNodeTestCase {
                 .setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE)
                 .get();
 
-        try (Searcher searcher = indexService.getShard(0).acquireSearcher("test")) {
-            QueryShardContext context = indexService.newQueryShardContext(0, searcher.reader(), () -> 42L, null);
+        try (Engine.Searcher searcher = indexService.getShard(0).acquireSearcher("test")) {
+            QueryShardContext context = indexService.newQueryShardContext(0, searcher.getIndexReader(), () -> 42L, null);
 
             ValuesSourceConfig<ValuesSource.Numeric> config = ValuesSourceConfig.resolve(
                     context, null, "bool", null, null, null, null);
             ValuesSource.Numeric valuesSource = config.toValuesSource(context);
-            LeafReaderContext ctx = searcher.reader().leaves().get(0);
+            LeafReaderContext ctx = searcher.getIndexReader().leaves().get(0);
             SortedNumericDocValues values = valuesSource.longValues(ctx);
             assertFalse(values.advanceExact(0));
 
@@ -241,8 +241,8 @@ public class ValuesSourceConfigTests extends ESSingleNodeTestCase {
                 .setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE)
                 .get();
 
-        try (Searcher searcher = indexService.getShard(0).acquireSearcher("test")) {
-            QueryShardContext context = indexService.newQueryShardContext(0, searcher.reader(), () -> 42L, null);
+        try (Engine.Searcher searcher = indexService.getShard(0).acquireSearcher("test")) {
+            QueryShardContext context = indexService.newQueryShardContext(0, searcher.getIndexReader(), () -> 42L, null);
 
             ValuesSourceConfig<ValuesSource.Numeric> config = ValuesSourceConfig.resolve(
                     context, ValueType.BOOLEAN, "bool", null, null, null, null);
@@ -252,7 +252,7 @@ public class ValuesSourceConfigTests extends ESSingleNodeTestCase {
             config = ValuesSourceConfig.resolve(
                     context, ValueType.BOOLEAN, "bool", null, true, null, null);
             valuesSource = config.toValuesSource(context);
-            LeafReaderContext ctx = searcher.reader().leaves().get(0);
+            LeafReaderContext ctx = searcher.getIndexReader().leaves().get(0);
             SortedNumericDocValues values = valuesSource.longValues(ctx);
             assertTrue(values.advanceExact(0));
             assertEquals(1, values.docValueCount());
@@ -262,8 +262,8 @@ public class ValuesSourceConfigTests extends ESSingleNodeTestCase {
 
     public void testTypeFieldDeprecation() {
         IndexService indexService = createIndex("index", Settings.EMPTY, "type");
-        try (Searcher searcher = indexService.getShard(0).acquireSearcher("test")) {
-            QueryShardContext context = indexService.newQueryShardContext(0, searcher.reader(), () -> 42L, null);
+        try (Engine.Searcher searcher = indexService.getShard(0).acquireSearcher("test")) {
+            QueryShardContext context = indexService.newQueryShardContext(0, searcher.getIndexReader(), () -> 42L, null);
 
             ValuesSourceConfig<ValuesSource.Bytes> config = ValuesSourceConfig.resolve(
                 context, null, TypeFieldMapper.NAME, null, null, null, null);
@@ -279,13 +279,13 @@ public class ValuesSourceConfigTests extends ESSingleNodeTestCase {
             .setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE)
             .get();
 
-        try (Searcher searcher = indexService.getShard(0).acquireSearcher("test")) {
-            QueryShardContext context = indexService.newQueryShardContext(0, searcher.reader(), () -> 42L, null);
+        try (Engine.Searcher searcher = indexService.getShard(0).acquireSearcher("test")) {
+            QueryShardContext context = indexService.newQueryShardContext(0, searcher.getIndexReader(), () -> 42L, null);
             ValuesSourceConfig<ValuesSource.Bytes> config = ValuesSourceConfig.resolve(
                 context, ValueType.STRING, "alias", null, null, null, null);
             ValuesSource.Bytes valuesSource = config.toValuesSource(context);
 
-            LeafReaderContext ctx = searcher.reader().leaves().get(0);
+            LeafReaderContext ctx = searcher.getIndexReader().leaves().get(0);
             SortedBinaryDocValues values = valuesSource.bytesValues(ctx);
             assertTrue(values.advanceExact(0));
             assertEquals(1, values.docValueCount());

+ 4 - 4
test/framework/src/main/java/org/elasticsearch/index/engine/EngineTestCase.java

@@ -166,7 +166,7 @@ public abstract class EngineTestCase extends ESTestCase {
         }
         try (Engine.Searcher searcher = engine.acquireSearcher("test")) {
             final TotalHitCountCollector collector = new TotalHitCountCollector();
-            searcher.searcher().search(new MatchAllDocsQuery(), collector);
+            searcher.search(new MatchAllDocsQuery(), collector);
             assertThat(collector.getTotalHits(), equalTo(numDocs));
         }
     }
@@ -769,7 +769,7 @@ public abstract class EngineTestCase extends ESTestCase {
         }
         try (Engine.Searcher searcher = engine.acquireSearcher("test")) {
             final TotalHitCountCollector collector = new TotalHitCountCollector();
-            searcher.searcher().search(new MatchAllDocsQuery(), collector);
+            searcher.search(new MatchAllDocsQuery(), collector);
             assertThat(collector.getTotalHits(), equalTo(numDocs));
         }
     }
@@ -927,7 +927,7 @@ public abstract class EngineTestCase extends ESTestCase {
         if (lastFieldValue != null) {
             try (Engine.Searcher searcher = replicaEngine.acquireSearcher("test")) {
                 final TotalHitCountCollector collector = new TotalHitCountCollector();
-                searcher.searcher().search(new TermQuery(new Term("value", lastFieldValue)), collector);
+                searcher.search(new TermQuery(new Term("value", lastFieldValue)), collector);
                 assertThat(collector.getTotalHits(), equalTo(1));
             }
         }
@@ -1006,7 +1006,7 @@ public abstract class EngineTestCase extends ESTestCase {
         }
         try (Engine.Searcher searcher = engine.acquireSearcher("test_get_doc_ids")) {
             List<DocIdSeqNoAndSource> docs = new ArrayList<>();
-            for (LeafReaderContext leafContext : searcher.reader().leaves()) {
+            for (LeafReaderContext leafContext : searcher.getIndexReader().leaves()) {
                 LeafReader reader = leafContext.reader();
                 NumericDocValues seqNoDocValues = reader.getNumericDocValues(SeqNoFieldMapper.NAME);
                 NumericDocValues primaryTermDocValues = reader.getNumericDocValues(SeqNoFieldMapper.PRIMARY_TERM_NAME);

+ 1 - 2
test/framework/src/main/java/org/elasticsearch/index/shard/IndexShardTestCase.java

@@ -369,8 +369,7 @@ public abstract class IndexShardTestCase extends ESTestCase {
                     indexSettings.getSettings(), "index");
             mapperService.merge(indexMetaData, MapperService.MergeReason.MAPPING_RECOVERY);
             SimilarityService similarityService = new SimilarityService(indexSettings, null, Collections.emptyMap());
-            final Engine.Warmer warmer = searcher -> {
-            };
+            final Engine.Warmer warmer = reader -> {};
             ClusterSettings clusterSettings = new ClusterSettings(nodeSettings, ClusterSettings.BUILT_IN_CLUSTER_SETTINGS);
             CircuitBreakerService breakerService = new HierarchyCircuitBreakerService(nodeSettings, clusterSettings);
             indexShard = new IndexShard(

+ 16 - 24
test/framework/src/main/java/org/elasticsearch/test/engine/MockEngineSupport.java

@@ -24,7 +24,6 @@ import org.apache.lucene.index.AssertingDirectoryReader;
 import org.apache.lucene.index.DirectoryReader;
 import org.apache.lucene.index.FilterDirectoryReader;
 import org.apache.lucene.index.IndexReader;
-import org.apache.lucene.search.AssertingIndexSearcher;
 import org.apache.lucene.search.QueryCache;
 import org.apache.lucene.search.QueryCachingPolicy;
 import org.apache.lucene.util.LuceneTestCase;
@@ -138,19 +137,13 @@ public final class MockEngineSupport {
         }
     }
 
-    public AssertingIndexSearcher newSearcher(Engine.Searcher searcher) throws EngineException {
-        IndexReader reader = searcher.reader();
+    public IndexReader newReader(IndexReader reader) throws EngineException {
         IndexReader wrappedReader = reader;
         assert reader != null;
         if (reader instanceof DirectoryReader && mockContext.wrapReader) {
             wrappedReader = wrapReader((DirectoryReader) reader);
         }
-        // this executes basic query checks and asserts that weights are normalized only once etc.
-        final AssertingIndexSearcher assertingIndexSearcher = new AssertingIndexSearcher(mockContext.random, wrappedReader);
-        assertingIndexSearcher.setSimilarity(searcher.searcher().getSimilarity());
-        assertingIndexSearcher.setQueryCache(filterCache);
-        assertingIndexSearcher.setQueryCachingPolicy(filterCachingPolicy);
-        return assertingIndexSearcher;
+        return wrappedReader;
     }
 
     private DirectoryReader wrapReader(DirectoryReader reader) {
@@ -187,9 +180,9 @@ public final class MockEngineSupport {
 
     }
 
-    public Engine.Searcher wrapSearcher(Engine.Searcher engineSearcher) {
-        final AssertingIndexSearcher assertingIndexSearcher = newSearcher(engineSearcher);
-        assertingIndexSearcher.setSimilarity(engineSearcher.searcher().getSimilarity());
+    public Engine.Searcher wrapSearcher(Engine.Searcher searcher) {
+        final IndexReader reader = newReader(searcher.getIndexReader());
+
         /*
          * pass the original searcher to the super.newSearcher() method to
          * make sure this is the searcher that will be released later on.
@@ -198,8 +191,9 @@ public final class MockEngineSupport {
          * early. - good news, stuff will fail all over the place if we don't
          * get this right here
          */
-        SearcherCloseable closeable = new SearcherCloseable(engineSearcher, logger, inFlightSearchers);
-        return new Engine.Searcher(engineSearcher.source(), assertingIndexSearcher, closeable);
+        SearcherCloseable closeable = new SearcherCloseable(searcher, logger, inFlightSearchers);
+        return new Engine.Searcher(searcher.source(), reader, searcher.getSimilarity(),
+            searcher.getQueryCache(), searcher.getQueryCachingPolicy(), closeable);
     }
 
     private static final class InFlightSearchers implements Closeable {
@@ -230,7 +224,7 @@ public final class MockEngineSupport {
     }
 
     private static final class SearcherCloseable implements Closeable {
-        private final Engine.Searcher wrappedSearcher;
+        private final Engine.Searcher searcher;
         private final InFlightSearchers inFlightSearchers;
         private RuntimeException firstReleaseStack;
         private final Object lock = new Object();
@@ -238,16 +232,14 @@ public final class MockEngineSupport {
         private final Logger logger;
         private final AtomicBoolean closed = new AtomicBoolean(false);
 
-        SearcherCloseable(final Engine.Searcher wrappedSearcher, Logger logger, InFlightSearchers inFlightSearchers) {
-            // we only use the given index searcher here instead of the IS of the wrapped searcher. the IS might be a wrapped searcher
-            // with a wrapped reader.
-            this.wrappedSearcher = wrappedSearcher;
+        SearcherCloseable(final Engine.Searcher searcher, Logger logger, InFlightSearchers inFlightSearchers) {
+            this.searcher = searcher;
             this.logger = logger;
-            initialRefCount = wrappedSearcher.reader().getRefCount();
+            initialRefCount = searcher.getIndexReader().getRefCount();
             this.inFlightSearchers = inFlightSearchers;
             assert initialRefCount > 0 :
                 "IndexReader#getRefCount() was [" + initialRefCount + "] expected a value > [0] - reader is already closed";
-            inFlightSearchers.add(this, wrappedSearcher.source());
+            inFlightSearchers.add(this, searcher.source());
         }
 
         @Override
@@ -256,7 +248,7 @@ public final class MockEngineSupport {
                 if (closed.compareAndSet(false, true)) {
                     inFlightSearchers.remove(this);
                     firstReleaseStack = new RuntimeException();
-                    final int refCount = wrappedSearcher.reader().getRefCount();
+                    final int refCount = searcher.getIndexReader().getRefCount();
                     /*
                      * this assert seems to be paranoid but given LUCENE-5362 we
                      * better add some assertions here to make sure we catch any
@@ -265,13 +257,13 @@ public final class MockEngineSupport {
                     assert refCount > 0 : "IndexReader#getRefCount() was [" + refCount + "] expected a value > [0] - reader is already "
                         + " closed. Initial refCount was: [" + initialRefCount + "]";
                     try {
-                        wrappedSearcher.close();
+                        searcher.close();
                     } catch (RuntimeException ex) {
                         logger.debug("Failed to release searcher", ex);
                         throw ex;
                     }
                 } else {
-                    AssertionError error = new AssertionError("Released Searcher more than once, source [" + wrappedSearcher.source()
+                    AssertionError error = new AssertionError("Released Searcher more than once, source [" + searcher.source()
                         + "]");
                     error.initCause(firstReleaseStack);
                     throw error;

+ 3 - 2
test/framework/src/main/java/org/elasticsearch/test/engine/MockInternalEngine.java

@@ -19,6 +19,7 @@
 package org.elasticsearch.test.engine;
 
 import org.apache.lucene.index.FilterDirectoryReader;
+import org.elasticsearch.index.engine.Engine;
 import org.elasticsearch.index.engine.EngineConfig;
 import org.elasticsearch.index.engine.EngineException;
 import org.elasticsearch.index.engine.InternalEngine;
@@ -76,8 +77,8 @@ final class MockInternalEngine extends InternalEngine {
     }
 
     @Override
-    public Searcher acquireSearcher(String source, SearcherScope scope) {
-        final Searcher engineSearcher = super.acquireSearcher(source, scope);
+    public Engine.Searcher acquireSearcher(String source, SearcherScope scope) {
+        final Engine.Searcher engineSearcher = super.acquireSearcher(source, scope);
         return support().wrapSearcher(engineSearcher);
     }
 }

+ 13 - 11
x-pack/plugin/core/src/main/java/org/elasticsearch/index/engine/FrozenEngine.java

@@ -26,7 +26,6 @@ import org.apache.lucene.index.SortedNumericDocValues;
 import org.apache.lucene.index.SortedSetDocValues;
 import org.apache.lucene.index.StoredFieldVisitor;
 import org.apache.lucene.index.Terms;
-import org.apache.lucene.search.IndexSearcher;
 import org.apache.lucene.search.ReferenceManager;
 import org.apache.lucene.store.AlreadyClosedException;
 import org.apache.lucene.store.Directory;
@@ -70,8 +69,8 @@ public final class FrozenEngine extends ReadOnlyEngine {
     public static final Setting<Boolean> INDEX_FROZEN = Setting.boolSetting("index.frozen", false, Setting.Property.IndexScope,
         Setting.Property.PrivateIndex);
     private final SegmentsStats stats;
-    private volatile DirectoryReader lastOpenedReader;
-    private final DirectoryReader canMatchReader;
+    private volatile ElasticsearchDirectoryReader lastOpenedReader;
+    private final ElasticsearchDirectoryReader canMatchReader;
 
     public FrozenEngine(EngineConfig config) {
         super(config, null, null, true, Function.identity());
@@ -159,8 +158,8 @@ public final class FrozenEngine extends ReadOnlyEngine {
         }
     }
 
-    private synchronized DirectoryReader getOrOpenReader() throws IOException {
-        DirectoryReader reader = null;
+    private synchronized ElasticsearchDirectoryReader getOrOpenReader() throws IOException {
+        ElasticsearchDirectoryReader reader = null;
         boolean success = false;
         try {
             reader = getReader();
@@ -168,9 +167,9 @@ public final class FrozenEngine extends ReadOnlyEngine {
                 for (ReferenceManager.RefreshListener listeners : config ().getInternalRefreshListener()) {
                     listeners.beforeRefresh();
                 }
-                reader = DirectoryReader.open(engineConfig.getStore().directory(), OFF_HEAP_READER_ATTRIBUTES);
+                final DirectoryReader dirReader = DirectoryReader.open(engineConfig.getStore().directory(), OFF_HEAP_READER_ATTRIBUTES);
+                reader = lastOpenedReader = wrapReader(dirReader, Function.identity());
                 processReader(reader);
-                reader = lastOpenedReader = wrapReader(reader, Function.identity());
                 reader.getReaderCacheHelper().addClosedListener(this::onReaderClosed);
                 for (ReferenceManager.RefreshListener listeners : config ().getInternalRefreshListener()) {
                     listeners.afterRefresh(true);
@@ -186,7 +185,7 @@ public final class FrozenEngine extends ReadOnlyEngine {
     }
 
     @SuppressForbidden(reason = "we manage references explicitly here")
-    private synchronized DirectoryReader getReader() {
+    private synchronized ElasticsearchDirectoryReader getReader() {
         if (lastOpenedReader != null && lastOpenedReader.tryIncRef()) {
             return lastOpenedReader;
         }
@@ -220,20 +219,23 @@ public final class FrozenEngine extends ReadOnlyEngine {
             }
             // special case we only want to report segment stats if we have a reader open. in that case we only get a reader if we still
             // have one open at the time and can inc it's reference.
-            DirectoryReader reader = maybeOpenReader ? getOrOpenReader() : getReader();
+            ElasticsearchDirectoryReader reader = maybeOpenReader ? getOrOpenReader() : getReader();
             if (reader == null) {
                 // we just hand out a searcher on top of an empty reader that we opened for the ReadOnlyEngine in the #open(IndexCommit)
                 // method. this is the case when we don't have a reader open right now and we get a stats call any other that falls in
                 // the category that doesn't trigger a reopen
                 if ("can_match".equals(source)) {
                     canMatchReader.incRef();
-                    return new Searcher(source, new IndexSearcher(canMatchReader), canMatchReader::decRef);
+                    return new Searcher(source, canMatchReader,
+                        engineConfig.getSimilarity(), engineConfig.getQueryCache(), engineConfig.getQueryCachingPolicy(),
+                        canMatchReader::decRef);
                 }
                 return super.acquireSearcher(source, scope);
             } else {
                 try {
                     LazyDirectoryReader lazyDirectoryReader = new LazyDirectoryReader(reader, this);
-                    Searcher newSearcher = new Searcher(source, new IndexSearcher(lazyDirectoryReader),
+                    Searcher newSearcher = new Searcher(source, lazyDirectoryReader,
+                        engineConfig.getSimilarity(), engineConfig.getQueryCache(), engineConfig.getQueryCachingPolicy(),
                         () -> IOUtils.close(lazyDirectoryReader, store::decRef));
                     releaseRefeference = false;
                     return newSearcher;

+ 8 - 8
x-pack/plugin/core/src/test/java/org/elasticsearch/index/engine/FrozenEngineTests.java

@@ -52,16 +52,16 @@ public class FrozenEngineTests extends EngineTestCase {
                     assertEquals(config.getShardId(), ElasticsearchDirectoryReader.getElasticsearchDirectoryReader(searcher
                         .getDirectoryReader()).shardId());
                     assertTrue(frozenEngine.isReaderOpen());
-                    TopDocs search = searcher.searcher().search(new MatchAllDocsQuery(), numDocs);
+                    TopDocs search = searcher.search(new MatchAllDocsQuery(), numDocs);
                     assertEquals(search.scoreDocs.length, numDocs);
                     assertEquals(1, listener.afterRefresh.get());
                     FrozenEngine.unwrapLazyReader(searcher.getDirectoryReader()).release();
                     assertFalse(frozenEngine.isReaderOpen());
                     assertEquals(1, listener.afterRefresh.get());
-                    expectThrows(AlreadyClosedException.class, () -> searcher.searcher().search(new MatchAllDocsQuery(), numDocs));
+                    expectThrows(AlreadyClosedException.class, () -> searcher.search(new MatchAllDocsQuery(), numDocs));
                     FrozenEngine.unwrapLazyReader(searcher.getDirectoryReader()).reset();
                     assertEquals(2, listener.afterRefresh.get());
-                    search = searcher.searcher().search(new MatchAllDocsQuery(), numDocs);
+                    search = searcher.search(new MatchAllDocsQuery(), numDocs);
                     assertEquals(search.scoreDocs.length, numDocs);
                     searcher.close();
                 }
@@ -84,19 +84,19 @@ public class FrozenEngineTests extends EngineTestCase {
                     assertFalse(frozenEngine.isReaderOpen());
                     Engine.Searcher searcher1 = frozenEngine.acquireSearcher("test");
                     assertTrue(frozenEngine.isReaderOpen());
-                    TopDocs search = searcher1.searcher().search(new MatchAllDocsQuery(), numDocs);
+                    TopDocs search = searcher1.search(new MatchAllDocsQuery(), numDocs);
                     assertEquals(search.scoreDocs.length, numDocs);
                     assertEquals(1, listener.afterRefresh.get());
                     FrozenEngine.unwrapLazyReader(searcher1.getDirectoryReader()).release();
                     Engine.Searcher searcher2 = frozenEngine.acquireSearcher("test");
-                    search = searcher2.searcher().search(new MatchAllDocsQuery(), numDocs);
+                    search = searcher2.search(new MatchAllDocsQuery(), numDocs);
                     assertEquals(search.scoreDocs.length, numDocs);
                     assertTrue(frozenEngine.isReaderOpen());
                     assertEquals(2, listener.afterRefresh.get());
-                    expectThrows(AlreadyClosedException.class, () -> searcher1.searcher().search(new MatchAllDocsQuery(), numDocs));
+                    expectThrows(AlreadyClosedException.class, () -> searcher1.search(new MatchAllDocsQuery(), numDocs));
                     FrozenEngine.unwrapLazyReader(searcher1.getDirectoryReader()).reset();
                     assertEquals(2, listener.afterRefresh.get());
-                    search = searcher1.searcher().search(new MatchAllDocsQuery(), numDocs);
+                    search = searcher1.search(new MatchAllDocsQuery(), numDocs);
                     assertEquals(search.scoreDocs.length, numDocs);
                     searcher1.close();
                     searcher2.close();
@@ -220,7 +220,7 @@ public class FrozenEngineTests extends EngineTestCase {
                                 for (int j = 0; j < numIters; j++) {
                                     FrozenEngine.unwrapLazyReader(searcher.getDirectoryReader()).reset();
                                     assertTrue(frozenEngine.isReaderOpen());
-                                    TopDocs search = searcher.searcher().search(new MatchAllDocsQuery(), Math.min(10, numDocsAdded));
+                                    TopDocs search = searcher.search(new MatchAllDocsQuery(), Math.min(10, numDocsAdded));
                                     assertEquals(search.scoreDocs.length, Math.min(10, numDocsAdded));
                                     FrozenEngine.unwrapLazyReader(searcher.getDirectoryReader()).release();
                                 }

+ 6 - 6
x-pack/plugin/core/src/test/java/org/elasticsearch/snapshots/SourceOnlySnapshotShardTests.java

@@ -229,12 +229,12 @@ public class SourceOnlySnapshotShardTests extends IndexShardTestCase {
         assertEquals(seqNoStats.getMaxSeqNo(), seqNoStats.getLocalCheckpoint());
         final IndexShard targetShard;
         try (Engine.Searcher searcher = restoredShard.acquireSearcher("test")) {
-            assertEquals(searcher.reader().maxDoc(), seqNoStats.getLocalCheckpoint());
-            TopDocs search = searcher.searcher().search(new MatchAllDocsQuery(), Integer.MAX_VALUE);
-            assertEquals(searcher.reader().numDocs(), search.totalHits.value);
-            search = searcher.searcher().search(new MatchAllDocsQuery(), Integer.MAX_VALUE,
+            assertEquals(searcher.getIndexReader().maxDoc(), seqNoStats.getLocalCheckpoint());
+            TopDocs search = searcher.search(new MatchAllDocsQuery(), Integer.MAX_VALUE);
+            assertEquals(searcher.getIndexReader().numDocs(), search.totalHits.value);
+            search = searcher.search(new MatchAllDocsQuery(), Integer.MAX_VALUE,
                 new Sort(new SortField(SeqNoFieldMapper.NAME, SortField.Type.LONG)), false);
-            assertEquals(searcher.reader().numDocs(), search.totalHits.value);
+            assertEquals(searcher.getIndexReader().numDocs(), search.totalHits.value);
             long previous = -1;
             for (ScoreDoc doc : search.scoreDocs) {
                 FieldDoc fieldDoc = (FieldDoc) doc;
@@ -243,7 +243,7 @@ public class SourceOnlySnapshotShardTests extends IndexShardTestCase {
                 assertThat(previous, Matchers.lessThan(current));
                 previous = current;
             }
-            expectThrows(UnsupportedOperationException.class, () -> searcher.searcher().search(new TermQuery(new Term("boom", "boom")), 1));
+            expectThrows(UnsupportedOperationException.class, () -> searcher.search(new TermQuery(new Term("boom", "boom")), 1));
             targetShard = reindex(searcher.getDirectoryReader(), new MappingMetaData("_doc",
                 restoredShard.mapperService().documentMapper("_doc").meta()));
         }