Search in sources :

Example 46 with StoreFileMetadata

use of org.elasticsearch.index.store.StoreFileMetadata in project crate by crate.

the class RecoverySourceHandler method phase1.

/**
 * Perform phase1 of the recovery operations. Once this {@link IndexCommit}
 * snapshot has been performed no commit operations (files being fsync'd)
 * are effectively allowed on this index until all recovery phases are done
 * <p>
 * Phase1 examines the segment files on the target node and copies over the
 * segments that are missing. Only segments that have the same size and
 * checksum can be reused
 */
void phase1(IndexCommit snapshot, long startingSeqNo, IntSupplier translogOps, ActionListener<SendFileResult> listener) {
    cancellableThreads.checkForCancel();
    final Store store = shard.store();
    try {
        final StopWatch stopWatch = new StopWatch().start();
        final Store.MetadataSnapshot recoverySourceMetadata;
        try {
            recoverySourceMetadata = store.getMetadata(snapshot);
        } catch (CorruptIndexException | IndexFormatTooOldException | IndexFormatTooNewException ex) {
            shard.failShard("recovery", ex);
            throw ex;
        }
        for (String name : snapshot.getFileNames()) {
            final StoreFileMetadata md = recoverySourceMetadata.get(name);
            if (md == null) {
                logger.info("Snapshot differs from actual index for file: {} meta: {}", name, recoverySourceMetadata.asMap());
                throw new CorruptIndexException("Snapshot differs from actual index - maybe index was removed metadata has " + recoverySourceMetadata.asMap().size() + " files", name);
            }
        }
        if (canSkipPhase1(recoverySourceMetadata, request.metadataSnapshot()) == false) {
            final List<String> phase1FileNames = new ArrayList<>();
            final List<Long> phase1FileSizes = new ArrayList<>();
            final List<String> phase1ExistingFileNames = new ArrayList<>();
            final List<Long> phase1ExistingFileSizes = new ArrayList<>();
            // Total size of segment files that are recovered
            long totalSizeInBytes = 0;
            // Total size of segment files that were able to be re-used
            long existingTotalSizeInBytes = 0;
            // Generate a "diff" of all the identical, different, and missing
            // segment files on the target node, using the existing files on
            // the source node
            final Store.RecoveryDiff diff = recoverySourceMetadata.recoveryDiff(request.metadataSnapshot());
            for (StoreFileMetadata md : diff.identical) {
                phase1ExistingFileNames.add(md.name());
                phase1ExistingFileSizes.add(md.length());
                existingTotalSizeInBytes += md.length();
                if (logger.isTraceEnabled()) {
                    logger.trace("recovery [phase1]: not recovering [{}], exist in local store and has checksum [{}]," + " size [{}]", md.name(), md.checksum(), md.length());
                }
                totalSizeInBytes += md.length();
            }
            List<StoreFileMetadata> phase1Files = new ArrayList<>(diff.different.size() + diff.missing.size());
            phase1Files.addAll(diff.different);
            phase1Files.addAll(diff.missing);
            for (StoreFileMetadata md : phase1Files) {
                if (request.metadataSnapshot().asMap().containsKey(md.name())) {
                    logger.trace("recovery [phase1]: recovering [{}], exists in local store, but is different: remote [{}], local [{}]", md.name(), request.metadataSnapshot().asMap().get(md.name()), md);
                } else {
                    logger.trace("recovery [phase1]: recovering [{}], does not exist in remote", md.name());
                }
                phase1FileNames.add(md.name());
                phase1FileSizes.add(md.length());
                totalSizeInBytes += md.length();
            }
            logger.trace("recovery [phase1]: recovering_files [{}] with total_size [{}], reusing_files [{}] with total_size [{}]", phase1FileNames.size(), new ByteSizeValue(totalSizeInBytes), phase1ExistingFileNames.size(), new ByteSizeValue(existingTotalSizeInBytes));
            final StepListener<Void> sendFileInfoStep = new StepListener<>();
            final StepListener<Void> sendFilesStep = new StepListener<>();
            final StepListener<RetentionLease> createRetentionLeaseStep = new StepListener<>();
            final StepListener<Void> cleanFilesStep = new StepListener<>();
            cancellableThreads.checkForCancel();
            recoveryTarget.receiveFileInfo(phase1FileNames, phase1FileSizes, phase1ExistingFileNames, phase1ExistingFileSizes, translogOps.getAsInt(), sendFileInfoStep);
            sendFileInfoStep.whenComplete(r -> sendFiles(store, phase1Files.toArray(new StoreFileMetadata[0]), translogOps, sendFilesStep), listener::onFailure);
            sendFilesStep.whenComplete(r -> createRetentionLease(startingSeqNo, createRetentionLeaseStep), listener::onFailure);
            createRetentionLeaseStep.whenComplete(retentionLease -> {
                final long lastKnownGlobalCheckpoint = shard.getLastKnownGlobalCheckpoint();
                assert retentionLease == null || retentionLease.retainingSequenceNumber() - 1 <= lastKnownGlobalCheckpoint : retentionLease + " vs " + lastKnownGlobalCheckpoint;
                // Establishes new empty translog on the replica with global checkpoint set to lastKnownGlobalCheckpoint. We want
                // the commit we just copied to be a safe commit on the replica, so why not set the global checkpoint on the replica
                // to the max seqno of this commit? Because (in rare corner cases) this commit might not be a safe commit here on
                // the primary, and in these cases the max seqno would be too high to be valid as a global checkpoint.
                cleanFiles(store, recoverySourceMetadata, translogOps, lastKnownGlobalCheckpoint, cleanFilesStep);
            }, listener::onFailure);
            final long totalSize = totalSizeInBytes;
            final long existingTotalSize = existingTotalSizeInBytes;
            cleanFilesStep.whenComplete(r -> {
                final TimeValue took = stopWatch.totalTime();
                logger.trace("recovery [phase1]: took [{}]", took);
                listener.onResponse(new SendFileResult(phase1FileNames, phase1FileSizes, totalSize, phase1ExistingFileNames, phase1ExistingFileSizes, existingTotalSize, took));
            }, listener::onFailure);
        } else {
            logger.trace("skipping [phase1] since source and target have identical sync id [{}]", recoverySourceMetadata.getSyncId());
            // but we must still create a retention lease
            final StepListener<RetentionLease> createRetentionLeaseStep = new StepListener<>();
            createRetentionLease(startingSeqNo, createRetentionLeaseStep);
            createRetentionLeaseStep.whenComplete(retentionLease -> {
                final TimeValue took = stopWatch.totalTime();
                logger.trace("recovery [phase1]: took [{}]", took);
                listener.onResponse(new SendFileResult(Collections.emptyList(), Collections.emptyList(), 0L, Collections.emptyList(), Collections.emptyList(), 0L, took));
            }, listener::onFailure);
        }
    } catch (Exception e) {
        throw new RecoverFilesRecoveryException(request.shardId(), 0, new ByteSizeValue(0L), e);
    }
}
Also used : CopyOnWriteArrayList(java.util.concurrent.CopyOnWriteArrayList) ArrayList(java.util.ArrayList) ByteSizeValue(org.elasticsearch.common.unit.ByteSizeValue) Store(org.elasticsearch.index.store.Store) StoreFileMetadata(org.elasticsearch.index.store.StoreFileMetadata) IndexFormatTooOldException(org.apache.lucene.index.IndexFormatTooOldException) TimeValue(io.crate.common.unit.TimeValue) CorruptIndexException(org.apache.lucene.index.CorruptIndexException) IndexFormatTooNewException(org.apache.lucene.index.IndexFormatTooNewException) RecoveryEngineException(org.elasticsearch.index.engine.RecoveryEngineException) RetentionLeaseNotFoundException(org.elasticsearch.index.seqno.RetentionLeaseNotFoundException) CorruptIndexException(org.apache.lucene.index.CorruptIndexException) RemoteTransportException(org.elasticsearch.transport.RemoteTransportException) IndexShardClosedException(org.elasticsearch.index.shard.IndexShardClosedException) IndexShardRelocatedException(org.elasticsearch.index.shard.IndexShardRelocatedException) IOException(java.io.IOException) IndexFormatTooOldException(org.apache.lucene.index.IndexFormatTooOldException) StopWatch(org.elasticsearch.common.StopWatch) RetentionLease(org.elasticsearch.index.seqno.RetentionLease) AtomicLong(java.util.concurrent.atomic.AtomicLong) StepListener(org.elasticsearch.action.StepListener) IndexFormatTooNewException(org.apache.lucene.index.IndexFormatTooNewException)

Example 47 with StoreFileMetadata

use of org.elasticsearch.index.store.StoreFileMetadata in project crate by crate.

the class RecoverySourceHandler method handleErrorOnSendFiles.

private void handleErrorOnSendFiles(Store store, Exception e, StoreFileMetadata[] mds) throws Exception {
    final IOException corruptIndexException = ExceptionsHelper.unwrapCorruption(e);
    assert Transports.assertNotTransportThread(RecoverySourceHandler.this + "[handle error on send/clean files]");
    if (corruptIndexException != null) {
        Exception localException = null;
        for (StoreFileMetadata md : mds) {
            cancellableThreads.checkForCancel();
            logger.debug("checking integrity for file {} after remove corruption exception", md);
            if (store.checkIntegrityNoException(md) == false) {
                // we are corrupted on the primary -- fail!
                logger.warn("{} Corrupted file detected {} checksum mismatch", shardId, md);
                if (localException == null) {
                    localException = corruptIndexException;
                }
                failEngine(corruptIndexException);
            }
        }
        if (localException != null) {
            throw localException;
        } else {
            // corruption has happened on the way to replica
            RemoteTransportException remoteException = new RemoteTransportException("File corruption occurred on recovery but checksums are ok", null);
            remoteException.addSuppressed(e);
            logger.warn(() -> new ParameterizedMessage("{} Remote file corruption on node {}, recovering {}. local checksum OK", shardId, request.targetNode(), mds), corruptIndexException);
            throw remoteException;
        }
    }
    throw e;
}
Also used : RemoteTransportException(org.elasticsearch.transport.RemoteTransportException) ParameterizedMessage(org.apache.logging.log4j.message.ParameterizedMessage) IOException(java.io.IOException) StoreFileMetadata(org.elasticsearch.index.store.StoreFileMetadata) IndexFormatTooNewException(org.apache.lucene.index.IndexFormatTooNewException) RecoveryEngineException(org.elasticsearch.index.engine.RecoveryEngineException) RetentionLeaseNotFoundException(org.elasticsearch.index.seqno.RetentionLeaseNotFoundException) CorruptIndexException(org.apache.lucene.index.CorruptIndexException) RemoteTransportException(org.elasticsearch.transport.RemoteTransportException) IndexShardClosedException(org.elasticsearch.index.shard.IndexShardClosedException) IndexShardRelocatedException(org.elasticsearch.index.shard.IndexShardRelocatedException) IOException(java.io.IOException) IndexFormatTooOldException(org.apache.lucene.index.IndexFormatTooOldException)

Example 48 with StoreFileMetadata

use of org.elasticsearch.index.store.StoreFileMetadata in project crate by crate.

the class IndexShard method doCheckIndex.

private void doCheckIndex() throws IOException {
    final long timeNS = System.nanoTime();
    if (!Lucene.indexExists(store.directory())) {
        return;
    }
    BytesStreamOutput os = new BytesStreamOutput();
    PrintStream out = new PrintStream(os, false, StandardCharsets.UTF_8.name());
    if ("checksum".equals(checkIndexOnStartup)) {
        // physical verification only: verify all checksums for the latest commit
        IOException corrupt = null;
        MetadataSnapshot metadata = snapshotStoreMetadata();
        for (Map.Entry<String, StoreFileMetadata> entry : metadata.asMap().entrySet()) {
            try {
                Store.checkIntegrity(entry.getValue(), store.directory());
                out.println("checksum passed: " + entry.getKey());
            } catch (IOException exc) {
                out.println("checksum failed: " + entry.getKey());
                exc.printStackTrace(out);
                corrupt = exc;
            }
        }
        out.flush();
        if (corrupt != null) {
            logger.warn("check index [failure]\n{}", os.bytes().utf8ToString());
            throw corrupt;
        }
    } else {
        // full checkindex
        final CheckIndex.Status status = store.checkIndex(out);
        out.flush();
        if (!status.clean) {
            if (state == IndexShardState.CLOSED) {
                // ignore if closed....
                return;
            }
            logger.warn("check index [failure]\n{}", os.bytes().utf8ToString());
            throw new IOException("index check failure");
        }
    }
    if (logger.isDebugEnabled()) {
        logger.debug("check index [success]\n{}", os.bytes().utf8ToString());
    }
    recoveryState.getVerifyIndex().checkIndexTime(Math.max(0, TimeValue.nsecToMSec(System.nanoTime() - timeNS)));
}
Also used : PrintStream(java.io.PrintStream) IOException(java.io.IOException) StoreFileMetadata(org.elasticsearch.index.store.StoreFileMetadata) Map(java.util.Map) ObjectLongMap(com.carrotsearch.hppc.ObjectLongMap) BytesStreamOutput(org.elasticsearch.common.io.stream.BytesStreamOutput) CheckIndex(org.apache.lucene.index.CheckIndex) MetadataSnapshot(org.elasticsearch.index.store.Store.MetadataSnapshot)

Example 49 with StoreFileMetadata

use of org.elasticsearch.index.store.StoreFileMetadata in project crate by crate.

the class RecoverySourceHandlerTests method testSendFileChunksStopOnError.

@Test
public void testSendFileChunksStopOnError() throws Exception {
    final List<FileChunkResponse> unrepliedChunks = new CopyOnWriteArrayList<>();
    final AtomicInteger sentChunks = new AtomicInteger();
    final TestRecoveryTargetHandler recoveryTarget = new TestRecoveryTargetHandler() {

        final AtomicLong chunkNumberGenerator = new AtomicLong();

        @Override
        public void writeFileChunk(StoreFileMetadata md, long position, BytesReference content, boolean lastChunk, int totalTranslogOps, ActionListener<Void> listener) {
            final long chunkNumber = chunkNumberGenerator.getAndIncrement();
            logger.info("--> write chunk name={} seq={}, position={}", md.name(), chunkNumber, position);
            unrepliedChunks.add(new FileChunkResponse(chunkNumber, listener));
            sentChunks.incrementAndGet();
        }
    };
    final int maxConcurrentChunks = between(1, 4);
    final int chunkSize = between(1, 16);
    final RecoverySourceHandler handler = new RecoverySourceHandler(null, new AsyncRecoveryTarget(recoveryTarget, recoveryExecutor), threadPool, getStartRecoveryRequest(), chunkSize, maxConcurrentChunks, between(1, 5));
    Store store = newStore(createTempDir(), false);
    List<StoreFileMetadata> files = generateFiles(store, between(1, 10), () -> between(1, chunkSize * 20));
    int totalChunks = files.stream().mapToInt(md -> ((int) md.length() + chunkSize - 1) / chunkSize).sum();
    SetOnce<Exception> sendFilesError = new SetOnce<>();
    CountDownLatch sendFilesLatch = new CountDownLatch(1);
    handler.sendFiles(store, files.toArray(new StoreFileMetadata[0]), () -> 0, new LatchedActionListener<>(ActionListener.wrap(r -> sendFilesError.set(null), e -> sendFilesError.set(e)), sendFilesLatch));
    assertBusy(() -> assertThat(sentChunks.get(), equalTo(Math.min(totalChunks, maxConcurrentChunks))));
    List<FileChunkResponse> failedChunks = randomSubsetOf(between(1, unrepliedChunks.size()), unrepliedChunks);
    CountDownLatch replyLatch = new CountDownLatch(failedChunks.size());
    failedChunks.forEach(c -> {
        c.listener.onFailure(new IllegalStateException("test chunk exception"));
        replyLatch.countDown();
    });
    replyLatch.await();
    unrepliedChunks.removeAll(failedChunks);
    unrepliedChunks.forEach(c -> {
        if (randomBoolean()) {
            c.listener.onFailure(new RuntimeException("test"));
        } else {
            c.listener.onResponse(null);
        }
    });
    sendFilesLatch.await();
    assertThat(sendFilesError.get(), instanceOf(IllegalStateException.class));
    assertThat(sendFilesError.get().getMessage(), containsString("test chunk exception"));
    assertThat("no more chunks should be sent", sentChunks.get(), equalTo(Math.min(totalChunks, maxConcurrentChunks)));
    store.close();
}
Also used : BytesReference(org.elasticsearch.common.bytes.BytesReference) ShardId(org.elasticsearch.index.shard.ShardId) Versions(org.elasticsearch.common.lucene.uid.Versions) IndexSettingsModule(org.elasticsearch.test.IndexSettingsModule) IndexMetadata(org.elasticsearch.cluster.metadata.IndexMetadata) Term(org.apache.lucene.index.Term) ParseContext(org.elasticsearch.index.mapper.ParseContext) SeqNoStats(org.elasticsearch.index.seqno.SeqNoStats) Document(org.apache.lucene.document.Document) Mockito.doAnswer(org.mockito.Mockito.doAnswer) IOContext(org.apache.lucene.store.IOContext) Path(java.nio.file.Path) NumericDocValuesField(org.apache.lucene.document.NumericDocValuesField) PlainActionFuture(org.elasticsearch.action.support.PlainActionFuture) UUIDs(org.elasticsearch.common.UUIDs) Set(java.util.Set) StandardCharsets(java.nio.charset.StandardCharsets) Matchers.instanceOf(org.hamcrest.Matchers.instanceOf) SeqNoFieldMapper(org.elasticsearch.index.mapper.SeqNoFieldMapper) CountDownLatch(java.util.concurrent.CountDownLatch) ReplicationTracker(org.elasticsearch.index.seqno.ReplicationTracker) IndexOutputOutputStream(org.elasticsearch.common.lucene.store.IndexOutputOutputStream) Matchers.containsString(org.hamcrest.Matchers.containsString) CopyOnWriteArrayList(java.util.concurrent.CopyOnWriteArrayList) Mockito.mock(org.mockito.Mockito.mock) IndexCommit(org.apache.lucene.index.IndexCommit) IndexShardRelocatedException(org.elasticsearch.index.shard.IndexShardRelocatedException) ArrayList(java.util.ArrayList) BytesArray(org.elasticsearch.common.bytes.BytesArray) RetentionLease(org.elasticsearch.index.seqno.RetentionLease) RetentionLeases(org.elasticsearch.index.seqno.RetentionLeases) DiscoveryNode(org.elasticsearch.cluster.node.DiscoveryNode) Store(org.elasticsearch.index.store.Store) Matchers.hasSize(org.hamcrest.Matchers.hasSize) ESTestCase(org.elasticsearch.test.ESTestCase) Before(org.junit.Before) FileSystemUtils(org.elasticsearch.common.io.FileSystemUtils) SequenceNumbers(org.elasticsearch.index.seqno.SequenceNumbers) SetOnce(org.apache.lucene.util.SetOnce) Executor(java.util.concurrent.Executor) IdFieldMapper(org.elasticsearch.index.mapper.IdFieldMapper) IOUtils(io.crate.common.io.IOUtils) IndexShard(org.elasticsearch.index.shard.IndexShard) Test(org.junit.Test) IOException(java.io.IOException) ParsedDocument(org.elasticsearch.index.mapper.ParsedDocument) AtomicLong(java.util.concurrent.atomic.AtomicLong) CRC32(java.util.zip.CRC32) TextField(org.apache.lucene.document.TextField) RandomIndexWriter(org.apache.lucene.index.RandomIndexWriter) ActionListener(org.elasticsearch.action.ActionListener) Randomness(org.elasticsearch.common.Randomness) ArgumentMatchers.anyString(org.mockito.ArgumentMatchers.anyString) CancellableThreads(org.elasticsearch.common.util.CancellableThreads) ConcurrentCollections(org.elasticsearch.common.util.concurrent.ConcurrentCollections) RecoveryEngineException(org.elasticsearch.index.engine.RecoveryEngineException) VersionType(org.elasticsearch.index.VersionType) CorruptIndexException(org.apache.lucene.index.CorruptIndexException) StoreFileMetadata(org.elasticsearch.index.store.StoreFileMetadata) Settings(org.elasticsearch.common.settings.Settings) AtomicInteger(java.util.concurrent.atomic.AtomicInteger) Directory(org.apache.lucene.store.Directory) After(org.junit.After) ThreadPool(org.elasticsearch.threadpool.ThreadPool) StepListener(org.elasticsearch.action.StepListener) Releasable(org.elasticsearch.common.lease.Releasable) ArgumentMatchers.anyObject(org.mockito.ArgumentMatchers.anyObject) DirectoryReader(org.apache.lucene.index.DirectoryReader) UNASSIGNED_SEQ_NO(org.elasticsearch.index.seqno.SequenceNumbers.UNASSIGNED_SEQ_NO) BytesReference(org.elasticsearch.common.bytes.BytesReference) Engine(org.elasticsearch.index.engine.Engine) List(java.util.List) Version(org.elasticsearch.Version) Matchers.equalTo(org.hamcrest.Matchers.equalTo) TimeValue(io.crate.common.unit.TimeValue) IndexReader(org.apache.lucene.index.IndexReader) ArgumentMatchers.any(org.mockito.ArgumentMatchers.any) StringField(org.apache.lucene.document.StringField) PRIMARY(org.elasticsearch.index.engine.Engine.Operation.Origin.PRIMARY) AtomicBoolean(java.util.concurrent.atomic.AtomicBoolean) HashMap(java.util.HashMap) HashSet(java.util.HashSet) BaseDirectoryWrapper(org.apache.lucene.store.BaseDirectoryWrapper) IndexSettings(org.elasticsearch.index.IndexSettings) LatchedActionListener(org.elasticsearch.action.LatchedActionListener) IntSupplier(java.util.function.IntSupplier) OutputStream(java.io.OutputStream) Collections.emptyMap(java.util.Collections.emptyMap) TestThreadPool(org.elasticsearch.threadpool.TestThreadPool) Numbers(org.elasticsearch.common.Numbers) IndexShardState(org.elasticsearch.index.shard.IndexShardState) CorruptionUtils(org.elasticsearch.test.CorruptionUtils) Uid(org.elasticsearch.index.mapper.Uid) Iterator(java.util.Iterator) Collections.emptySet(java.util.Collections.emptySet) Mockito.when(org.mockito.Mockito.when) VersionUtils(org.elasticsearch.test.VersionUtils) TimeUnit(java.util.concurrent.TimeUnit) ExceptionsHelper(org.elasticsearch.ExceptionsHelper) ClusterSettings(org.elasticsearch.common.settings.ClusterSettings) Field(org.apache.lucene.document.Field) Translog(org.elasticsearch.index.translog.Translog) DummyShardLock(org.elasticsearch.test.DummyShardLock) Comparator(java.util.Comparator) Collections(java.util.Collections) SetOnce(org.apache.lucene.util.SetOnce) Store(org.elasticsearch.index.store.Store) StoreFileMetadata(org.elasticsearch.index.store.StoreFileMetadata) CountDownLatch(java.util.concurrent.CountDownLatch) IndexShardRelocatedException(org.elasticsearch.index.shard.IndexShardRelocatedException) IOException(java.io.IOException) RecoveryEngineException(org.elasticsearch.index.engine.RecoveryEngineException) CorruptIndexException(org.apache.lucene.index.CorruptIndexException) AtomicLong(java.util.concurrent.atomic.AtomicLong) ActionListener(org.elasticsearch.action.ActionListener) LatchedActionListener(org.elasticsearch.action.LatchedActionListener) AtomicInteger(java.util.concurrent.atomic.AtomicInteger) CopyOnWriteArrayList(java.util.concurrent.CopyOnWriteArrayList) Test(org.junit.Test)

Example 50 with StoreFileMetadata

use of org.elasticsearch.index.store.StoreFileMetadata in project crate by crate.

the class RecoverySourceHandlerTests method testHandleCorruptedIndexOnSendSendFiles.

@Test
public void testHandleCorruptedIndexOnSendSendFiles() throws Throwable {
    Settings settings = Settings.builder().put("indices.recovery.concurrent_streams", 1).put("indices.recovery.concurrent_small_file_streams", 1).build();
    final RecoverySettings recoverySettings = new RecoverySettings(settings, service);
    final StartRecoveryRequest request = getStartRecoveryRequest();
    Path tempDir = createTempDir();
    Store store = newStore(tempDir, false);
    AtomicBoolean failedEngine = new AtomicBoolean(false);
    Directory dir = store.directory();
    RandomIndexWriter writer = new RandomIndexWriter(random(), dir, newIndexWriterConfig());
    int numDocs = randomIntBetween(10, 100);
    for (int i = 0; i < numDocs; i++) {
        Document document = new Document();
        document.add(new StringField("id", Integer.toString(i), Field.Store.YES));
        document.add(newField("field", randomUnicodeOfCodepointLengthBetween(1, 10), TextField.TYPE_STORED));
        writer.addDocument(document);
    }
    writer.commit();
    writer.close();
    Store.MetadataSnapshot metadata = store.getMetadata(null);
    List<StoreFileMetadata> metas = new ArrayList<>();
    for (StoreFileMetadata md : metadata) {
        metas.add(md);
    }
    CorruptionUtils.corruptFile(random(), FileSystemUtils.files(tempDir, (p) -> (p.getFileName().toString().equals("write.lock") || p.getFileName().toString().startsWith("extra")) == false));
    Store targetStore = newStore(createTempDir(), false);
    MultiFileWriter multiFileWriter = new MultiFileWriter(targetStore, mock(RecoveryState.Index.class), "", logger, () -> {
    });
    RecoveryTargetHandler target = new TestRecoveryTargetHandler() {

        @Override
        public void writeFileChunk(StoreFileMetadata md, long position, BytesReference content, boolean lastChunk, int totalTranslogOps, ActionListener<Void> listener) {
            ActionListener.completeWith(listener, () -> {
                multiFileWriter.writeFileChunk(md, position, content, lastChunk);
                return null;
            });
        }
    };
    RecoverySourceHandler handler = new RecoverySourceHandler(null, new AsyncRecoveryTarget(target, recoveryExecutor), threadPool, request, Math.toIntExact(recoverySettings.getChunkSize().getBytes()), between(1, 8), between(1, 8)) {

        @Override
        protected void failEngine(IOException cause) {
            assertFalse(failedEngine.get());
            failedEngine.set(true);
        }
    };
    SetOnce<Exception> sendFilesError = new SetOnce<>();
    CountDownLatch latch = new CountDownLatch(1);
    handler.sendFiles(store, metas.toArray(new StoreFileMetadata[0]), () -> 0, new LatchedActionListener<>(ActionListener.wrap(r -> sendFilesError.set(null), e -> sendFilesError.set(e)), latch));
    latch.await();
    assertThat(sendFilesError.get(), instanceOf(IOException.class));
    assertNotNull(ExceptionsHelper.unwrapCorruption(sendFilesError.get()));
    assertTrue(failedEngine.get());
    // ensure all chunk requests have been completed; otherwise some files on the target are left open.
    IOUtils.close(() -> terminate(threadPool), () -> threadPool = null);
    IOUtils.close(store, multiFileWriter, targetStore);
}
Also used : ShardId(org.elasticsearch.index.shard.ShardId) Versions(org.elasticsearch.common.lucene.uid.Versions) IndexSettingsModule(org.elasticsearch.test.IndexSettingsModule) IndexMetadata(org.elasticsearch.cluster.metadata.IndexMetadata) Term(org.apache.lucene.index.Term) ParseContext(org.elasticsearch.index.mapper.ParseContext) SeqNoStats(org.elasticsearch.index.seqno.SeqNoStats) Document(org.apache.lucene.document.Document) Mockito.doAnswer(org.mockito.Mockito.doAnswer) IOContext(org.apache.lucene.store.IOContext) Path(java.nio.file.Path) NumericDocValuesField(org.apache.lucene.document.NumericDocValuesField) PlainActionFuture(org.elasticsearch.action.support.PlainActionFuture) UUIDs(org.elasticsearch.common.UUIDs) Set(java.util.Set) StandardCharsets(java.nio.charset.StandardCharsets) Matchers.instanceOf(org.hamcrest.Matchers.instanceOf) SeqNoFieldMapper(org.elasticsearch.index.mapper.SeqNoFieldMapper) CountDownLatch(java.util.concurrent.CountDownLatch) ReplicationTracker(org.elasticsearch.index.seqno.ReplicationTracker) IndexOutputOutputStream(org.elasticsearch.common.lucene.store.IndexOutputOutputStream) Matchers.containsString(org.hamcrest.Matchers.containsString) CopyOnWriteArrayList(java.util.concurrent.CopyOnWriteArrayList) Mockito.mock(org.mockito.Mockito.mock) IndexCommit(org.apache.lucene.index.IndexCommit) IndexShardRelocatedException(org.elasticsearch.index.shard.IndexShardRelocatedException) ArrayList(java.util.ArrayList) BytesArray(org.elasticsearch.common.bytes.BytesArray) RetentionLease(org.elasticsearch.index.seqno.RetentionLease) RetentionLeases(org.elasticsearch.index.seqno.RetentionLeases) DiscoveryNode(org.elasticsearch.cluster.node.DiscoveryNode) Store(org.elasticsearch.index.store.Store) Matchers.hasSize(org.hamcrest.Matchers.hasSize) ESTestCase(org.elasticsearch.test.ESTestCase) Before(org.junit.Before) FileSystemUtils(org.elasticsearch.common.io.FileSystemUtils) SequenceNumbers(org.elasticsearch.index.seqno.SequenceNumbers) SetOnce(org.apache.lucene.util.SetOnce) Executor(java.util.concurrent.Executor) IdFieldMapper(org.elasticsearch.index.mapper.IdFieldMapper) IOUtils(io.crate.common.io.IOUtils) IndexShard(org.elasticsearch.index.shard.IndexShard) Test(org.junit.Test) IOException(java.io.IOException) ParsedDocument(org.elasticsearch.index.mapper.ParsedDocument) AtomicLong(java.util.concurrent.atomic.AtomicLong) CRC32(java.util.zip.CRC32) TextField(org.apache.lucene.document.TextField) RandomIndexWriter(org.apache.lucene.index.RandomIndexWriter) ActionListener(org.elasticsearch.action.ActionListener) Randomness(org.elasticsearch.common.Randomness) ArgumentMatchers.anyString(org.mockito.ArgumentMatchers.anyString) CancellableThreads(org.elasticsearch.common.util.CancellableThreads) ConcurrentCollections(org.elasticsearch.common.util.concurrent.ConcurrentCollections) RecoveryEngineException(org.elasticsearch.index.engine.RecoveryEngineException) VersionType(org.elasticsearch.index.VersionType) CorruptIndexException(org.apache.lucene.index.CorruptIndexException) StoreFileMetadata(org.elasticsearch.index.store.StoreFileMetadata) Settings(org.elasticsearch.common.settings.Settings) AtomicInteger(java.util.concurrent.atomic.AtomicInteger) Directory(org.apache.lucene.store.Directory) After(org.junit.After) ThreadPool(org.elasticsearch.threadpool.ThreadPool) StepListener(org.elasticsearch.action.StepListener) Releasable(org.elasticsearch.common.lease.Releasable) ArgumentMatchers.anyObject(org.mockito.ArgumentMatchers.anyObject) DirectoryReader(org.apache.lucene.index.DirectoryReader) UNASSIGNED_SEQ_NO(org.elasticsearch.index.seqno.SequenceNumbers.UNASSIGNED_SEQ_NO) BytesReference(org.elasticsearch.common.bytes.BytesReference) Engine(org.elasticsearch.index.engine.Engine) List(java.util.List) Version(org.elasticsearch.Version) Matchers.equalTo(org.hamcrest.Matchers.equalTo) TimeValue(io.crate.common.unit.TimeValue) IndexReader(org.apache.lucene.index.IndexReader) ArgumentMatchers.any(org.mockito.ArgumentMatchers.any) StringField(org.apache.lucene.document.StringField) PRIMARY(org.elasticsearch.index.engine.Engine.Operation.Origin.PRIMARY) AtomicBoolean(java.util.concurrent.atomic.AtomicBoolean) HashMap(java.util.HashMap) HashSet(java.util.HashSet) BaseDirectoryWrapper(org.apache.lucene.store.BaseDirectoryWrapper) IndexSettings(org.elasticsearch.index.IndexSettings) LatchedActionListener(org.elasticsearch.action.LatchedActionListener) IntSupplier(java.util.function.IntSupplier) OutputStream(java.io.OutputStream) Collections.emptyMap(java.util.Collections.emptyMap) TestThreadPool(org.elasticsearch.threadpool.TestThreadPool) Numbers(org.elasticsearch.common.Numbers) IndexShardState(org.elasticsearch.index.shard.IndexShardState) CorruptionUtils(org.elasticsearch.test.CorruptionUtils) Uid(org.elasticsearch.index.mapper.Uid) Iterator(java.util.Iterator) Collections.emptySet(java.util.Collections.emptySet) Mockito.when(org.mockito.Mockito.when) VersionUtils(org.elasticsearch.test.VersionUtils) TimeUnit(java.util.concurrent.TimeUnit) ExceptionsHelper(org.elasticsearch.ExceptionsHelper) ClusterSettings(org.elasticsearch.common.settings.ClusterSettings) Field(org.apache.lucene.document.Field) Translog(org.elasticsearch.index.translog.Translog) DummyShardLock(org.elasticsearch.test.DummyShardLock) Comparator(java.util.Comparator) Collections(java.util.Collections) CopyOnWriteArrayList(java.util.concurrent.CopyOnWriteArrayList) ArrayList(java.util.ArrayList) Store(org.elasticsearch.index.store.Store) StoreFileMetadata(org.elasticsearch.index.store.StoreFileMetadata) Document(org.apache.lucene.document.Document) ParsedDocument(org.elasticsearch.index.mapper.ParsedDocument) Settings(org.elasticsearch.common.settings.Settings) IndexSettings(org.elasticsearch.index.IndexSettings) ClusterSettings(org.elasticsearch.common.settings.ClusterSettings) Directory(org.apache.lucene.store.Directory) Path(java.nio.file.Path) BytesReference(org.elasticsearch.common.bytes.BytesReference) SetOnce(org.apache.lucene.util.SetOnce) IOException(java.io.IOException) CountDownLatch(java.util.concurrent.CountDownLatch) IndexShardRelocatedException(org.elasticsearch.index.shard.IndexShardRelocatedException) IOException(java.io.IOException) RecoveryEngineException(org.elasticsearch.index.engine.RecoveryEngineException) CorruptIndexException(org.apache.lucene.index.CorruptIndexException) AtomicBoolean(java.util.concurrent.atomic.AtomicBoolean) ActionListener(org.elasticsearch.action.ActionListener) LatchedActionListener(org.elasticsearch.action.LatchedActionListener) StringField(org.apache.lucene.document.StringField) RandomIndexWriter(org.apache.lucene.index.RandomIndexWriter) Test(org.junit.Test)

Aggregations

StoreFileMetadata (org.elasticsearch.index.store.StoreFileMetadata)34 RoutingAllocation (org.elasticsearch.cluster.routing.allocation.RoutingAllocation)30 StoreFileMetaData (org.elasticsearch.index.store.StoreFileMetaData)25 IOException (java.io.IOException)19 ArrayList (java.util.ArrayList)18 Store (org.elasticsearch.index.store.Store)17 DiscoveryNode (org.elasticsearch.cluster.node.DiscoveryNode)16 CorruptIndexException (org.apache.lucene.index.CorruptIndexException)13 Directory (org.apache.lucene.store.Directory)10 RetentionLease (org.elasticsearch.index.seqno.RetentionLease)10 IndexShardRelocatedException (org.elasticsearch.index.shard.IndexShardRelocatedException)10 List (java.util.List)9 CopyOnWriteArrayList (java.util.concurrent.CopyOnWriteArrayList)9 Document (org.apache.lucene.document.Document)9 StringField (org.apache.lucene.document.StringField)9 RandomIndexWriter (org.apache.lucene.index.RandomIndexWriter)9 BytesArray (org.elasticsearch.common.bytes.BytesArray)9 RecoveryEngineException (org.elasticsearch.index.engine.RecoveryEngineException)9 ParsedDocument (org.elasticsearch.index.mapper.ParsedDocument)9 Settings (org.elasticsearch.common.settings.Settings)8