Search in sources :

Example 1 with StreamSegmentSealedException

use of io.pravega.segmentstore.contracts.StreamSegmentSealedException in project pravega by pravega.

the class FileSystemStorage method doWrite.

private Void doWrite(SegmentHandle handle, long offset, InputStream data, int length) throws Exception {
    long traceId = LoggerHelpers.traceEnter(log, "write", handle.getSegmentName(), offset, length);
    Timer timer = new Timer();
    if (handle.isReadOnly()) {
        throw new IllegalArgumentException("Write called on a readonly handle of segment " + handle.getSegmentName());
    }
    Path path = Paths.get(config.getRoot(), handle.getSegmentName());
    // This means that writes to readonly files also succeed. We need to explicitly check permissions in this case.
    if (!isWritableFile(path)) {
        throw new StreamSegmentSealedException(handle.getSegmentName());
    }
    long fileSize = path.toFile().length();
    if (fileSize < offset) {
        throw new BadOffsetException(handle.getSegmentName(), fileSize, offset);
    } else {
        long totalBytesWritten = 0;
        try (FileChannel channel = FileChannel.open(path, StandardOpenOption.WRITE)) {
            // Wrap the input data into a ReadableByteChannel, but do not close it. Doing so will result in closing
            // the underlying InputStream, which is not desirable if it is to be reused.
            ReadableByteChannel sourceChannel = Channels.newChannel(data);
            while (length != 0) {
                long bytesWritten = channel.transferFrom(sourceChannel, offset, length);
                assert bytesWritten > 0 : "Unable to make any progress transferring data.";
                offset += bytesWritten;
                totalBytesWritten += bytesWritten;
                length -= bytesWritten;
            }
        }
        FileSystemMetrics.WRITE_LATENCY.reportSuccessEvent(timer.getElapsed());
        FileSystemMetrics.WRITE_BYTES.add(totalBytesWritten);
        LoggerHelpers.traceLeave(log, "write", traceId);
        return null;
    }
}
Also used : Path(java.nio.file.Path) ReadableByteChannel(java.nio.channels.ReadableByteChannel) Timer(io.pravega.common.Timer) StreamSegmentSealedException(io.pravega.segmentstore.contracts.StreamSegmentSealedException) FileChannel(java.nio.channels.FileChannel) BadOffsetException(io.pravega.segmentstore.contracts.BadOffsetException)

Example 2 with StreamSegmentSealedException

use of io.pravega.segmentstore.contracts.StreamSegmentSealedException in project pravega by pravega.

the class ContainerMetadataUpdateTransactionTests method testPreProcessStreamSegmentAppend.

// region StreamSegmentAppendOperation
/**
 * Tests the preProcess method with StreamSegmentAppend operations.
 * Scenarios:
 * * Recovery Mode
 * * Non-recovery mode
 * * StreamSegment is Merged (both in-transaction and in-metadata)
 * * StreamSegment is Sealed (both in-transaction and in-metadata)
 */
@Test
public void testPreProcessStreamSegmentAppend() throws Exception {
    val metadata = createMetadata();
    StreamSegmentAppendOperation appendOp = createAppendNoOffset();
    // When everything is OK (in recovery mode) - nothing should change.
    metadata.enterRecoveryMode();
    val txn1 = createUpdateTransaction(metadata);
    txn1.preProcessOperation(appendOp);
    AssertExtensions.assertLessThan("Unexpected StreamSegmentOffset after call to preProcess in recovery mode.", 0, appendOp.getStreamSegmentOffset());
    checkNoSequenceNumberAssigned(appendOp, "call to preProcess in recovery mode");
    Assert.assertEquals("preProcess(Append) seems to have changed the Updater internal state in recovery mode.", SEGMENT_LENGTH, txn1.getStreamSegmentMetadata(SEGMENT_ID).getLength());
    Assert.assertEquals("preProcess(Append) seems to have changed the metadata in recovery mode.", SEGMENT_LENGTH, metadata.getStreamSegmentMetadata(SEGMENT_ID).getLength());
    // When everything is OK (no recovery mode).
    metadata.exitRecoveryMode();
    val txn2 = createUpdateTransaction(metadata);
    txn2.preProcessOperation(appendOp);
    Assert.assertEquals("Unexpected StreamSegmentOffset after call to preProcess in non-recovery mode.", SEGMENT_LENGTH, appendOp.getStreamSegmentOffset());
    checkNoSequenceNumberAssigned(appendOp, "call to preProcess in non-recovery mode");
    Assert.assertEquals("preProcess(Append) seems to have changed the Updater internal state.", SEGMENT_LENGTH, txn2.getStreamSegmentMetadata(SEGMENT_ID).getLength());
    Assert.assertEquals("preProcess(Append) seems to have changed the metadata.", SEGMENT_LENGTH, metadata.getStreamSegmentMetadata(SEGMENT_ID).getLength());
    // When StreamSegment is merged (via transaction).
    StreamSegmentAppendOperation transactionAppendOp = new StreamSegmentAppendOperation(SEALED_TRANSACTION_ID, DEFAULT_APPEND_DATA, null);
    MergeTransactionOperation mergeOp = createMerge();
    txn2.preProcessOperation(mergeOp);
    txn2.acceptOperation(mergeOp);
    Assert.assertFalse("Transaction should not be merged in metadata (yet).", metadata.getStreamSegmentMetadata(SEALED_TRANSACTION_ID).isMerged());
    AssertExtensions.assertThrows("Unexpected behavior for preProcess(Append) when Segment is merged (in transaction).", () -> txn2.preProcessOperation(transactionAppendOp), ex -> ex instanceof StreamSegmentMergedException);
    // When StreamSegment is merged (via metadata).
    txn2.commit(metadata);
    Assert.assertTrue("Transaction should have been merged in metadata.", metadata.getStreamSegmentMetadata(SEALED_TRANSACTION_ID).isMerged());
    AssertExtensions.assertThrows("Unexpected behavior for preProcess(Append) when Segment is merged (in metadata).", () -> txn2.preProcessOperation(transactionAppendOp), ex -> ex instanceof StreamSegmentMergedException);
    // When StreamSegment is sealed (via transaction).
    StreamSegmentSealOperation sealOp = createSeal();
    txn2.preProcessOperation(sealOp);
    txn2.acceptOperation(sealOp);
    Assert.assertFalse("StreamSegment should not be sealed in metadata (yet).", metadata.getStreamSegmentMetadata(SEGMENT_ID).isSealed());
    AssertExtensions.assertThrows("Unexpected behavior for preProcess(Append) when Segment is sealed (in transaction).", () -> txn2.preProcessOperation(createAppendNoOffset()), ex -> ex instanceof StreamSegmentSealedException);
    // When StreamSegment is sealed (via metadata).
    txn2.commit(metadata);
    Assert.assertTrue("StreamSegment should have been sealed in metadata.", metadata.getStreamSegmentMetadata(SEGMENT_ID).isSealed());
    AssertExtensions.assertThrows("Unexpected behavior for preProcess(Append) when Segment is sealed (in metadata).", () -> txn2.preProcessOperation(createAppendNoOffset()), ex -> ex instanceof StreamSegmentSealedException);
}
Also used : lombok.val(lombok.val) StreamSegmentSealOperation(io.pravega.segmentstore.server.logs.operations.StreamSegmentSealOperation) StreamSegmentSealedException(io.pravega.segmentstore.contracts.StreamSegmentSealedException) StreamSegmentMergedException(io.pravega.segmentstore.contracts.StreamSegmentMergedException) StreamSegmentAppendOperation(io.pravega.segmentstore.server.logs.operations.StreamSegmentAppendOperation) MergeTransactionOperation(io.pravega.segmentstore.server.logs.operations.MergeTransactionOperation) Test(org.junit.Test)

Example 3 with StreamSegmentSealedException

use of io.pravega.segmentstore.contracts.StreamSegmentSealedException in project pravega by pravega.

the class ContainerMetadataUpdateTransactionTests method testPreProcessStreamSegmentSeal.

// endregion
// region StreamSegmentSealOperation
/**
 * Tests the preProcess method with StreamSegmentSeal operations.
 * Scenarios:
 * * Recovery Mode
 * * Non-recovery mode
 * * StreamSegment is Merged (both in-transaction and in-metadata)
 * * StreamSegment is Sealed (both in-transaction and in-metadata)
 */
@Test
public void testPreProcessStreamSegmentSeal() throws Exception {
    UpdateableContainerMetadata metadata = createMetadata();
    StreamSegmentSealOperation sealOp = createSeal();
    // When everything is OK (in recovery mode) - nothing should change.
    metadata.enterRecoveryMode();
    val txn1 = createUpdateTransaction(metadata);
    txn1.preProcessOperation(sealOp);
    AssertExtensions.assertLessThan("Unexpected StreamSegmentLength after call to preProcess in recovery mode.", 0, sealOp.getStreamSegmentOffset());
    checkNoSequenceNumberAssigned(sealOp, "call to preProcess in recovery mode");
    Assert.assertFalse("preProcess(Seal) seems to have changed the Updater internal state in recovery mode.", txn1.getStreamSegmentMetadata(SEGMENT_ID).isSealed());
    Assert.assertFalse("preProcess(Seal) seems to have changed the metadata in recovery mode.", metadata.getStreamSegmentMetadata(SEGMENT_ID).isSealed());
    // When everything is OK (no recovery mode).
    metadata.exitRecoveryMode();
    val txn2 = createUpdateTransaction(metadata);
    txn2.preProcessOperation(sealOp);
    Assert.assertEquals("Unexpected StreamSegmentLength after call to preProcess in non-recovery mode.", SEGMENT_LENGTH, sealOp.getStreamSegmentOffset());
    checkNoSequenceNumberAssigned(sealOp, "call to preProcess in non-recovery mode");
    Assert.assertFalse("preProcess(Seal) seems to have changed the Updater internal state.", txn2.getStreamSegmentMetadata(SEGMENT_ID).isSealed());
    Assert.assertFalse("preProcess(Seal) seems to have changed the metadata.", metadata.getStreamSegmentMetadata(SEGMENT_ID).isSealed());
    // When StreamSegment is merged (via transaction).
    StreamSegmentSealOperation transactionSealOp = new StreamSegmentSealOperation(SEALED_TRANSACTION_ID);
    MergeTransactionOperation mergeOp = createMerge();
    txn2.preProcessOperation(mergeOp);
    txn2.acceptOperation(mergeOp);
    Assert.assertFalse("Transaction should not be merged in metadata (yet).", metadata.getStreamSegmentMetadata(SEALED_TRANSACTION_ID).isMerged());
    AssertExtensions.assertThrows("Unexpected behavior for preProcess(Seal) when Segment is merged (in transaction).", () -> txn2.preProcessOperation(transactionSealOp), ex -> ex instanceof StreamSegmentMergedException);
    // When StreamSegment is merged (via metadata).
    txn2.commit(metadata);
    Assert.assertTrue("Transaction should have been merged in metadata.", metadata.getStreamSegmentMetadata(SEALED_TRANSACTION_ID).isMerged());
    AssertExtensions.assertThrows("Unexpected behavior for preProcess(Seal) when Segment is merged (in metadata).", () -> txn2.preProcessOperation(transactionSealOp), ex -> ex instanceof StreamSegmentMergedException);
    // When StreamSegment is sealed (via transaction).
    txn2.acceptOperation(sealOp);
    Assert.assertFalse("StreamSegment should not be sealed in metadata (yet).", metadata.getStreamSegmentMetadata(SEGMENT_ID).isSealed());
    AssertExtensions.assertThrows("Unexpected behavior for preProcess(Seal) when Segment is sealed (in transaction).", () -> txn2.preProcessOperation(createSeal()), ex -> ex instanceof StreamSegmentSealedException);
    // When StreamSegment is sealed (via metadata).
    txn2.commit(metadata);
    Assert.assertTrue("StreamSegment should have been sealed in metadata.", metadata.getStreamSegmentMetadata(SEGMENT_ID).isSealed());
    AssertExtensions.assertThrows("Unexpected behavior for preProcess(Seal) when Segment is sealed (in metadata).", () -> txn2.preProcessOperation(createSeal()), ex -> ex instanceof StreamSegmentSealedException);
}
Also used : lombok.val(lombok.val) StreamSegmentSealOperation(io.pravega.segmentstore.server.logs.operations.StreamSegmentSealOperation) StreamSegmentSealedException(io.pravega.segmentstore.contracts.StreamSegmentSealedException) UpdateableContainerMetadata(io.pravega.segmentstore.server.UpdateableContainerMetadata) StreamSegmentMergedException(io.pravega.segmentstore.contracts.StreamSegmentMergedException) MergeTransactionOperation(io.pravega.segmentstore.server.logs.operations.MergeTransactionOperation) Test(org.junit.Test)

Example 4 with StreamSegmentSealedException

use of io.pravega.segmentstore.contracts.StreamSegmentSealedException in project pravega by pravega.

the class AppendProcessor method handleException.

private void handleException(UUID writerId, long requestId, String segment, String doingWhat, Throwable u) {
    if (u == null) {
        IllegalStateException exception = new IllegalStateException("No exception to handle.");
        log.error("Append processor: Error {} on segment = '{}'", doingWhat, segment, exception);
        throw exception;
    }
    u = Exceptions.unwrap(u);
    if (u instanceof StreamSegmentExistsException) {
        log.warn("Segment '{}' already exists and {} cannot perform operation '{}'.", segment, writerId, doingWhat);
        connection.send(new SegmentAlreadyExists(requestId, segment));
    } else if (u instanceof StreamSegmentNotExistsException) {
        log.warn("Segment '{}' does not exist and {} cannot perform operation '{}'.", segment, writerId, doingWhat);
        connection.send(new NoSuchSegment(requestId, segment));
    } else if (u instanceof StreamSegmentSealedException) {
        log.info("Segment '{}' is sealed and {} cannot perform operation '{}'.", segment, writerId, doingWhat);
        connection.send(new SegmentIsSealed(requestId, segment));
    } else if (u instanceof ContainerNotFoundException) {
        int containerId = ((ContainerNotFoundException) u).getContainerId();
        log.warn("Wrong host. Segment '{}' (Container {}) is not owned and {} cannot perform operation '{}'.", segment, containerId, writerId, doingWhat);
        connection.send(new WrongHost(requestId, segment, ""));
    } else if (u instanceof BadAttributeUpdateException) {
        log.warn("Bad attribute update by {} on segment {}.", writerId, segment, u);
        connection.send(new InvalidEventNumber(writerId, requestId));
        connection.close();
    } else if (u instanceof TooManyAttributesException) {
        log.warn("Attribute limit would be exceeded by {} on segment {}.", writerId, segment, u);
        connection.send(new InvalidEventNumber(writerId, requestId));
        connection.close();
    } else if (u instanceof AuthenticationException) {
        log.warn("Token check failed while being written by {} on segment {}.", writerId, segment, u);
        connection.send(new WireCommands.AuthTokenCheckFailed(requestId));
        connection.close();
    } else if (u instanceof UnsupportedOperationException) {
        log.warn("Unsupported Operation '{}'.", doingWhat, u);
        connection.send(new OperationUnsupported(requestId, doingWhat));
    } else {
        log.error("Error (Segment = '{}', Operation = 'append')", segment, u);
        // Closing connection should reinitialize things, and hopefully fix the problem
        connection.close();
    }
}
Also used : TooManyAttributesException(io.pravega.segmentstore.contracts.TooManyAttributesException) OperationUnsupported(io.pravega.shared.protocol.netty.WireCommands.OperationUnsupported) AuthenticationException(io.pravega.common.auth.AuthenticationException) WrongHost(io.pravega.shared.protocol.netty.WireCommands.WrongHost) StreamSegmentNotExistsException(io.pravega.segmentstore.contracts.StreamSegmentNotExistsException) StreamSegmentExistsException(io.pravega.segmentstore.contracts.StreamSegmentExistsException) SegmentAlreadyExists(io.pravega.shared.protocol.netty.WireCommands.SegmentAlreadyExists) StreamSegmentSealedException(io.pravega.segmentstore.contracts.StreamSegmentSealedException) SegmentIsSealed(io.pravega.shared.protocol.netty.WireCommands.SegmentIsSealed) BadAttributeUpdateException(io.pravega.segmentstore.contracts.BadAttributeUpdateException) InvalidEventNumber(io.pravega.shared.protocol.netty.WireCommands.InvalidEventNumber) NoSuchSegment(io.pravega.shared.protocol.netty.WireCommands.NoSuchSegment) WireCommands(io.pravega.shared.protocol.netty.WireCommands) ContainerNotFoundException(io.pravega.segmentstore.contracts.ContainerNotFoundException)

Example 5 with StreamSegmentSealedException

use of io.pravega.segmentstore.contracts.StreamSegmentSealedException in project pravega by pravega.

the class StreamSegmentReadIndex method triggerFutureReads.

// endregion
// region Reading
/**
 * Triggers all future reads that have a starting offset before the given value.
 *
 * @throws IllegalStateException If the read index is in recovery mode.
 */
void triggerFutureReads() {
    Exceptions.checkNotClosed(this.closed, this);
    Preconditions.checkState(!this.recoveryMode, "StreamSegmentReadIndex is in Recovery Mode.");
    // Get all eligible Future Reads which wait for data prior to the end offset.
    // Since we are not actually using this entry's data, there is no need to 'touch' it.
    ReadIndexEntry lastEntry;
    synchronized (this.lock) {
        lastEntry = this.indexEntries.getLast();
    }
    if (lastEntry == null) {
        // Nothing to do.
        return;
    }
    Collection<FutureReadResultEntry> futureReads;
    boolean sealed = this.metadata.isSealed();
    if (sealed) {
        // Get everything, even if some Future Reads are in the future - those will eventually return EndOfSegment.
        futureReads = this.futureReads.pollAll();
    } else {
        // Get only those up to the last offset of the last append.
        futureReads = this.futureReads.poll(lastEntry.getLastStreamSegmentOffset());
    }
    log.debug("{}: triggerFutureReads (Count = {}, Offset = {}, Sealed = {}).", this.traceObjectId, futureReads.size(), lastEntry.getLastStreamSegmentOffset(), sealed);
    for (FutureReadResultEntry r : futureReads) {
        ReadResultEntry entry = getSingleReadResultEntry(r.getStreamSegmentOffset(), r.getRequestedReadLength());
        assert entry != null : "Serving a StorageReadResultEntry with a null result";
        assert !(entry instanceof FutureReadResultEntry) : "Serving a FutureReadResultEntry with another FutureReadResultEntry.";
        log.trace("{}: triggerFutureReads (Offset = {}, Type = {}).", this.traceObjectId, r.getStreamSegmentOffset(), entry.getType());
        if (entry.getType() == ReadResultEntryType.EndOfStreamSegment) {
            // We have attempted to read beyond the end of the stream. Fail the read request with the appropriate message.
            r.fail(new StreamSegmentSealedException(String.format("StreamSegment has been sealed at offset %d. There can be no more reads beyond this offset.", this.metadata.getLength())));
        } else {
            if (!entry.getContent().isDone()) {
                // Normally, all Future Reads are served from Cache, since they reflect data that has just been appended.
                // However, it's possible that after recovery, we get a read for some data that we do not have in the
                // cache (but it's not a tail read) - this data exists in Storage but our StorageLength has not yet been
                // updated. As such, the only solution we have is to return a FutureRead which will be satisfied when
                // the Writer updates the StorageLength (and trigger future reads). In that scenario, entry we get
                // will likely not be auto-fetched, so we need to request the content.
                entry.requestContent(this.config.getStorageReadDefaultTimeout());
            }
            CompletableFuture<ReadResultEntryContents> entryContent = entry.getContent();
            entryContent.thenAccept(r::complete);
            Futures.exceptionListener(entryContent, r::fail);
        }
    }
}
Also used : Consumer(java.util.function.Consumer) ReadResultEntryContents(io.pravega.segmentstore.contracts.ReadResultEntryContents) StreamSegmentSealedException(io.pravega.segmentstore.contracts.StreamSegmentSealedException) ReadResultEntry(io.pravega.segmentstore.contracts.ReadResultEntry)

Aggregations

StreamSegmentSealedException (io.pravega.segmentstore.contracts.StreamSegmentSealedException)13 Test (org.junit.Test)8 lombok.val (lombok.val)6 StreamSegmentNotExistsException (io.pravega.segmentstore.contracts.StreamSegmentNotExistsException)5 BadOffsetException (io.pravega.segmentstore.contracts.BadOffsetException)4 StreamSegmentMergedException (io.pravega.segmentstore.contracts.StreamSegmentMergedException)4 UpdateableContainerMetadata (io.pravega.segmentstore.server.UpdateableContainerMetadata)4 ByteArrayOutputStream (java.io.ByteArrayOutputStream)4 ArrayList (java.util.ArrayList)4 HashMap (java.util.HashMap)4 Cleanup (lombok.Cleanup)4 ReadResult (io.pravega.segmentstore.contracts.ReadResult)3 ReadResultEntry (io.pravega.segmentstore.contracts.ReadResultEntry)3 ReadResultEntryContents (io.pravega.segmentstore.contracts.ReadResultEntryContents)3 SegmentProperties (io.pravega.segmentstore.contracts.SegmentProperties)3 HashSet (java.util.HashSet)3 CompletableFuture (java.util.concurrent.CompletableFuture)3 AtomicLong (java.util.concurrent.atomic.AtomicLong)3 Runnables (com.google.common.util.concurrent.Runnables)2 Service (com.google.common.util.concurrent.Service)2