Search in sources :

Example 46 with StreamSegmentNotExistsException

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

the class RollingStorage method concat.

@Override
public void concat(SegmentHandle targetHandle, long targetOffset, String sourceSegment) throws StreamSegmentException {
    val target = asWritableHandle(targetHandle);
    ensureOffset(target, targetOffset);
    ensureNotDeleted(target);
    ensureNotSealed(target);
    long traceId = LoggerHelpers.traceEnter(log, "concat", target, targetOffset, sourceSegment);
    // We can only use a Segment as a concat source if it is Sealed.
    RollingSegmentHandle source = (RollingSegmentHandle) openWrite(sourceSegment);
    Preconditions.checkState(source.isSealed(), "Cannot concat segment '%s' into '%s' because it is not sealed.", sourceSegment, target.getSegmentName());
    if (source.length() == 0) {
        // Source is empty; do not bother with concatenation.
        log.debug("Concat source '{}' is empty. Deleting instead of concatenating.", source);
        delete(source);
        return;
    }
    // We can only use a Segment as a concat source if all of its SegmentChunks exist.
    refreshChunkExistence(source);
    Preconditions.checkState(source.chunks().stream().allMatch(SegmentChunk::exists), "Cannot use Segment '%s' as concat source because it is truncated.", source.getSegmentName());
    if (shouldConcatNatively(source, target)) {
        // The Source either does not have a Header or is made up of a single SegmentChunk that can fit entirely into
        // the Target's Active SegmentChunk. Concat it directly without touching the header file; this helps prevent
        // having a lot of very small SegmentChunks around if the application has a lot of small transactions.
        log.debug("Concat '{}' into '{}' using native method.", source, target);
        SegmentChunk lastTarget = target.lastChunk();
        if (lastTarget == null || lastTarget.isSealed()) {
            // Make sure the last SegmentChunk of the target is not sealed, otherwise we can't concat into it.
            rollover(target);
        }
        SegmentChunk lastSource = source.lastChunk();
        this.baseStorage.concat(target.getActiveChunkHandle(), target.lastChunk().getLength(), lastSource.getName());
        target.lastChunk().increaseLength(lastSource.getLength());
        if (source.getHeaderHandle() != null) {
            try {
                this.baseStorage.delete(source.getHeaderHandle());
            } catch (StreamSegmentNotExistsException ex) {
                // It's ok if it's not there anymore.
                log.warn("Attempted to delete concat source Header '{}' but it doesn't exist.", source.getHeaderHandle().getSegmentName(), ex);
            }
        }
    } else {
        // Generate new SegmentChunk entries from the SegmentChunks of the Source Segment(but update their start offsets).
        log.debug("Concat '{}' into '{}' using header merge method.", source, target);
        if (target.getHeaderHandle() == null) {
            // We need to concat into a Segment that does not have a Header (yet). Create one before continuing.
            createHeader(target);
        }
        List<SegmentChunk> newSegmentChunks = rebase(source.chunks(), target.length());
        sealActiveChunk(target);
        serializeBeginConcat(target, source);
        this.baseStorage.concat(target.getHeaderHandle(), target.getHeaderLength(), source.getHeaderHandle().getSegmentName());
        target.increaseHeaderLength(source.getHeaderLength());
        target.addChunks(newSegmentChunks);
        // After we do a header merge, it's possible that the (new) last chunk may still have space to write to.
        // Unseal it now so that future writes/concats will not unnecessarily create chunks. Note that this will not
        // unseal the segment (even though it's unsealed) - that is determined by the Header file seal status.
        unsealLastChunkIfNecessary(target);
    }
    LoggerHelpers.traceLeave(log, "concat", traceId, target, targetOffset, sourceSegment);
}
Also used : lombok.val(lombok.val) StreamSegmentNotExistsException(io.pravega.segmentstore.contracts.StreamSegmentNotExistsException)

Example 47 with StreamSegmentNotExistsException

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

the class RollingStorage method openHandle.

private RollingSegmentHandle openHandle(String segmentName, boolean readOnly) throws StreamSegmentException {
    // Load up the handle from Storage.
    RollingSegmentHandle handle;
    try {
        // Attempt to open using Header.
        val headerInfo = getHeaderInfo(segmentName);
        val headerHandle = readOnly ? this.baseStorage.openRead(headerInfo.getName()) : this.baseStorage.openWrite(headerInfo.getName());
        handle = readHeader(headerInfo, headerHandle);
    } catch (StreamSegmentNotExistsException ex) {
        // Header does not exist. Attempt to open Segment directly.
        val segmentHandle = readOnly ? this.baseStorage.openRead(segmentName) : this.baseStorage.openWrite(segmentName);
        handle = new RollingSegmentHandle(segmentHandle);
    }
    // Update each SegmentChunk's Length (based on offset difference) and mark them as Sealed.
    SegmentChunk last = null;
    for (SegmentChunk s : handle.chunks()) {
        if (last != null) {
            last.setLength(s.getStartOffset() - last.getStartOffset());
            last.markSealed();
        }
        last = s;
    }
    // For the last one, we need to actually check the file and update its info.
    if (last != null) {
        val si = this.baseStorage.getStreamSegmentInfo(last.getName());
        last.setLength(si.getLength());
        if (si.isSealed()) {
            last.markSealed();
            if (handle.getHeaderHandle() == null) {
                handle.markSealed();
            }
        }
    }
    return handle;
}
Also used : lombok.val(lombok.val) StreamSegmentNotExistsException(io.pravega.segmentstore.contracts.StreamSegmentNotExistsException)

Example 48 with StreamSegmentNotExistsException

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

the class RollingStorage method deleteChunks.

private void deleteChunks(RollingSegmentHandle handle, Predicate<SegmentChunk> canDelete) throws StreamSegmentException {
    for (SegmentChunk s : handle.chunks()) {
        if (s.exists() && canDelete.test(s)) {
            try {
                val subHandle = this.baseStorage.openWrite(s.getName());
                this.baseStorage.delete(subHandle);
                s.markInexistent();
                log.debug("Deleted SegmentChunk '{}' for '{}'.", s, handle);
            } catch (StreamSegmentNotExistsException ex) {
                // Ignore; It's OK if it doesn't exist; just make sure the handle is updated.
                s.markInexistent();
            }
        }
    }
}
Also used : lombok.val(lombok.val) StreamSegmentNotExistsException(io.pravega.segmentstore.contracts.StreamSegmentNotExistsException)

Example 49 with StreamSegmentNotExistsException

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

the class StorageTestBase method testWrite.

/**
 * Tests the write() method.
 *
 * @throws Exception if an unexpected error occurred.
 */
@Test
public void testWrite() throws Exception {
    String segmentName = "foo_write";
    int appendCount = 100;
    try (Storage s = createStorage()) {
        s.initialize(DEFAULT_EPOCH);
        createSegment(segmentName, s);
        // Invalid handle.
        val readOnlyHandle = s.openRead(segmentName).join();
        assertThrows("write() did not throw for read-only handle.", () -> s.write(readOnlyHandle, 0, new ByteArrayInputStream("h".getBytes()), 1, TIMEOUT), ex -> ex instanceof IllegalArgumentException);
        assertThrows("write() did not throw for handle pointing to inexistent segment.", () -> s.write(createInexistentSegmentHandle(s, false), 0, new ByteArrayInputStream("h".getBytes()), 1, TIMEOUT), ex -> ex instanceof StreamSegmentNotExistsException);
        val writeHandle = s.openWrite(segmentName).join();
        long offset = 0;
        for (int j = 0; j < appendCount; j++) {
            byte[] writeData = String.format(APPEND_FORMAT, segmentName, j).getBytes();
            // We intentionally add some garbage at the end of the dataStream to verify that write() takes into account
            // the value of the "length" argument.
            val dataStream = new SequenceInputStream(new ByteArrayInputStream(writeData), new ByteArrayInputStream(new byte[100]));
            s.write(writeHandle, offset, dataStream, writeData.length, TIMEOUT).join();
            offset += writeData.length;
        }
        // Check bad offset.
        final long finalOffset = offset;
        assertThrows("write() did not throw bad offset write (smaller).", () -> s.write(writeHandle, finalOffset - 1, new ByteArrayInputStream("h".getBytes()), 1, TIMEOUT), ex -> ex instanceof BadOffsetException);
        assertThrows("write() did not throw bad offset write (larger).", () -> s.write(writeHandle, finalOffset + 1, new ByteArrayInputStream("h".getBytes()), 1, TIMEOUT), ex -> ex instanceof BadOffsetException);
        // Check post-delete write.
        s.delete(writeHandle, TIMEOUT).join();
        assertThrows("write() did not throw for a deleted StreamSegment.", () -> s.write(writeHandle, 0, new ByteArrayInputStream(new byte[1]), 1, TIMEOUT), ex -> ex instanceof StreamSegmentNotExistsException);
    }
}
Also used : lombok.val(lombok.val) SequenceInputStream(java.io.SequenceInputStream) ByteArrayInputStream(java.io.ByteArrayInputStream) BadOffsetException(io.pravega.segmentstore.contracts.BadOffsetException) StreamSegmentNotExistsException(io.pravega.segmentstore.contracts.StreamSegmentNotExistsException) Test(org.junit.Test)

Example 50 with StreamSegmentNotExistsException

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

the class RollingStorageTests method testCreateRecovery.

/**
 * Tests the case when Create was interrupted after it created the Header file but before populating it.
 */
@Test
public void testCreateRecovery() throws Exception {
    @Cleanup val baseStorage = new TestStorage();
    @Cleanup val s = new RollingStorage(baseStorage, DEFAULT_ROLLING_POLICY);
    s.initialize(1);
    // Create an empty header file. This simulates a create() operation that failed mid-way.
    baseStorage.create(StreamSegmentNameUtils.getHeaderSegmentName(SEGMENT_NAME));
    Assert.assertFalse("Not expecting Segment to exist.", s.exists(SEGMENT_NAME));
    AssertExtensions.assertThrows("Not expecting Segment to exist (getStreamSegmentInfo).", () -> s.getStreamSegmentInfo(SEGMENT_NAME), ex -> ex instanceof StreamSegmentNotExistsException);
    AssertExtensions.assertThrows("Not expecting Segment to exist (openHandle).", () -> s.openRead(SEGMENT_NAME), ex -> ex instanceof StreamSegmentNotExistsException);
    // Retry the operation and verify everything is in place.
    s.create(SEGMENT_NAME);
    val si = s.getStreamSegmentInfo(SEGMENT_NAME);
    Assert.assertEquals("Expected the Segment to have been created.", 0, si.getLength());
}
Also used : lombok.val(lombok.val) Cleanup(lombok.Cleanup) StreamSegmentNotExistsException(io.pravega.segmentstore.contracts.StreamSegmentNotExistsException) Test(org.junit.Test)

Aggregations

StreamSegmentNotExistsException (io.pravega.segmentstore.contracts.StreamSegmentNotExistsException)51 lombok.val (lombok.val)27 Test (org.junit.Test)22 Cleanup (lombok.Cleanup)15 SegmentProperties (io.pravega.segmentstore.contracts.SegmentProperties)12 Storage (io.pravega.segmentstore.storage.Storage)11 SegmentMetadata (io.pravega.segmentstore.server.SegmentMetadata)10 StreamSegmentSealedException (io.pravega.segmentstore.contracts.StreamSegmentSealedException)9 ByteArrayInputStream (java.io.ByteArrayInputStream)9 Duration (java.time.Duration)8 ArrayList (java.util.ArrayList)8 CompletionException (java.util.concurrent.CompletionException)8 BadOffsetException (io.pravega.segmentstore.contracts.BadOffsetException)7 ReadResult (io.pravega.segmentstore.contracts.ReadResult)7 StreamSegmentAppendOperation (io.pravega.segmentstore.server.logs.operations.StreamSegmentAppendOperation)7 UUID (java.util.UUID)7 AtomicLong (java.util.concurrent.atomic.AtomicLong)7 Futures (io.pravega.common.concurrent.Futures)6 MergeTransactionOperation (io.pravega.segmentstore.server.logs.operations.MergeTransactionOperation)6 ByteArrayOutputStream (java.io.ByteArrayOutputStream)6