public void testV0LegacyTranslogVersion() throws Exception { Path translogFile = getDataPath("/org/elasticsearch/index/translog/translog-v0.binary"); assertThat("test file should exist", Files.exists(translogFile), equalTo(true)); try (ImmutableTranslogReader reader = openReader(translogFile, 0)) { assertThat( "a version0 stream is returned", reader instanceof LegacyTranslogReader, equalTo(true)); try (final Translog.Snapshot snapshot = reader.newSnapshot()) { final Translog.Operation operation = snapshot.next(); assertThat( "operation is the correct type correctly", operation.opType() == Translog.Operation.Type.INDEX, equalTo(true)); Translog.Index op = (Translog.Index) operation; assertThat(op.id(), equalTo("1")); assertThat(op.type(), equalTo("doc")); assertThat( op.source().toUtf8(), equalTo("{\"body\": \"worda wordb wordc wordd \\\"worde\\\" wordf\"}")); assertThat(op.routing(), equalTo(null)); assertThat(op.parent(), equalTo(null)); assertThat(op.version(), equalTo(1L)); assertThat(op.timestamp(), equalTo(1407312091791L)); assertThat(op.ttl(), equalTo(-1L)); assertThat(op.versionType(), equalTo(VersionType.INTERNAL)); assertNull(snapshot.next()); } } }
public void testV1ChecksummedTranslogVersion() throws Exception { Path translogFile = getDataPath("/org/elasticsearch/index/translog/translog-v1.binary"); assertThat("test file should exist", Files.exists(translogFile), equalTo(true)); try (ImmutableTranslogReader reader = openReader(translogFile, 0)) { try (final Translog.Snapshot snapshot = reader.newSnapshot()) { assertThat( "a version1 stream is returned", reader instanceof ImmutableTranslogReader, equalTo(true)); Translog.Operation operation = snapshot.next(); assertThat( "operation is the correct type correctly", operation.opType() == Translog.Operation.Type.INDEX, equalTo(true)); Translog.Index op = (Translog.Index) operation; assertThat(op.id(), equalTo("Bwiq98KFSb6YjJQGeSpeiw")); assertThat(op.type(), equalTo("doc")); assertThat(op.source().toUtf8(), equalTo("{\"body\": \"foo\"}")); assertThat(op.routing(), equalTo(null)); assertThat(op.parent(), equalTo(null)); assertThat(op.version(), equalTo(1L)); assertThat(op.timestamp(), equalTo(1408627184844L)); assertThat(op.ttl(), equalTo(-1L)); assertThat(op.versionType(), equalTo(VersionType.INTERNAL)); // There are more operations int opNum = 1; while (snapshot.next() != null) { opNum++; } assertThat("there should be 5 translog operations", opNum, equalTo(5)); } } }
public void testCorruptedTranslogs() throws Exception { try { Path translogFile = getDataPath("/org/elasticsearch/index/translog/translog-v1-corrupted-magic.binary"); assertThat("test file should exist", Files.exists(translogFile), equalTo(true)); openReader(translogFile, 0); fail("should have thrown an exception about the header being corrupt"); } catch (TranslogCorruptedException e) { assertThat( "translog corruption from header: " + e.getMessage(), e.getMessage() .contains("translog looks like version 1 or later, but has corrupted header"), equalTo(true)); } try { Path translogFile = getDataPath("/org/elasticsearch/index/translog/translog-invalid-first-byte.binary"); assertThat("test file should exist", Files.exists(translogFile), equalTo(true)); openReader(translogFile, 0); fail("should have thrown an exception about the header being corrupt"); } catch (TranslogCorruptedException e) { assertThat( "translog corruption from header: " + e.getMessage(), e.getMessage() .contains("Invalid first byte in translog file, got: 1, expected 0x00 or 0x3f"), equalTo(true)); } try { Path translogFile = getDataPath("/org/elasticsearch/index/translog/translog-v1-corrupted-body.binary"); assertThat("test file should exist", Files.exists(translogFile), equalTo(true)); try (ImmutableTranslogReader reader = openReader(translogFile, 0)) { try (final Translog.Snapshot snapshot = reader.newSnapshot()) { while (snapshot.next() != null) {} } } fail("should have thrown an exception about the body being corrupted"); } catch (TranslogCorruptedException e) { assertThat( "translog corruption from body: " + e.getMessage(), e.getMessage().contains("translog corruption while reading from stream"), equalTo(true)); } }
public void testTruncatedTranslog() throws Exception { try { Path translogFile = getDataPath("/org/elasticsearch/index/translog/translog-v1-truncated.binary"); assertThat("test file should exist", Files.exists(translogFile), equalTo(true)); try (ImmutableTranslogReader reader = openReader(translogFile, 0)) { try (final Translog.Snapshot snapshot = reader.newSnapshot()) { while (snapshot.next() != null) {} } } fail("should have thrown an exception about the body being truncated"); } catch (TranslogCorruptedException e) { assertThat( "translog truncated: " + e.getMessage(), e.getMessage().contains("operation size is corrupted must be"), equalTo(true)); } }
/** * Send the given snapshot's operations to this handler's target node. * * <p>Operations are bulked into a single request depending on an operation count limit or * size-in-bytes limit * * @return the total number of translog operations that were sent */ protected int sendSnapshot(final Translog.Snapshot snapshot) { int ops = 0; long size = 0; int totalOperations = 0; final List<Translog.Operation> operations = new ArrayList<>(); Translog.Operation operation; try { operation = snapshot.next(); // this ex should bubble up } catch (IOException ex) { throw new ElasticsearchException("failed to get next operation from translog", ex); } if (operation == null) { logger.trace( "[{}][{}] no translog operations to send to {}", indexName, shardId, request.targetNode()); } while (operation != null) { if (shard.state() == IndexShardState.CLOSED) { throw new IndexShardClosedException(request.shardId()); } cancellableThreads.checkForCancel(); operations.add(operation); ops += 1; size += operation.estimateSize(); totalOperations++; // Check if this request is past bytes threshold, and // if so, send it off if (size >= chunkSizeInBytes) { // don't throttle translog, since we lock for phase3 indexing, // so we need to move it as fast as possible. Note, since we // index docs to replicas while the index files are recovered // the lock can potentially be removed, in which case, it might // make sense to re-enable throttling in this phase cancellableThreads.execute( () -> recoveryTarget.indexTranslogOperations(operations, snapshot.totalOperations())); if (logger.isTraceEnabled()) { logger.trace( "[{}][{}] sent batch of [{}][{}] (total: [{}]) translog operations to {}", indexName, shardId, ops, new ByteSizeValue(size), snapshot.totalOperations(), request.targetNode()); } ops = 0; size = 0; operations.clear(); } try { operation = snapshot.next(); // this ex should bubble up } catch (IOException ex) { throw new ElasticsearchException("failed to get next operation from translog", ex); } } // send the leftover if (!operations.isEmpty()) { cancellableThreads.execute( () -> recoveryTarget.indexTranslogOperations(operations, snapshot.totalOperations())); } if (logger.isTraceEnabled()) { logger.trace( "[{}][{}] sent final batch of [{}][{}] (total: [{}]) translog operations to {}", indexName, shardId, ops, new ByteSizeValue(size), snapshot.totalOperations(), request.targetNode()); } return totalOperations; }
/** * Send the given snapshot's operations to this handler's target node. * * <p>Operations are bulked into a single request depending on an operation count limit or * size-in-bytes limit * * @return the total number of translog operations that were sent */ protected int sendSnapshot(Translog.Snapshot snapshot) throws ElasticsearchException { int ops = 0; long size = 0; int totalOperations = 0; final List<Translog.Operation> operations = Lists.newArrayList(); Translog.Operation operation = snapshot.next(); final TransportRequestOptions recoveryOptions = TransportRequestOptions.options() .withCompress(recoverySettings.compress()) .withType(TransportRequestOptions.Type.RECOVERY) .withTimeout(recoverySettings.internalActionLongTimeout()); if (operation == null) { logger.trace( "[{}][{}] no translog operations (id: [{}]) to send to {}", indexName, shardId, snapshot.translogId(), request.targetNode()); } while (operation != null) { if (shard.state() == IndexShardState.CLOSED) { throw new IndexShardClosedException(request.shardId()); } cancellableThreads.checkForCancel(); operations.add(operation); ops += 1; size += operation.estimateSize(); totalOperations++; // Check if this request is past the size or bytes threshold, and // if so, send it off if (ops >= recoverySettings.translogOps() || size >= recoverySettings.translogSize().bytes()) { // don't throttle translog, since we lock for phase3 indexing, // so we need to move it as fast as possible. Note, since we // index docs to replicas while the index files are recovered // the lock can potentially be removed, in which case, it might // make sense to re-enable throttling in this phase // if (recoverySettings.rateLimiter() != null) { // recoverySettings.rateLimiter().pause(size); // } if (logger.isTraceEnabled()) { logger.trace( "[{}][{}] sending batch of [{}][{}] (total: [{}], id: [{}]) translog operations to {}", indexName, shardId, ops, new ByteSizeValue(size), shard.translog().estimatedNumberOfOperations(), snapshot.translogId(), request.targetNode()); } cancellableThreads.execute( new Interruptable() { @Override public void run() throws InterruptedException { final RecoveryTranslogOperationsRequest translogOperationsRequest = new RecoveryTranslogOperationsRequest( request.recoveryId(), request.shardId(), operations, shard.translog().estimatedNumberOfOperations()); transportService .submitRequest( request.targetNode(), RecoveryTarget.Actions.TRANSLOG_OPS, translogOperationsRequest, recoveryOptions, EmptyTransportResponseHandler.INSTANCE_SAME) .txGet(); } }); ops = 0; size = 0; operations.clear(); } operation = snapshot.next(); } // send the leftover if (logger.isTraceEnabled()) { logger.trace( "[{}][{}] sending final batch of [{}][{}] (total: [{}], id: [{}]) translog operations to {}", indexName, shardId, ops, new ByteSizeValue(size), shard.translog().estimatedNumberOfOperations(), snapshot.translogId(), request.targetNode()); } if (!operations.isEmpty()) { cancellableThreads.execute( new Interruptable() { @Override public void run() throws InterruptedException { RecoveryTranslogOperationsRequest translogOperationsRequest = new RecoveryTranslogOperationsRequest( request.recoveryId(), request.shardId(), operations, shard.translog().estimatedNumberOfOperations()); transportService .submitRequest( request.targetNode(), RecoveryTarget.Actions.TRANSLOG_OPS, translogOperationsRequest, recoveryOptions, EmptyTransportResponseHandler.INSTANCE_SAME) .txGet(); } }); } return totalOperations; }