|
31 | 31 | import org.apache.lucene.util.Bits;
|
32 | 32 | import org.elasticsearch.common.SuppressForbidden;
|
33 | 33 | import org.elasticsearch.common.lucene.Lucene;
|
| 34 | +import org.elasticsearch.common.settings.Setting; |
34 | 35 | import org.elasticsearch.core.internal.io.IOUtils;
|
| 36 | +import org.elasticsearch.index.shard.SearchOperationListener; |
| 37 | +import org.elasticsearch.search.internal.SearchContext; |
| 38 | +import org.elasticsearch.transport.TransportRequest; |
35 | 39 |
|
36 | 40 | import java.io.IOException;
|
37 | 41 | import java.io.UncheckedIOException;
|
|
59 | 63 | * stats in order to obtain the number of reopens.
|
60 | 64 | */
|
61 | 65 | public final class FrozenEngine extends ReadOnlyEngine {
|
| 66 | + public static final Setting<Boolean> INDEX_FROZEN = Setting.boolSetting("index.frozen", false, Setting.Property.IndexScope, |
| 67 | + Setting.Property.PrivateIndex); |
62 | 68 | private volatile DirectoryReader lastOpenedReader;
|
63 | 69 |
|
64 | 70 | public FrozenEngine(EngineConfig config) {
|
@@ -232,6 +238,49 @@ static LazyDirectoryReader unwrapLazyReader(DirectoryReader reader) {
|
232 | 238 | return null;
|
233 | 239 | }
|
234 | 240 |
|
| 241 | + /* |
| 242 | + * We register this listener for a frozen index that will |
| 243 | + * 1. reset the reader every time the search context is validated which happens when the context is looked up ie. on a fetch phase |
| 244 | + * etc. |
| 245 | + * 2. register a releasable resource that is cleaned after each phase that releases the reader for this searcher |
| 246 | + */ |
| 247 | + public static class ReacquireEngineSearcherListener implements SearchOperationListener { |
| 248 | + |
| 249 | + @Override |
| 250 | + public void validateSearchContext(SearchContext context, TransportRequest transportRequest) { |
| 251 | + Searcher engineSearcher = context.searcher().getEngineSearcher(); |
| 252 | + LazyDirectoryReader lazyDirectoryReader = unwrapLazyReader(engineSearcher.getDirectoryReader()); |
| 253 | + if (lazyDirectoryReader != null) { |
| 254 | + try { |
| 255 | + lazyDirectoryReader.reset(); |
| 256 | + } catch (IOException e) { |
| 257 | + throw new UncheckedIOException(e); |
| 258 | + } |
| 259 | + // also register a release resource in this case if we have multiple roundtrips like in DFS |
| 260 | + registerRelease(context, lazyDirectoryReader); |
| 261 | + } |
| 262 | + } |
| 263 | + |
| 264 | + private void registerRelease(SearchContext context, LazyDirectoryReader lazyDirectoryReader) { |
| 265 | + context.addReleasable(() -> { |
| 266 | + try { |
| 267 | + lazyDirectoryReader.release(); |
| 268 | + } catch (IOException e) { |
| 269 | + throw new UncheckedIOException(e); |
| 270 | + } |
| 271 | + }, SearchContext.Lifetime.PHASE); |
| 272 | + } |
| 273 | + |
| 274 | + @Override |
| 275 | + public void onNewContext(SearchContext context) { |
| 276 | + Searcher engineSearcher = context.searcher().getEngineSearcher(); |
| 277 | + LazyDirectoryReader lazyDirectoryReader = unwrapLazyReader(engineSearcher.getDirectoryReader()); |
| 278 | + if (lazyDirectoryReader != null) { |
| 279 | + registerRelease(context, lazyDirectoryReader); |
| 280 | + } |
| 281 | + } |
| 282 | + } |
| 283 | + |
235 | 284 | /**
|
236 | 285 | * This class allows us to use the same high level reader across multiple search phases but replace the underpinnings
|
237 | 286 | * on/after each search phase. This is really important otherwise we would hold on to multiple readers across phases.
|
|
0 commit comments