Search in sources :

Example 6 with StreamSegmentAppendOperation

use of io.pravega.segmentstore.server.logs.operations.StreamSegmentAppendOperation in project pravega by pravega.

the class ContainerMetadataUpdateTransactionTests method testProcessMetadataCheckpoint.

/**
 * Tests the processMetadataOperation method with MetadataCheckpoint operations.
 */
@Test
public void testProcessMetadataCheckpoint() throws Exception {
    // When encountering MetadataCheckpoint in non-Recovery Mode, the ContainerMetadataUpdateTransaction serializes a snapshot
    // of the current metadata inside the Operation.
    // When encountering MetadataCheckpoint in Recovery Mode, the ContainerMetadataUpdateTransaction deserializes the snapshot-ted
    // metadata in it and applies it to the container metadata (inside the transaction). All existing metadata updates
    // are cleared.
    String newSegmentName = "NewSegmentId";
    AtomicLong seqNo = new AtomicLong();
    // Create a non-empty metadata, and in addition, seal a segment and truncate it.
    this.timeProvider.setElapsedMillis(1234);
    UpdateableContainerMetadata metadata = createMetadata();
    metadata.getStreamSegmentMetadata(SEGMENT_ID).markSealed();
    metadata.getStreamSegmentMetadata(SEGMENT_ID).setStartOffset(SEGMENT_LENGTH / 2);
    val txn = createUpdateTransaction(metadata);
    // Checkpoint 1: original metadata.
    // Checkpoint 2: Checkpoint 1 + 1 StreamSegment and 1 Transaction + 1 Append
    MetadataCheckpointOperation checkpoint1 = createMetadataCheckpoint();
    MetadataCheckpointOperation checkpoint2 = createMetadataCheckpoint();
    // Checkpoint 1 Should have original metadata.
    processOperation(checkpoint1, txn, seqNo::incrementAndGet);
    UpdateableContainerMetadata checkpointedMetadata = getCheckpointedMetadata(checkpoint1);
    assertMetadataSame("Unexpected metadata before any operation.", metadata, checkpointedMetadata);
    // Map another StreamSegment, and add an append
    StreamSegmentMapOperation mapOp = new StreamSegmentMapOperation(StreamSegmentInformation.builder().name(newSegmentName).length(SEGMENT_LENGTH).build());
    processOperation(mapOp, txn, seqNo::incrementAndGet);
    processOperation(new StreamSegmentAppendOperation(mapOp.getStreamSegmentId(), DEFAULT_APPEND_DATA, createAttributeUpdates()), txn, seqNo::incrementAndGet);
    processOperation(checkpoint2, txn, seqNo::incrementAndGet);
    // Checkpoint 2 should have Checkpoint 1 + New StreamSegment + Append.
    txn.commit(metadata);
    checkpointedMetadata = getCheckpointedMetadata(checkpoint2);
    assertMetadataSame("Unexpected metadata after deserializing checkpoint.", metadata, checkpointedMetadata);
}
Also used : lombok.val(lombok.val) AtomicLong(java.util.concurrent.atomic.AtomicLong) StorageMetadataCheckpointOperation(io.pravega.segmentstore.server.logs.operations.StorageMetadataCheckpointOperation) MetadataCheckpointOperation(io.pravega.segmentstore.server.logs.operations.MetadataCheckpointOperation) StreamSegmentMapOperation(io.pravega.segmentstore.server.logs.operations.StreamSegmentMapOperation) UpdateableContainerMetadata(io.pravega.segmentstore.server.UpdateableContainerMetadata) StreamSegmentAppendOperation(io.pravega.segmentstore.server.logs.operations.StreamSegmentAppendOperation) Test(org.junit.Test)

Example 7 with StreamSegmentAppendOperation

use of io.pravega.segmentstore.server.logs.operations.StreamSegmentAppendOperation in project pravega by pravega.

the class ContainerMetadataUpdateTransactionTests method testStreamSegmentAppendWithOffset.

/**
 * Tests the ability of the ContainerMetadataUpdateTransaction to process (and accept) StreamSegmentAppendOperations with
 * predefined offsets.
 */
@Test
public void testStreamSegmentAppendWithOffset() throws Exception {
    UpdateableContainerMetadata metadata = createMetadata();
    val txn = createUpdateTransaction(metadata);
    // Append #1 (at offset 0).
    long offset = metadata.getStreamSegmentMetadata(SEGMENT_ID).getLength();
    StreamSegmentAppendOperation appendOp = createAppendWithOffset(offset);
    txn.preProcessOperation(appendOp);
    Assert.assertEquals("Unexpected StreamSegmentOffset after call to preProcess in non-recovery mode.", offset, appendOp.getStreamSegmentOffset());
    checkNoSequenceNumberAssigned(appendOp, "call to preProcess in non-recovery mode");
    Assert.assertEquals("preProcess(Append) seems to have changed the Updater internal state.", offset, txn.getStreamSegmentMetadata(SEGMENT_ID).getLength());
    Assert.assertEquals("preProcess(Append) seems to have changed the metadata.", offset, metadata.getStreamSegmentMetadata(SEGMENT_ID).getLength());
    txn.acceptOperation(appendOp);
    // Append #2 (after Append #1)
    offset = appendOp.getStreamSegmentOffset() + appendOp.getLength();
    appendOp = createAppendWithOffset(offset);
    txn.preProcessOperation(appendOp);
    Assert.assertEquals("Unexpected StreamSegmentOffset after call to preProcess in non-recovery mode.", offset, appendOp.getStreamSegmentOffset());
    checkNoSequenceNumberAssigned(appendOp, "call to preProcess in non-recovery mode");
    Assert.assertEquals("preProcess(Append) seems to have changed the Updater internal state.", offset, txn.getStreamSegmentMetadata(SEGMENT_ID).getLength());
    Assert.assertEquals("preProcess(Append) seems to have changed the metadata.", SEGMENT_LENGTH, metadata.getStreamSegmentMetadata(SEGMENT_ID).getLength());
    txn.acceptOperation(appendOp);
    // Append #3 (wrong offset)
    offset = appendOp.getStreamSegmentOffset() + appendOp.getLength() - 1;
    StreamSegmentAppendOperation badAppendOp = createAppendWithOffset(offset);
    AssertExtensions.assertThrows("preProcessOperations accepted an append with the wrong offset.", () -> txn.preProcessOperation(badAppendOp), ex -> ex instanceof BadOffsetException);
    AssertExtensions.assertThrows("acceptOperation accepted an append that was rejected during preProcessing.", () -> txn.acceptOperation(badAppendOp), ex -> ex instanceof MetadataUpdateException);
}
Also used : lombok.val(lombok.val) BadOffsetException(io.pravega.segmentstore.contracts.BadOffsetException) UpdateableContainerMetadata(io.pravega.segmentstore.server.UpdateableContainerMetadata) StreamSegmentAppendOperation(io.pravega.segmentstore.server.logs.operations.StreamSegmentAppendOperation) Test(org.junit.Test)

Example 8 with StreamSegmentAppendOperation

use of io.pravega.segmentstore.server.logs.operations.StreamSegmentAppendOperation in project pravega by pravega.

the class MemoryStateUpdater method addToReadIndex.

/**
 * Registers the given operation in the ReadIndex.
 *
 * @param operation The operation to register.
 */
private void addToReadIndex(StorageOperation operation) {
    try {
        if (operation instanceof StreamSegmentAppendOperation) {
            // Record a StreamSegmentAppendOperation. Just in case, we also support this type of operation, but we need to
            // log a warning indicating so. This means we do not optimize memory properly, and we end up storing data
            // in two different places.
            StreamSegmentAppendOperation appendOperation = (StreamSegmentAppendOperation) operation;
            this.readIndex.append(appendOperation.getStreamSegmentId(), appendOperation.getStreamSegmentOffset(), appendOperation.getData());
        } else if (operation instanceof MergeTransactionOperation) {
            // Record a MergeTransactionOperation. We call beginMerge here, and the StorageWriter will call completeMerge.
            MergeTransactionOperation mergeOperation = (MergeTransactionOperation) operation;
            this.readIndex.beginMerge(mergeOperation.getStreamSegmentId(), mergeOperation.getStreamSegmentOffset(), mergeOperation.getTransactionSegmentId());
        } else {
            assert !(operation instanceof CachedStreamSegmentAppendOperation) : "attempted to add a CachedStreamSegmentAppendOperation to the ReadIndex";
        }
    } catch (ObjectClosedException | StreamSegmentNotExistsException ex) {
        // The Segment is in the process of being deleted. We usually end up in here because a concurrent delete
        // request has updated the metadata while we were executing.
        log.warn("Not adding operation '{}' to ReadIndex because it refers to a deleted StreamSegment.", operation);
    }
}
Also used : ObjectClosedException(io.pravega.common.ObjectClosedException) CachedStreamSegmentAppendOperation(io.pravega.segmentstore.server.logs.operations.CachedStreamSegmentAppendOperation) StreamSegmentAppendOperation(io.pravega.segmentstore.server.logs.operations.StreamSegmentAppendOperation) MergeTransactionOperation(io.pravega.segmentstore.server.logs.operations.MergeTransactionOperation) StreamSegmentNotExistsException(io.pravega.segmentstore.contracts.StreamSegmentNotExistsException) CachedStreamSegmentAppendOperation(io.pravega.segmentstore.server.logs.operations.CachedStreamSegmentAppendOperation)

Example 9 with StreamSegmentAppendOperation

use of io.pravega.segmentstore.server.logs.operations.StreamSegmentAppendOperation in project pravega by pravega.

the class SegmentAggregator method reconcileAppendOperation.

/**
 * Attempts to reconcile the given Append Operation. Since Append Operations can be partially flushed, reconciliation
 * may be for the full operation or for a part of it.
 *
 * @param op          The Operation (StreamSegmentAppendOperation or CachedStreamSegmentAppendOperation) to reconcile.
 * @param storageInfo The current state of the Segment in Storage.
 * @param timer       Timer for the operation.
 * @return A CompletableFuture containing a FlushResult with the number of bytes reconciled, or failed with a ReconciliationFailureException,
 * if the operation cannot be reconciled, based on the in-memory metadata or the current state of the Segment in Storage.
 */
private CompletableFuture<FlushResult> reconcileAppendOperation(StorageOperation op, SegmentProperties storageInfo, TimeoutTimer timer) {
    Preconditions.checkArgument(op instanceof AggregatedAppendOperation, "Not given an append operation.");
    // Read data from Storage, and compare byte-by-byte.
    InputStream appendStream = this.dataSource.getAppendData(op.getStreamSegmentId(), op.getStreamSegmentOffset(), (int) op.getLength());
    if (appendStream == null) {
        return Futures.failedFuture(new ReconciliationFailureException(String.format("Unable to reconcile operation '%s' because no append data is associated with it.", op), this.metadata, storageInfo));
    }
    // Only read as much data as we need.
    long readLength = Math.min(op.getLastStreamSegmentOffset(), storageInfo.getLength()) - op.getStreamSegmentOffset();
    assert readLength > 0 : "Append Operation to be reconciled is beyond the Segment's StorageLength " + op;
    AtomicInteger bytesReadSoFar = new AtomicInteger();
    // Read all data from storage.
    byte[] storageData = new byte[(int) readLength];
    return Futures.loop(() -> bytesReadSoFar.get() < readLength, () -> this.storage.read(this.handle.get(), op.getStreamSegmentOffset() + bytesReadSoFar.get(), storageData, bytesReadSoFar.get(), (int) readLength - bytesReadSoFar.get(), timer.getRemaining()), bytesRead -> {
        assert bytesRead > 0 : String.format("Unable to make any read progress when reconciling operation '%s' after reading %s bytes.", op, bytesReadSoFar);
        bytesReadSoFar.addAndGet(bytesRead);
    }, this.executor).thenApplyAsync(v -> {
        // Compare, byte-by-byte, the contents of the append.
        verifySame(appendStream, storageData, op, storageInfo);
        if (readLength >= op.getLength() && op.getLastStreamSegmentOffset() <= storageInfo.getLength()) {
            // Operation has been completely validated; pop it off the list.
            StorageOperation removedOp = this.operations.removeFirst();
            assert op == removedOp : "Reconciled operation is not the same as removed operation";
        }
        return new FlushResult().withFlushedBytes(readLength);
    }, this.executor);
}
Also used : Storage(io.pravega.segmentstore.storage.Storage) Getter(lombok.Getter) StreamSegmentNotExistsException(io.pravega.segmentstore.contracts.StreamSegmentNotExistsException) SneakyThrows(lombok.SneakyThrows) Exceptions(io.pravega.common.Exceptions) RequiredArgsConstructor(lombok.RequiredArgsConstructor) AtomicBoolean(java.util.concurrent.atomic.AtomicBoolean) CompletableFuture(java.util.concurrent.CompletableFuture) AtomicReference(java.util.concurrent.atomic.AtomicReference) UpdateableSegmentMetadata(io.pravega.segmentstore.server.UpdateableSegmentMetadata) SegmentProperties(io.pravega.segmentstore.contracts.SegmentProperties) AbstractTimer(io.pravega.common.AbstractTimer) StreamSegmentSealedException(io.pravega.segmentstore.contracts.StreamSegmentSealedException) SegmentMetadata(io.pravega.segmentstore.server.SegmentMetadata) SegmentHandle(io.pravega.segmentstore.storage.SegmentHandle) AtomicInteger(java.util.concurrent.atomic.AtomicInteger) Duration(java.time.Duration) Operation(io.pravega.segmentstore.server.logs.operations.Operation) StreamSegmentTruncateOperation(io.pravega.segmentstore.server.logs.operations.StreamSegmentTruncateOperation) LoggerHelpers(io.pravega.common.LoggerHelpers) TimeoutTimer(io.pravega.common.TimeoutTimer) Executor(java.util.concurrent.Executor) CompletionException(java.util.concurrent.CompletionException) ThreadSafe(javax.annotation.concurrent.ThreadSafe) GuardedBy(javax.annotation.concurrent.GuardedBy) AtomicLong(java.util.concurrent.atomic.AtomicLong) Slf4j(lombok.extern.slf4j.Slf4j) CachedStreamSegmentAppendOperation(io.pravega.segmentstore.server.logs.operations.CachedStreamSegmentAppendOperation) StorageOperation(io.pravega.segmentstore.server.logs.operations.StorageOperation) StreamSegmentAppendOperation(io.pravega.segmentstore.server.logs.operations.StreamSegmentAppendOperation) BadOffsetException(io.pravega.segmentstore.contracts.BadOffsetException) Preconditions(com.google.common.base.Preconditions) DataCorruptionException(io.pravega.segmentstore.server.DataCorruptionException) ArrayDeque(java.util.ArrayDeque) MergeTransactionOperation(io.pravega.segmentstore.server.logs.operations.MergeTransactionOperation) Futures(io.pravega.common.concurrent.Futures) StreamSegmentSealOperation(io.pravega.segmentstore.server.logs.operations.StreamSegmentSealOperation) InputStream(java.io.InputStream) AtomicInteger(java.util.concurrent.atomic.AtomicInteger) InputStream(java.io.InputStream) StorageOperation(io.pravega.segmentstore.server.logs.operations.StorageOperation)

Example 10 with StreamSegmentAppendOperation

use of io.pravega.segmentstore.server.logs.operations.StreamSegmentAppendOperation in project pravega by pravega.

the class StreamSegmentContainer method append.

// endregion
// region StreamSegmentStore Implementation
@Override
public CompletableFuture<Void> append(String streamSegmentName, byte[] data, Collection<AttributeUpdate> attributeUpdates, Duration timeout) {
    ensureRunning();
    TimeoutTimer timer = new TimeoutTimer(timeout);
    logRequest("append", streamSegmentName, data.length);
    this.metrics.append();
    return this.segmentMapper.getOrAssignStreamSegmentId(streamSegmentName, timer.getRemaining(), streamSegmentId -> {
        StreamSegmentAppendOperation operation = new StreamSegmentAppendOperation(streamSegmentId, data, attributeUpdates);
        return this.durableLog.add(operation, timer.getRemaining());
    });
}
Also used : StreamSegmentAppendOperation(io.pravega.segmentstore.server.logs.operations.StreamSegmentAppendOperation) TimeoutTimer(io.pravega.common.TimeoutTimer)

Aggregations

StreamSegmentAppendOperation (io.pravega.segmentstore.server.logs.operations.StreamSegmentAppendOperation)26 MergeTransactionOperation (io.pravega.segmentstore.server.logs.operations.MergeTransactionOperation)13 lombok.val (lombok.val)12 Test (org.junit.Test)12 CachedStreamSegmentAppendOperation (io.pravega.segmentstore.server.logs.operations.CachedStreamSegmentAppendOperation)9 Operation (io.pravega.segmentstore.server.logs.operations.Operation)9 StorageOperation (io.pravega.segmentstore.server.logs.operations.StorageOperation)9 StreamSegmentMapOperation (io.pravega.segmentstore.server.logs.operations.StreamSegmentMapOperation)8 StreamSegmentSealOperation (io.pravega.segmentstore.server.logs.operations.StreamSegmentSealOperation)8 ArrayList (java.util.ArrayList)8 UpdateableContainerMetadata (io.pravega.segmentstore.server.UpdateableContainerMetadata)7 UpdateableSegmentMetadata (io.pravega.segmentstore.server.UpdateableSegmentMetadata)7 MetadataCheckpointOperation (io.pravega.segmentstore.server.logs.operations.MetadataCheckpointOperation)7 StreamSegmentTruncateOperation (io.pravega.segmentstore.server.logs.operations.StreamSegmentTruncateOperation)6 HashMap (java.util.HashMap)6 StorageMetadataCheckpointOperation (io.pravega.segmentstore.server.logs.operations.StorageMetadataCheckpointOperation)5 DataCorruptionException (io.pravega.segmentstore.server.DataCorruptionException)4 SegmentMetadata (io.pravega.segmentstore.server.SegmentMetadata)4 ProbeOperation (io.pravega.segmentstore.server.logs.operations.ProbeOperation)4 SegmentOperation (io.pravega.segmentstore.server.logs.operations.SegmentOperation)4