| 
70 | 70 | import org.elasticsearch.core.IOUtils;  | 
71 | 71 | import org.elasticsearch.core.Nullable;  | 
72 | 72 | import org.elasticsearch.core.Releasable;  | 
 | 73 | +import org.elasticsearch.core.Releasables;  | 
73 | 74 | import org.elasticsearch.core.SuppressForbidden;  | 
74 | 75 | import org.elasticsearch.core.Tuple;  | 
75 | 76 | import org.elasticsearch.env.Environment;  | 
 | 
106 | 107 | 
 
  | 
107 | 108 | import java.io.Closeable;  | 
108 | 109 | import java.io.IOException;  | 
 | 110 | +import java.io.UncheckedIOException;  | 
109 | 111 | import java.util.Arrays;  | 
110 | 112 | import java.util.Collections;  | 
111 | 113 | import java.util.List;  | 
@@ -1020,18 +1022,15 @@ private VersionValue resolveDocVersion(final Operation op, boolean loadSeqNo) th  | 
1020 | 1022 |         VersionValue versionValue = getVersionFromMap(op.uid());  | 
1021 | 1023 |         if (versionValue == null) {  | 
1022 | 1024 |             assert incrementIndexVersionLookup(); // used for asserting in tests  | 
1023 |  | -            var referenceManager = getReferenceManager(SearcherScope.INTERNAL);  | 
1024 | 1025 |             final VersionsAndSeqNoResolver.DocIdAndVersion docIdAndVersion;  | 
1025 |  | -            var indexReader = referenceManager.acquire();  | 
1026 |  | -            try {  | 
 | 1026 | +            try (var directoryReaderSupplier = acquireDirectoryReaderSupplier(SearcherScope.INTERNAL)) {  | 
 | 1027 | +                var indexReader = directoryReaderSupplier.getDirectoryReader();  | 
1027 | 1028 |                 if (engineConfig.getIndexSettings().getMode() == IndexMode.TIME_SERIES) {  | 
1028 | 1029 |                     assert engineConfig.getLeafSorter() == DataStream.TIMESERIES_LEAF_READERS_SORTER;  | 
1029 | 1030 |                     docIdAndVersion = VersionsAndSeqNoResolver.timeSeriesLoadDocIdAndVersion(indexReader, op.uid(), op.id(), loadSeqNo);  | 
1030 | 1031 |                 } else {  | 
1031 | 1032 |                     docIdAndVersion = VersionsAndSeqNoResolver.timeSeriesLoadDocIdAndVersion(indexReader, op.uid(), loadSeqNo);  | 
1032 | 1033 |                 }  | 
1033 |  | -            } finally {  | 
1034 |  | -                referenceManager.release(indexReader);  | 
1035 | 1034 |             }  | 
1036 | 1035 |             if (docIdAndVersion != null) {  | 
1037 | 1036 |                 versionValue = new IndexVersionValue(null, docIdAndVersion.version, docIdAndVersion.seqNo, docIdAndVersion.primaryTerm);  | 
@@ -3465,4 +3464,70 @@ public LiveVersionMap getLiveVersionMap() {  | 
3465 | 3464 |     protected long getPreCommitSegmentGeneration() {  | 
3466 | 3465 |         return preCommitSegmentGeneration.get();  | 
3467 | 3466 |     }  | 
 | 3467 | + | 
 | 3468 | +    DirectoryReaderSupplier acquireDirectoryReaderSupplier(SearcherScope scope) throws EngineException {  | 
 | 3469 | +        assert scope == SearcherScope.INTERNAL : "acquireDirectoryReaderSupplier(...) isn't prepared for external usage";  | 
 | 3470 | + | 
 | 3471 | +        /* Acquire order here is store -> manager since we need  | 
 | 3472 | +         * to make sure that the store is not closed before  | 
 | 3473 | +         * the searcher is acquired. */  | 
 | 3474 | +        if (store.tryIncRef() == false) {  | 
 | 3475 | +            throw new AlreadyClosedException(shardId + " store is closed", failedEngine.get());  | 
 | 3476 | +        }  | 
 | 3477 | +        Releasable releasable = store::decRef;  | 
 | 3478 | +        try {  | 
 | 3479 | +            ReferenceManager<ElasticsearchDirectoryReader> referenceManager = getReferenceManager(scope);  | 
 | 3480 | +            ElasticsearchDirectoryReader acquire = referenceManager.acquire();  | 
 | 3481 | +            releasable = null; // success - hand over the reference to the engine reader  | 
 | 3482 | +            return new DirectoryReaderSupplier(acquire) {  | 
 | 3483 | + | 
 | 3484 | +                @Override  | 
 | 3485 | +                void doClose() {  | 
 | 3486 | +                    try {  | 
 | 3487 | +                        referenceManager.release(acquire);  | 
 | 3488 | +                    } catch (IOException e) {  | 
 | 3489 | +                        throw new UncheckedIOException("failed to close", e);  | 
 | 3490 | +                    } catch (AlreadyClosedException e) {  | 
 | 3491 | +                        // This means there's a bug somewhere: don't suppress it  | 
 | 3492 | +                        throw new AssertionError(e);  | 
 | 3493 | +                    } finally {  | 
 | 3494 | +                        store.decRef();  | 
 | 3495 | +                    }  | 
 | 3496 | +                }  | 
 | 3497 | +            };  | 
 | 3498 | +        } catch (AlreadyClosedException ex) {  | 
 | 3499 | +            throw ex;  | 
 | 3500 | +        } catch (Exception ex) {  | 
 | 3501 | +            maybeFailEngine("acquire_reader", ex);  | 
 | 3502 | +            ensureOpen(ex); // throw EngineCloseException here if we are already closed  | 
 | 3503 | +            logger.error("failed to acquire reader", ex);  | 
 | 3504 | +            throw new EngineException(shardId, "failed to acquire reader", ex);  | 
 | 3505 | +        } finally {  | 
 | 3506 | +            Releasables.close(releasable);  | 
 | 3507 | +        }  | 
 | 3508 | +    }  | 
 | 3509 | + | 
 | 3510 | +    abstract static class DirectoryReaderSupplier implements Releasable {  | 
 | 3511 | +        private final DirectoryReader directoryReader;  | 
 | 3512 | +        private final AtomicBoolean released = new AtomicBoolean(false);  | 
 | 3513 | + | 
 | 3514 | +        DirectoryReaderSupplier(DirectoryReader directoryReader) {  | 
 | 3515 | +            this.directoryReader = directoryReader;  | 
 | 3516 | +        }  | 
 | 3517 | + | 
 | 3518 | +        public DirectoryReader getDirectoryReader() {  | 
 | 3519 | +            return directoryReader;  | 
 | 3520 | +        }  | 
 | 3521 | + | 
 | 3522 | +        @Override  | 
 | 3523 | +        public final void close() {  | 
 | 3524 | +            if (released.compareAndSet(false, true)) {  | 
 | 3525 | +                doClose();  | 
 | 3526 | +            } else {  | 
 | 3527 | +                assert false : "DirectoryReaderSupplier was released twice";  | 
 | 3528 | +            }  | 
 | 3529 | +        }  | 
 | 3530 | + | 
 | 3531 | +        abstract void doClose();  | 
 | 3532 | +    }  | 
3468 | 3533 | }  | 
0 commit comments