Search in sources :

Example 66 with AlreadyClosedException

use of org.apache.lucene.store.AlreadyClosedException in project crate by crate.

the class InternalEngine method index.

@Override
public IndexResult index(Index index) throws IOException {
    assert Objects.equals(index.uid().field(), IdFieldMapper.NAME) : index.uid().field();
    final boolean doThrottle = index.origin().isRecovery() == false;
    try (ReleasableLock releasableLock = readLock.acquire()) {
        ensureOpen();
        assert assertIncomingSequenceNumber(index.origin(), index.seqNo());
        try (Releasable ignored = versionMap.acquireLock(index.uid().bytes());
            Releasable indexThrottle = doThrottle ? () -> {
            } : throttle.acquireThrottle()) {
            lastWriteNanos = index.startTime();
            /* A NOTE ABOUT APPEND ONLY OPTIMIZATIONS:
                 * if we have an autoGeneratedID that comes into the engine we can potentially optimize
                 * and just use addDocument instead of updateDocument and skip the entire version and index lookupVersion across the board.
                 * Yet, we have to deal with multiple document delivery, for this we use a property of the document that is added
                 * to detect if it has potentially been added before. We use the documents timestamp for this since it's something
                 * that:
                 *  - doesn't change per document
                 *  - is preserved in the transaction log
                 *  - and is assigned before we start to index / replicate
                 * NOTE: it's not important for this timestamp to be consistent across nodes etc. it's just a number that is in the common
                 * case increasing and can be used in the failure case when we retry and resent documents to establish a happens before
                 * relationship. For instance:
                 *  - doc A has autoGeneratedIdTimestamp = 10, isRetry = false
                 *  - doc B has autoGeneratedIdTimestamp = 9, isRetry = false
                 *
                 *  while both docs are in in flight, we disconnect on one node, reconnect and send doc A again
                 *  - now doc A' has autoGeneratedIdTimestamp = 10, isRetry = true
                 *
                 *  if A' arrives on the shard first we update maxUnsafeAutoIdTimestamp to 10 and use update document. All subsequent
                 *  documents that arrive (A and B) will also use updateDocument since their timestamps are less than
                 *  maxUnsafeAutoIdTimestamp. While this is not strictly needed for doc B it is just much simpler to implement since it
                 *  will just de-optimize some doc in the worst case.
                 *
                 *  if A arrives on the shard first we use addDocument since maxUnsafeAutoIdTimestamp is < 10. A` will then just be skipped
                 *  or calls updateDocument.
                 */
            final IndexingStrategy plan = indexingStrategyForOperation(index);
            final IndexResult indexResult;
            if (plan.earlyResultOnPreFlightError.isPresent()) {
                indexResult = plan.earlyResultOnPreFlightError.get();
                assert indexResult.getResultType() == Result.Type.FAILURE : indexResult.getResultType();
            } else {
                // generate or register sequence number
                if (index.origin() == Operation.Origin.PRIMARY) {
                    index = new Index(index.uid(), index.parsedDoc(), generateSeqNoForOperationOnPrimary(index), index.primaryTerm(), index.version(), index.versionType(), index.origin(), index.startTime(), index.getAutoGeneratedIdTimestamp(), index.isRetry(), index.getIfSeqNo(), index.getIfPrimaryTerm());
                    final boolean toAppend = plan.indexIntoLucene && plan.useLuceneUpdateDocument == false;
                    if (toAppend == false) {
                        advanceMaxSeqNoOfUpdatesOrDeletesOnPrimary(index.seqNo());
                    }
                } else {
                    markSeqNoAsSeen(index.seqNo());
                }
                assert index.seqNo() >= 0 : "ops should have an assigned seq no.; origin: " + index.origin();
                if (plan.indexIntoLucene || plan.addStaleOpToLucene) {
                    indexResult = indexIntoLucene(index, plan);
                } else {
                    indexResult = new IndexResult(plan.versionForIndexing, index.primaryTerm(), index.seqNo(), plan.currentNotFoundOrDeleted);
                }
            }
            if (index.origin().isFromTranslog() == false) {
                final Translog.Location location;
                if (indexResult.getResultType() == Result.Type.SUCCESS) {
                    location = translog.add(new Translog.Index(index, indexResult));
                } else if (indexResult.getSeqNo() != SequenceNumbers.UNASSIGNED_SEQ_NO) {
                    // if we have document failure, record it as a no-op in the translog and Lucene with the generated seq_no
                    final NoOp noOp = new NoOp(indexResult.getSeqNo(), index.primaryTerm(), index.origin(), index.startTime(), indexResult.getFailure().toString());
                    location = innerNoOp(noOp).getTranslogLocation();
                } else {
                    location = null;
                }
                indexResult.setTranslogLocation(location);
            }
            if (plan.indexIntoLucene && indexResult.getResultType() == Result.Type.SUCCESS) {
                final Translog.Location translogLocation = trackTranslogLocation.get() ? indexResult.getTranslogLocation() : null;
                versionMap.maybePutIndexUnderLock(index.uid().bytes(), new IndexVersionValue(translogLocation, plan.versionForIndexing, index.seqNo(), index.primaryTerm()));
            }
            localCheckpointTracker.markSeqNoAsProcessed(indexResult.getSeqNo());
            if (indexResult.getTranslogLocation() == null) {
                // the op is coming from the translog (and is hence persisted already) or it does not have a sequence number
                assert index.origin().isFromTranslog() || indexResult.getSeqNo() == SequenceNumbers.UNASSIGNED_SEQ_NO : "version conflict: index operation not coming from translog should not have seqNo, but found [" + indexResult.getSeqNo() + "]";
                localCheckpointTracker.markSeqNoAsPersisted(indexResult.getSeqNo());
            }
            indexResult.setTook(System.nanoTime() - index.startTime());
            indexResult.freeze();
            return indexResult;
        }
    } catch (RuntimeException | IOException e) {
        try {
            if (e instanceof AlreadyClosedException == false && treatDocumentFailureAsTragicError(index)) {
                failEngine("index id[" + index.id() + "] origin[" + index.origin() + "] seq#[" + index.seqNo() + "]", e);
            } else {
                maybeFailEngine("index id[" + index.id() + "] origin[" + index.origin() + "] seq#[" + index.seqNo() + "]", e);
            }
        } catch (Exception inner) {
            e.addSuppressed(inner);
        }
        throw e;
    }
}
Also used : IOException(java.io.IOException) AlreadyClosedException(org.apache.lucene.store.AlreadyClosedException) ReleasableLock(org.elasticsearch.common.util.concurrent.ReleasableLock) AlreadyClosedException(org.apache.lucene.store.AlreadyClosedException) LockObtainFailedException(org.apache.lucene.store.LockObtainFailedException) TranslogCorruptedException(org.elasticsearch.index.translog.TranslogCorruptedException) IOException(java.io.IOException) Translog(org.elasticsearch.index.translog.Translog) Releasable(org.elasticsearch.common.lease.Releasable)

Example 67 with AlreadyClosedException

use of org.apache.lucene.store.AlreadyClosedException in project crate by crate.

the class InternalEngine method failOnTragicEvent.

private boolean failOnTragicEvent(AlreadyClosedException ex) {
    final boolean engineFailed;
    // but we are double-checking it's failed and closed
    if (indexWriter.isOpen() == false && indexWriter.getTragicException() != null) {
        final Exception tragicException;
        if (indexWriter.getTragicException() instanceof Exception) {
            tragicException = (Exception) indexWriter.getTragicException();
        } else {
            tragicException = new RuntimeException(indexWriter.getTragicException());
        }
        failEngine("already closed by tragic event on the index writer", tragicException);
        engineFailed = true;
    } else if (translog.isOpen() == false && translog.getTragicException() != null) {
        failEngine("already closed by tragic event on the translog", translog.getTragicException());
        engineFailed = true;
    } else if (failedEngine.get() == null && isClosed.get() == false) {
        // a tragic event or has closed itself. if that is not the case we are in a buggy state and raise an assertion error
        throw new AssertionError("Unexpected AlreadyClosedException", ex);
    } else {
        engineFailed = false;
    }
    return engineFailed;
}
Also used : AlreadyClosedException(org.apache.lucene.store.AlreadyClosedException) LockObtainFailedException(org.apache.lucene.store.LockObtainFailedException) TranslogCorruptedException(org.elasticsearch.index.translog.TranslogCorruptedException) IOException(java.io.IOException)

Example 68 with AlreadyClosedException

use of org.apache.lucene.store.AlreadyClosedException in project crate by crate.

the class Engine method failEngine.

/**
 * fail engine due to some error. the engine will also be closed.
 * The underlying store is marked corrupted iff failure is caused by index corruption
 */
public void failEngine(String reason, @Nullable Exception failure) {
    if (failure != null) {
        maybeDie(reason, failure);
    }
    if (failEngineLock.tryLock()) {
        try {
            if (failedEngine.get() != null) {
                logger.warn(() -> new ParameterizedMessage("tried to fail engine but engine is already failed. ignoring. [{}]", reason), failure);
                return;
            }
            // this must happen before we close IW or Translog such that we can check this state to opt out of failing the engine
            // again on any caught AlreadyClosedException
            failedEngine.set((failure != null) ? failure : new IllegalStateException(reason));
            try {
                // we just go and close this engine - no way to recover
                closeNoLock("engine failed on: [" + reason + "]", closedLatch);
            } finally {
                logger.warn(() -> new ParameterizedMessage("failed engine [{}]", reason), failure);
                // the shard is initializing
                if (Lucene.isCorruptionException(failure)) {
                    if (store.tryIncRef()) {
                        try {
                            store.markStoreCorrupted(new IOException("failed engine (reason: [" + reason + "])", ExceptionsHelper.unwrapCorruption(failure)));
                        } catch (IOException e) {
                            logger.warn("Couldn't mark store corrupted", e);
                        } finally {
                            store.decRef();
                        }
                    } else {
                        logger.warn(() -> new ParameterizedMessage("tried to mark store as corrupted but store is already closed. [{}]", reason), failure);
                    }
                }
                eventListener.onFailedEngine(reason, failure);
            }
        } catch (Exception inner) {
            if (failure != null)
                inner.addSuppressed(failure);
            // don't bubble up these exceptions up
            logger.warn("failEngine threw exception", inner);
        }
    } else {
        logger.debug(() -> new ParameterizedMessage("tried to fail engine but could not acquire lock - engine should be failed by now [{}]", reason), failure);
    }
}
Also used : ParameterizedMessage(org.apache.logging.log4j.message.ParameterizedMessage) UncheckedIOException(java.io.UncheckedIOException) IOException(java.io.IOException) AlreadyClosedException(org.apache.lucene.store.AlreadyClosedException) UncheckedIOException(java.io.UncheckedIOException) IOException(java.io.IOException)

Example 69 with AlreadyClosedException

use of org.apache.lucene.store.AlreadyClosedException in project crate by crate.

the class Engine method acquireSearcher.

/**
 * Returns a new searcher instance. The consumer of this
 * API is responsible for releasing the returned searcher in a
 * safe manner, preferably in a try/finally block.
 *
 * @param source the source API or routing that triggers this searcher acquire
 * @param scope the scope of this searcher ie. if the searcher will be used for get or search purposes
 *
 * @see Searcher#close()
 */
public Searcher acquireSearcher(String source, SearcherScope scope) throws EngineException {
    /* Acquire order here is store -> manager since we need
         * to make sure that the store is not closed before
         * the searcher is acquired. */
    if (store.tryIncRef() == false) {
        throw new AlreadyClosedException(shardId + " store is closed", failedEngine.get());
    }
    Releasable releasable = store::decRef;
    try {
        ReferenceManager<ElasticsearchDirectoryReader> referenceManager = getReferenceManager(scope);
        final ElasticsearchDirectoryReader acquire = referenceManager.acquire();
        AtomicBoolean released = new AtomicBoolean(false);
        Searcher engineSearcher = new Searcher(source, acquire, engineConfig.getQueryCache(), engineConfig.getQueryCachingPolicy(), () -> {
            if (released.compareAndSet(false, true)) {
                try {
                    referenceManager.release(acquire);
                } finally {
                    store.decRef();
                }
            } else {
                /*
                            * 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"));
            }
        });
        // success - hand over the reference to the engine reader
        releasable = null;
        return engineSearcher;
    } catch (AlreadyClosedException ex) {
        throw ex;
    } catch (Exception ex) {
        maybeFailEngine("acquire_searcher", ex);
        // throw EngineCloseException here if we are already closed
        ensureOpen(ex);
        logger.error(() -> new ParameterizedMessage("failed to acquire searcher, source {}", source), ex);
        throw new EngineException(shardId, "failed to acquire searcher, source " + source, ex);
    } finally {
        Releasables.close(releasable);
    }
}
Also used : AtomicBoolean(java.util.concurrent.atomic.AtomicBoolean) ElasticsearchDirectoryReader(org.elasticsearch.common.lucene.index.ElasticsearchDirectoryReader) IndexSearcher(org.apache.lucene.search.IndexSearcher) Releasable(org.elasticsearch.common.lease.Releasable) ParameterizedMessage(org.apache.logging.log4j.message.ParameterizedMessage) AlreadyClosedException(org.apache.lucene.store.AlreadyClosedException) AlreadyClosedException(org.apache.lucene.store.AlreadyClosedException) UncheckedIOException(java.io.UncheckedIOException) IOException(java.io.IOException)

Example 70 with AlreadyClosedException

use of org.apache.lucene.store.AlreadyClosedException in project crate by crate.

the class InternalEngine method forceMerge.

@Override
public void forceMerge(final boolean flush, int maxNumSegments, boolean onlyExpungeDeletes, final boolean upgrade, final boolean upgradeOnlyAncientSegments, String forceMergeUUID) throws EngineException, IOException {
    /*
         * We do NOT acquire the readlock here since we are waiting on the merges to finish
         * that's fine since the IW.rollback should stop all the threads and trigger an IOException
         * causing us to fail the forceMerge
         *
         * The way we implement upgrades is a bit hackish in the sense that we set an instance
         * variable and that this setting will thus apply to the next forced merge that will be run.
         * This is ok because (1) this is the only place we call forceMerge, (2) we have a single
         * thread for optimize, and the 'optimizeLock' guarding this code, and (3) ConcurrentMergeScheduler
         * syncs calls to findForcedMerges.
         */
    assert indexWriter.getConfig().getMergePolicy() instanceof ElasticsearchMergePolicy : "MergePolicy is " + indexWriter.getConfig().getMergePolicy().getClass().getName();
    ElasticsearchMergePolicy mp = (ElasticsearchMergePolicy) indexWriter.getConfig().getMergePolicy();
    optimizeLock.lock();
    try {
        ensureOpen();
        if (upgrade) {
            logger.info("starting segment upgrade upgradeOnlyAncientSegments={}", upgradeOnlyAncientSegments);
            mp.setUpgradeInProgress(true, upgradeOnlyAncientSegments);
        }
        // increment the ref just to ensure nobody closes the store while we optimize
        store.incRef();
        try {
            if (onlyExpungeDeletes) {
                assert upgrade == false;
                indexWriter.forceMergeDeletes(true);
            } else if (maxNumSegments <= 0) {
                assert upgrade == false;
                indexWriter.maybeMerge();
            } else {
                indexWriter.forceMerge(maxNumSegments, true);
                this.forceMergeUUID = forceMergeUUID;
            }
            if (flush) {
                if (tryRenewSyncCommit() == false) {
                    flush(false, true);
                }
            }
            if (upgrade) {
                logger.info("finished segment upgrade");
            }
        } finally {
            store.decRef();
        }
    } catch (AlreadyClosedException ex) {
        /* in this case we first check if the engine is still open. If so this exception is just fine
             * and expected. We don't hold any locks while we block on forceMerge otherwise it would block
             * closing the engine as well. If we are not closed we pass it on to failOnTragicEvent which ensures
             * we are handling a tragic even exception here */
        ensureOpen(ex);
        failOnTragicEvent(ex);
        throw ex;
    } catch (Exception e) {
        try {
            maybeFailEngine("force merge", e);
        } catch (Exception inner) {
            e.addSuppressed(inner);
        }
        throw e;
    } finally {
        try {
            // reset it just to make sure we reset it in a case of an error
            mp.setUpgradeInProgress(false, false);
        } finally {
            optimizeLock.unlock();
        }
    }
}
Also used : AlreadyClosedException(org.apache.lucene.store.AlreadyClosedException) AlreadyClosedException(org.apache.lucene.store.AlreadyClosedException) LockObtainFailedException(org.apache.lucene.store.LockObtainFailedException) TranslogCorruptedException(org.elasticsearch.index.translog.TranslogCorruptedException) IOException(java.io.IOException) ElasticsearchMergePolicy(org.elasticsearch.index.shard.ElasticsearchMergePolicy)

Aggregations

AlreadyClosedException (org.apache.lucene.store.AlreadyClosedException)79 IOException (java.io.IOException)53 LockObtainFailedException (org.apache.lucene.store.LockObtainFailedException)16 CountDownLatch (java.util.concurrent.CountDownLatch)15 MockDirectoryWrapper (org.apache.lucene.store.MockDirectoryWrapper)14 TranslogCorruptedException (org.elasticsearch.index.translog.TranslogCorruptedException)13 MockAnalyzer (org.apache.lucene.analysis.MockAnalyzer)12 AtomicBoolean (java.util.concurrent.atomic.AtomicBoolean)11 Document (org.apache.lucene.document.Document)11 ElasticsearchException (org.elasticsearch.ElasticsearchException)11 ReleasableLock (org.elasticsearch.common.util.concurrent.ReleasableLock)10 UncheckedIOException (java.io.UncheckedIOException)9 ParsedDocument (org.elasticsearch.index.mapper.ParsedDocument)9 EOFException (java.io.EOFException)8 ArrayList (java.util.ArrayList)7 FileNotFoundException (java.io.FileNotFoundException)6 FileAlreadyExistsException (java.nio.file.FileAlreadyExistsException)6 NoSuchFileException (java.nio.file.NoSuchFileException)6 BrokenBarrierException (java.util.concurrent.BrokenBarrierException)6 CopyOnWriteArrayList (java.util.concurrent.CopyOnWriteArrayList)6