Search in sources :

Example 6 with StreamSegmentTruncatedException

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

the class RollingStorage method read.

@Override
public int read(SegmentHandle handle, long offset, byte[] buffer, int bufferOffset, int length) throws StreamSegmentException {
    val h = asReadableHandle(handle);
    long traceId = LoggerHelpers.traceEnter(log, "read", handle, offset, length);
    ensureNotDeleted(h);
    Exceptions.checkArrayRange(bufferOffset, length, buffer.length, "bufferOffset", "length");
    if (offset < 0 || bufferOffset < 0 || length < 0 || buffer.length < bufferOffset + length) {
        throw new ArrayIndexOutOfBoundsException(String.format("Offset (%s) must be non-negative, and bufferOffset (%s) and length (%s) must be valid indices into buffer of size %s.", offset, bufferOffset, length, buffer.length));
    }
    if (h.isReadOnly() && !h.isSealed() && offset + length > h.length()) {
        // We have a non-sealed read-only handle. It's possible that the SegmentChunks may have been modified since
        // the last time we refreshed it, and we received a request for a read beyond our last known offset. Reload
        // the handle before attempting the read.
        val newHandle = (RollingSegmentHandle) openRead(handle.getSegmentName());
        h.refresh(newHandle);
        log.debug("Handle refreshed: {}.", h);
    }
    Preconditions.checkArgument(offset < h.length(), "Offset %s is beyond the last offset %s of the segment.", offset, h.length());
    Preconditions.checkArgument(offset + length <= h.length(), "Offset %s + length %s is beyond the last offset %s of the segment.", offset, length, h.length());
    // Read in a loop, from each SegmentChunk, until we can't read anymore.
    // If at any point we encounter a StreamSegmentNotExistsException, fail immediately with StreamSegmentTruncatedException (+inner).
    val chunks = h.chunks();
    int currentIndex = CollectionHelpers.binarySearch(chunks, s -> offset < s.getStartOffset() ? -1 : (offset >= s.getLastOffset() ? 1 : 0));
    assert currentIndex >= 0 : "unable to locate first SegmentChunk index.";
    try {
        int bytesRead = 0;
        while (bytesRead < length && currentIndex < chunks.size()) {
            // Verify if this is a known truncated SegmentChunk; if so, bail out quickly.
            SegmentChunk current = chunks.get(currentIndex);
            checkTruncatedSegment(null, h, current);
            if (current.getLength() == 0) {
                // Empty SegmentChunk; don't bother trying to read from it.
                continue;
            }
            long readOffset = offset + bytesRead - current.getStartOffset();
            int readLength = (int) Math.min(length - bytesRead, current.getLength() - readOffset);
            assert readOffset >= 0 && readLength >= 0 : "negative readOffset or readLength";
            // Read from the actual SegmentChunk into the given buffer.
            try {
                val sh = this.baseStorage.openRead(current.getName());
                int count = this.baseStorage.read(sh, readOffset, buffer, bufferOffset + bytesRead, readLength);
                bytesRead += count;
                if (readOffset + count >= current.getLength()) {
                    currentIndex++;
                }
            } catch (StreamSegmentNotExistsException ex) {
                log.debug("SegmentChunk '{}' does not exist anymore ({}).", current, h);
                checkTruncatedSegment(ex, h, current);
            }
        }
        LoggerHelpers.traceLeave(log, "read", traceId, handle, offset, bytesRead);
        return bytesRead;
    } catch (StreamSegmentTruncatedException ex) {
        // It's possible that the Segment has been truncated or deleted altogether using another handle. We need to
        // refresh the handle and throw the appropriate exception.
        val newHandle = (RollingSegmentHandle) openRead(handle.getSegmentName());
        h.refresh(newHandle);
        if (h.isDeleted()) {
            log.debug("Segment '{}' has been deleted. Cannot read anymore.", h);
            throw new StreamSegmentNotExistsException(handle.getSegmentName(), ex);
        } else {
            throw ex;
        }
    }
}
Also used : lombok.val(lombok.val) StreamSegmentTruncatedException(io.pravega.segmentstore.contracts.StreamSegmentTruncatedException) StreamSegmentNotExistsException(io.pravega.segmentstore.contracts.StreamSegmentNotExistsException)

Example 7 with StreamSegmentTruncatedException

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

the class RollingStorageTests method testTruncate.

/**
 * Tests the ability to truncate Segments.
 */
@Test
public void testTruncate() throws Exception {
    // Write small and large writes, alternatively.
    @Cleanup val baseStorage = new TestStorage();
    @Cleanup val s = new RollingStorage(baseStorage, DEFAULT_ROLLING_POLICY);
    s.initialize(1);
    s.create(SEGMENT_NAME);
    val writeHandle = (RollingSegmentHandle) s.openWrite(SEGMENT_NAME);
    // Open now, before writing, so we force a refresh.
    val readHandle = s.openRead(SEGMENT_NAME);
    val writeStream = new ByteArrayOutputStream();
    populate(s, writeHandle, writeStream);
    byte[] writtenData = writeStream.toByteArray();
    int truncateOffset = 0;
    while (true) {
        s.truncate(writeHandle, truncateOffset);
        // Verify we can still read properly.
        checkWrittenData(writtenData, truncateOffset, readHandle, s);
        // Verify each SegmentChunk's existence.
        for (SegmentChunk segmentChunk : writeHandle.chunks()) {
            boolean expectedExists = segmentChunk.getLastOffset() > truncateOffset || (segmentChunk.getStartOffset() == segmentChunk.getLastOffset() && segmentChunk.getLastOffset() == truncateOffset);
            Assert.assertEquals("Unexpected SegmentChunk truncation status for " + segmentChunk + ", truncation offset = " + truncateOffset, expectedExists, segmentChunk.exists());
            boolean existsInStorage = baseStorage.exists(segmentChunk.getName());
            Assert.assertEquals("Expected SegmentChunk deletion status for " + segmentChunk + ", truncation offset = " + truncateOffset, expectedExists, existsInStorage);
            if (!expectedExists) {
                AssertExtensions.assertThrows("Not expecting a read from a truncated SegmentChunk to work.", () -> s.read(readHandle, segmentChunk.getLastOffset() - 1, new byte[1], 0, 1), ex -> ex instanceof StreamSegmentTruncatedException);
            }
        }
        // Increment truncateOffset by some value, but let's make sure we also truncate at the very end of the Segment.
        if (truncateOffset >= writtenData.length) {
            break;
        }
        truncateOffset = (int) Math.min(writtenData.length, truncateOffset + DEFAULT_ROLLING_POLICY.getMaxLength() / 2);
    }
    // Do some more writes and verify they are added properly.
    int startOffset = writtenData.length;
    populate(s, writeHandle, writeStream);
    writtenData = writeStream.toByteArray();
    checkWrittenData(writtenData, startOffset, readHandle, s);
    // Verify we cannot concat a truncated segment into another.
    final String targetSegmentName = "TargetSegment";
    s.create(targetSegmentName);
    val targetSegmentHandle = s.openWrite(targetSegmentName);
    s.seal(writeHandle);
    AssertExtensions.assertThrows("concat() allowed using a truncated segment as a source.", () -> s.concat(targetSegmentHandle, 0, SEGMENT_NAME), ex -> ex instanceof IllegalStateException);
}
Also used : lombok.val(lombok.val) ByteArrayOutputStream(java.io.ByteArrayOutputStream) StreamSegmentTruncatedException(io.pravega.segmentstore.contracts.StreamSegmentTruncatedException) Cleanup(lombok.Cleanup) Test(org.junit.Test)

Example 8 with StreamSegmentTruncatedException

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

the class PravegaRequestProcessor method handleReadResult.

/**
 * Handles a readResult.
 * If there are cached entries that can be returned without blocking only these are returned.
 * Otherwise the call will request the data and setup a callback to return the data when it is available.
 * If no data is available but it was detected that the Segment had been truncated beyond the current offset,
 * an appropriate message is sent back over the connection.
 */
private void handleReadResult(ReadSegment request, ReadResult result) {
    String segment = request.getSegment();
    ArrayList<ReadResultEntryContents> cachedEntries = new ArrayList<>();
    ReadResultEntry nonCachedEntry = collectCachedEntries(request.getOffset(), result, cachedEntries);
    boolean truncated = nonCachedEntry != null && nonCachedEntry.getType() == Truncated;
    boolean endOfSegment = nonCachedEntry != null && nonCachedEntry.getType() == EndOfStreamSegment;
    boolean atTail = nonCachedEntry != null && nonCachedEntry.getType() == Future;
    if (!cachedEntries.isEmpty() || endOfSegment) {
        // We managed to collect some data. Send it.
        ByteBuffer data = copyData(cachedEntries);
        SegmentRead reply = new SegmentRead(segment, request.getOffset(), atTail, endOfSegment, data);
        connection.send(reply);
    } else if (truncated) {
        // We didn't collect any data, instead we determined that the current read offset was truncated.
        // Determine the current Start Offset and send that back.
        segmentStore.getStreamSegmentInfo(segment, false, TIMEOUT).thenAccept(info -> connection.send(new SegmentIsTruncated(nonCachedEntry.getStreamSegmentOffset(), segment, info.getStartOffset()))).exceptionally(e -> handleException(nonCachedEntry.getStreamSegmentOffset(), segment, "Read segment", e));
    } else {
        Preconditions.checkState(nonCachedEntry != null, "No ReadResultEntries returned from read!?");
        nonCachedEntry.requestContent(TIMEOUT);
        nonCachedEntry.getContent().thenAccept(contents -> {
            ByteBuffer data = copyData(Collections.singletonList(contents));
            connection.send(new SegmentRead(segment, nonCachedEntry.getStreamSegmentOffset(), false, endOfSegment, data));
        }).exceptionally(e -> {
            if (Exceptions.unwrap(e) instanceof StreamSegmentTruncatedException) {
                // The Segment may have been truncated in Storage after we got this entry but before we managed
                // to make a read. In that case, send the appropriate error back.
                connection.send(new SegmentIsTruncated(nonCachedEntry.getStreamSegmentOffset(), segment, nonCachedEntry.getStreamSegmentOffset()));
            } else {
                handleException(nonCachedEntry.getStreamSegmentOffset(), segment, "Read segment", e);
            }
            return null;
        }).exceptionally(e -> handleException(nonCachedEntry.getStreamSegmentOffset(), segment, "Read segment", e));
    }
}
Also used : SCALE_POLICY_RATE(io.pravega.segmentstore.contracts.Attributes.SCALE_POLICY_RATE) Arrays(java.util.Arrays) READ(io.pravega.auth.AuthHandler.Permissions.READ) StreamSegmentNotExistsException(io.pravega.segmentstore.contracts.StreamSegmentNotExistsException) SEGMENT_CREATE_LATENCY(io.pravega.shared.MetricsNames.SEGMENT_CREATE_LATENCY) AuthHandler(io.pravega.auth.AuthHandler) SegmentIsTruncated(io.pravega.shared.protocol.netty.WireCommands.SegmentIsTruncated) CREATION_TIME(io.pravega.segmentstore.contracts.Attributes.CREATION_TIME) MetricsNames.nameFromSegment(io.pravega.shared.MetricsNames.nameFromSegment) GetStreamSegmentInfo(io.pravega.shared.protocol.netty.WireCommands.GetStreamSegmentInfo) ReadResultEntryContents(io.pravega.segmentstore.contracts.ReadResultEntryContents) Duration(java.time.Duration) Map(java.util.Map) SegmentCreated(io.pravega.shared.protocol.netty.WireCommands.SegmentCreated) StreamSegmentStore(io.pravega.segmentstore.contracts.StreamSegmentStore) Attributes(io.pravega.segmentstore.contracts.Attributes) CancellationException(java.util.concurrent.CancellationException) ContainerNotFoundException(io.pravega.segmentstore.contracts.ContainerNotFoundException) Slf4j(lombok.extern.slf4j.Slf4j) CreateSegment(io.pravega.shared.protocol.netty.WireCommands.CreateSegment) SealSegment(io.pravega.shared.protocol.netty.WireCommands.SealSegment) SegmentSealed(io.pravega.shared.protocol.netty.WireCommands.SegmentSealed) EndOfStreamSegment(io.pravega.segmentstore.contracts.ReadResultEntryType.EndOfStreamSegment) SegmentAttribute(io.pravega.shared.protocol.netty.WireCommands.SegmentAttribute) SEGMENT_READ_LATENCY(io.pravega.shared.MetricsNames.SEGMENT_READ_LATENCY) Exceptions(io.pravega.common.Exceptions) BadAttributeUpdateException(io.pravega.segmentstore.contracts.BadAttributeUpdateException) GetSegmentAttribute(io.pravega.shared.protocol.netty.WireCommands.GetSegmentAttribute) ArrayList(java.util.ArrayList) READ_UPDATE(io.pravega.auth.AuthHandler.Permissions.READ_UPDATE) SegmentRead(io.pravega.shared.protocol.netty.WireCommands.SegmentRead) AccessLevel(lombok.AccessLevel) Future(io.pravega.segmentstore.contracts.ReadResultEntryType.Future) FailingRequestProcessor(io.pravega.shared.protocol.netty.FailingRequestProcessor) StreamHelpers(io.pravega.common.io.StreamHelpers) StreamSegmentTruncatedException(io.pravega.segmentstore.contracts.StreamSegmentTruncatedException) StatsLogger(io.pravega.shared.metrics.StatsLogger) OpStatsLogger(io.pravega.shared.metrics.OpStatsLogger) lombok.val(lombok.val) SEGMENT_WRITE_EVENTS(io.pravega.shared.MetricsNames.SEGMENT_WRITE_EVENTS) IOException(java.io.IOException) WireCommands(io.pravega.shared.protocol.netty.WireCommands) WrongHost(io.pravega.shared.protocol.netty.WireCommands.WrongHost) SegmentDeleted(io.pravega.shared.protocol.netty.WireCommands.SegmentDeleted) CreateTransaction(io.pravega.shared.protocol.netty.WireCommands.CreateTransaction) Truncated(io.pravega.segmentstore.contracts.ReadResultEntryType.Truncated) SegmentTruncated(io.pravega.shared.protocol.netty.WireCommands.SegmentTruncated) RequestProcessor(io.pravega.shared.protocol.netty.RequestProcessor) OperationUnsupported(io.pravega.shared.protocol.netty.WireCommands.OperationUnsupported) Preconditions(com.google.common.base.Preconditions) TransactionInfo(io.pravega.shared.protocol.netty.WireCommands.TransactionInfo) AbortTransaction(io.pravega.shared.protocol.netty.WireCommands.AbortTransaction) AuthenticationException(io.pravega.common.auth.AuthenticationException) Cache(io.pravega.segmentstore.contracts.ReadResultEntryType.Cache) SneakyThrows(lombok.SneakyThrows) ByteBuffer(java.nio.ByteBuffer) AttributeUpdate(io.pravega.segmentstore.contracts.AttributeUpdate) StreamSegmentSealedException(io.pravega.segmentstore.contracts.StreamSegmentSealedException) UpdateSegmentAttribute(io.pravega.shared.protocol.netty.WireCommands.UpdateSegmentAttribute) UpdateSegmentPolicy(io.pravega.shared.protocol.netty.WireCommands.UpdateSegmentPolicy) SegmentStatsRecorder(io.pravega.segmentstore.server.host.stat.SegmentStatsRecorder) CommitTransaction(io.pravega.shared.protocol.netty.WireCommands.CommitTransaction) Collection(java.util.Collection) UUID(java.util.UUID) Math.min(java.lang.Math.min) StreamSegmentNameUtils(io.pravega.shared.segment.StreamSegmentNameUtils) MetricsProvider(io.pravega.shared.metrics.MetricsProvider) List(java.util.List) StreamSegmentExistsException(io.pravega.segmentstore.contracts.StreamSegmentExistsException) PassingTokenVerifier(io.pravega.segmentstore.server.host.delegationtoken.PassingTokenVerifier) BadOffsetException(io.pravega.segmentstore.contracts.BadOffsetException) DelegationTokenVerifier(io.pravega.segmentstore.server.host.delegationtoken.DelegationTokenVerifier) Math.max(java.lang.Math.max) SegmentIsSealed(io.pravega.shared.protocol.netty.WireCommands.SegmentIsSealed) ReadResult(io.pravega.segmentstore.contracts.ReadResult) TransactionAborted(io.pravega.shared.protocol.netty.WireCommands.TransactionAborted) DeleteSegment(io.pravega.shared.protocol.netty.WireCommands.DeleteSegment) SegmentPolicyUpdated(io.pravega.shared.protocol.netty.WireCommands.SegmentPolicyUpdated) Getter(lombok.Getter) NoSuchSegment(io.pravega.shared.protocol.netty.WireCommands.NoSuchSegment) CompletableFuture(java.util.concurrent.CompletableFuture) GetTransactionInfo(io.pravega.shared.protocol.netty.WireCommands.GetTransactionInfo) DynamicLogger(io.pravega.shared.metrics.DynamicLogger) SEGMENT_WRITE_BYTES(io.pravega.shared.MetricsNames.SEGMENT_WRITE_BYTES) ReadResultEntry(io.pravega.segmentstore.contracts.ReadResultEntry) SEGMENT_READ_BYTES(io.pravega.shared.MetricsNames.SEGMENT_READ_BYTES) SCALE_POLICY_TYPE(io.pravega.segmentstore.contracts.Attributes.SCALE_POLICY_TYPE) TransactionCommitted(io.pravega.shared.protocol.netty.WireCommands.TransactionCommitted) TYPE_PLUS_LENGTH_SIZE(io.pravega.shared.protocol.netty.WireCommands.TYPE_PLUS_LENGTH_SIZE) StreamSegmentInfo(io.pravega.shared.protocol.netty.WireCommands.StreamSegmentInfo) TransactionCreated(io.pravega.shared.protocol.netty.WireCommands.TransactionCreated) TruncateSegment(io.pravega.shared.protocol.netty.WireCommands.TruncateSegment) ReadSegment(io.pravega.shared.protocol.netty.WireCommands.ReadSegment) SegmentAlreadyExists(io.pravega.shared.protocol.netty.WireCommands.SegmentAlreadyExists) LoggerHelpers(io.pravega.common.LoggerHelpers) StreamSegmentMergedException(io.pravega.segmentstore.contracts.StreamSegmentMergedException) Timer(io.pravega.common.Timer) SegmentAttributeUpdated(io.pravega.shared.protocol.netty.WireCommands.SegmentAttributeUpdated) VisibleForTesting(com.google.common.annotations.VisibleForTesting) AttributeUpdateType(io.pravega.segmentstore.contracts.AttributeUpdateType) Collections(java.util.Collections) ReadResultEntryContents(io.pravega.segmentstore.contracts.ReadResultEntryContents) SegmentRead(io.pravega.shared.protocol.netty.WireCommands.SegmentRead) SegmentIsTruncated(io.pravega.shared.protocol.netty.WireCommands.SegmentIsTruncated) ReadResultEntry(io.pravega.segmentstore.contracts.ReadResultEntry) ArrayList(java.util.ArrayList) StreamSegmentTruncatedException(io.pravega.segmentstore.contracts.StreamSegmentTruncatedException) ByteBuffer(java.nio.ByteBuffer)

Aggregations

StreamSegmentTruncatedException (io.pravega.segmentstore.contracts.StreamSegmentTruncatedException)8 ReadResult (io.pravega.segmentstore.contracts.ReadResult)5 Cleanup (lombok.Cleanup)5 lombok.val (lombok.val)5 ReadResultEntry (io.pravega.segmentstore.contracts.ReadResultEntry)4 StreamSegmentNotExistsException (io.pravega.segmentstore.contracts.StreamSegmentNotExistsException)4 ByteArrayOutputStream (java.io.ByteArrayOutputStream)4 ReadResultEntryContents (io.pravega.segmentstore.contracts.ReadResultEntryContents)3 Map (java.util.Map)3 IOException (java.io.IOException)2 Test (org.junit.Test)2 VisibleForTesting (com.google.common.annotations.VisibleForTesting)1 Preconditions (com.google.common.base.Preconditions)1 AuthHandler (io.pravega.auth.AuthHandler)1 READ (io.pravega.auth.AuthHandler.Permissions.READ)1 READ_UPDATE (io.pravega.auth.AuthHandler.Permissions.READ_UPDATE)1 Exceptions (io.pravega.common.Exceptions)1 LoggerHelpers (io.pravega.common.LoggerHelpers)1 Timer (io.pravega.common.Timer)1 AuthenticationException (io.pravega.common.auth.AuthenticationException)1