Search in sources :

Example 11 with UpdateableSegmentMetadata

use of io.pravega.segmentstore.server.UpdateableSegmentMetadata in project pravega by pravega.

the class StorageWriter method getSegmentAggregator.

// endregion
// region Helpers
/**
 * Gets, or creates, a SegmentAggregator for the given StorageOperation.
 *
 * @param streamSegmentId The Id of the StreamSegment to get the aggregator for.
 */
private CompletableFuture<SegmentAggregator> getSegmentAggregator(long streamSegmentId) {
    SegmentAggregator existingAggregator = this.aggregators.getOrDefault(streamSegmentId, null);
    if (existingAggregator != null) {
        if (closeIfNecessary(existingAggregator).isClosed()) {
            // Existing SegmentAggregator has become stale (most likely due to its SegmentMetadata being evicted),
            // so it has been closed and we need to create a new one.
            this.aggregators.remove(streamSegmentId);
        } else {
            return CompletableFuture.completedFuture(existingAggregator);
        }
    }
    // Get the SegmentAggregator's Metadata.
    UpdateableSegmentMetadata segmentMetadata = this.dataSource.getStreamSegmentMetadata(streamSegmentId);
    if (segmentMetadata == null) {
        return Futures.failedFuture(new DataCorruptionException(String.format("No StreamSegment with id '%d' is registered in the metadata.", streamSegmentId)));
    }
    // Then create the aggregator, and only register it after a successful initialization. Otherwise we risk
    // having a registered aggregator that is not initialized.
    SegmentAggregator newAggregator = new SegmentAggregator(segmentMetadata, this.dataSource, this.storage, this.config, this.timer, this.executor);
    try {
        CompletableFuture<Void> init = newAggregator.initialize(this.config.getFlushTimeout());
        Futures.exceptionListener(init, ex -> newAggregator.close());
        return init.thenApply(ignored -> {
            this.aggregators.put(streamSegmentId, newAggregator);
            return newAggregator;
        });
    } catch (Exception ex) {
        newAggregator.close();
        throw ex;
    }
}
Also used : UpdateableSegmentMetadata(io.pravega.segmentstore.server.UpdateableSegmentMetadata) DataCorruptionException(io.pravega.segmentstore.server.DataCorruptionException) ObjectClosedException(io.pravega.common.ObjectClosedException) TimeoutException(java.util.concurrent.TimeoutException) CancellationException(java.util.concurrent.CancellationException) CompletionException(java.util.concurrent.CompletionException) DataCorruptionException(io.pravega.segmentstore.server.DataCorruptionException)

Example 12 with UpdateableSegmentMetadata

use of io.pravega.segmentstore.server.UpdateableSegmentMetadata in project pravega by pravega.

the class ContainerMetadataUpdateTransaction method createSegmentMetadata.

/**
 * Creates a new UpdateableSegmentMetadata for the given Segment and registers it.
 */
private UpdateableSegmentMetadata createSegmentMetadata(String segmentName, long segmentId, long parentId) {
    UpdateableSegmentMetadata metadata;
    if (parentId == ContainerMetadata.NO_STREAM_SEGMENT_ID) {
        metadata = new StreamSegmentMetadata(segmentName, segmentId, this.containerId);
    } else {
        metadata = new StreamSegmentMetadata(segmentName, segmentId, parentId, this.containerId);
    }
    this.newSegments.put(metadata.getId(), metadata);
    this.newSegmentNames.put(metadata.getName(), metadata.getId());
    return metadata;
}
Also used : UpdateableSegmentMetadata(io.pravega.segmentstore.server.UpdateableSegmentMetadata) StreamSegmentMetadata(io.pravega.segmentstore.server.containers.StreamSegmentMetadata)

Example 13 with UpdateableSegmentMetadata

use of io.pravega.segmentstore.server.UpdateableSegmentMetadata in project pravega by pravega.

the class ContainerMetadataUpdateTransaction method getOrCreateSegmentUpdateTransaction.

/**
 * Gets an UpdateableSegmentMetadata for the given Segment. If already registered, it returns that instance,
 * otherwise it creates and records a new Segment metadata.
 */
private SegmentMetadataUpdateTransaction getOrCreateSegmentUpdateTransaction(String segmentName, long segmentId, long parentId) {
    SegmentMetadataUpdateTransaction sm = tryGetSegmentUpdateTransaction(segmentId);
    if (sm == null) {
        SegmentMetadata baseSegmentMetadata = createSegmentMetadata(segmentName, segmentId, parentId);
        sm = new SegmentMetadataUpdateTransaction(baseSegmentMetadata, this.recoveryMode);
        this.segmentUpdates.put(segmentId, sm);
    }
    return sm;
}
Also used : UpdateableSegmentMetadata(io.pravega.segmentstore.server.UpdateableSegmentMetadata) SegmentMetadata(io.pravega.segmentstore.server.SegmentMetadata) StreamSegmentMetadata(io.pravega.segmentstore.server.containers.StreamSegmentMetadata)

Example 14 with UpdateableSegmentMetadata

use of io.pravega.segmentstore.server.UpdateableSegmentMetadata in project pravega by pravega.

the class ContainerMetadataUpdateTransaction method commit.

/**
 * Commits all pending changes to the given target Container Metadata.
 * @param target The UpdateableContainerMetadata to commit to.
 */
void commit(UpdateableContainerMetadata target) {
    Preconditions.checkArgument(target.getContainerId() == this.containerId, "ContainerId mismatch");
    Preconditions.checkArgument(target.isRecoveryMode() == this.isRecoveryMode(), "isRecoveryMode mismatch");
    if (target.isRecoveryMode()) {
        if (this.processedCheckpoint) {
            // If we processed a checkpoint during recovery, we need to wipe the metadata clean. We are setting
            // a brand new one.
            target.reset();
        }
        // we have in our UpdateTransaction. If we have nothing, we'll just set it to the default.
        assert this.newSequenceNumber >= ContainerMetadata.INITIAL_OPERATION_SEQUENCE_NUMBER : "Invalid Sequence Number " + this.newSequenceNumber;
        target.setOperationSequenceNumber(this.newSequenceNumber);
    }
    // Commit all segment-related transactional changes to their respective sources.
    this.segmentUpdates.values().forEach(txn -> {
        UpdateableSegmentMetadata targetSegmentMetadata = target.getStreamSegmentMetadata(txn.getId());
        if (targetSegmentMetadata == null) {
            targetSegmentMetadata = this.newSegments.get(txn.getId());
        }
        txn.apply(targetSegmentMetadata);
    });
    // We must first copy the Standalone Segments, and then the Transaction Segments. That's because
    // the Transaction Segments may refer to one of these newly created Segments, and the metadata
    // will reject the operation if it can't find the parent.
    // We need this because HashMap does not necessarily preserve order when iterating via values().
    copySegmentMetadata(this.newSegments.values(), s -> !s.isTransaction(), target);
    copySegmentMetadata(this.newSegments.values(), SegmentMetadata::isTransaction, target);
    // Copy truncation points.
    this.newTruncationPoints.forEach(target::setValidTruncationPoint);
    // We are done. Clear the transaction.
    clear();
}
Also used : UpdateableSegmentMetadata(io.pravega.segmentstore.server.UpdateableSegmentMetadata) SegmentMetadata(io.pravega.segmentstore.server.SegmentMetadata) StreamSegmentMetadata(io.pravega.segmentstore.server.containers.StreamSegmentMetadata) UpdateableSegmentMetadata(io.pravega.segmentstore.server.UpdateableSegmentMetadata)

Example 15 with UpdateableSegmentMetadata

use of io.pravega.segmentstore.server.UpdateableSegmentMetadata in project pravega by pravega.

the class DurableLogTests method testTailReads.

/**
 * Tests the ability to block reads if the read is at the tail and no more data is available (for now).
 */
@Test
public void testTailReads() throws Exception {
    final int operationCount = 10;
    final long segmentId = 1;
    final String segmentName = Long.toString(segmentId);
    // Setup a DurableLog and start it.
    @Cleanup ContainerSetup setup = new ContainerSetup(executorService());
    @Cleanup DurableLog durableLog = setup.createDurableLog();
    durableLog.startAsync().awaitRunning();
    // Create a segment, which will be used for testing later.
    UpdateableSegmentMetadata segmentMetadata = setup.metadata.mapStreamSegmentId(segmentName, segmentId);
    segmentMetadata.setLength(0);
    segmentMetadata.setStorageLength(0);
    // Setup a bunch of read operations, and make sure they are blocked (since there is no data).
    ArrayList<CompletableFuture<Iterator<Operation>>> readFutures = new ArrayList<>();
    for (int i = 0; i < operationCount; i++) {
        long afterSeqNo = i + 1;
        CompletableFuture<Iterator<Operation>> readFuture = durableLog.read(afterSeqNo, operationCount, TIMEOUT);
        Assert.assertFalse("read() returned a completed future when there is no data available (afterSeqNo = " + afterSeqNo + ").", readFuture.isDone());
        readFutures.add(readFuture);
    }
    // Add one operation at at time, and each time, verify that the correct Read got activated.
    OperationComparer operationComparer = new OperationComparer(true);
    for (int appendId = 0; appendId < operationCount; appendId++) {
        Operation operation = new StreamSegmentAppendOperation(segmentId, ("foo" + Integer.toString(appendId)).getBytes(), null);
        durableLog.add(operation, TIMEOUT).join();
        for (int readId = 0; readId < readFutures.size(); readId++) {
            val readFuture = readFutures.get(readId);
            boolean expectedComplete = readId <= appendId;
            if (expectedComplete) {
                // The internal callback happens asynchronously, so wait for this future to complete in a bit.
                readFuture.get(TIMEOUT.toMillis(), TimeUnit.MILLISECONDS);
            }
            Assert.assertEquals(String.format("Unexpected read completion status for read after seqNo %d after adding op with seqNo %d", readId + 1, operation.getSequenceNumber()), expectedComplete, readFutures.get(readId).isDone());
            if (appendId == readId) {
                // Verify that the read result matches the operation.
                Iterator<Operation> readResult = readFuture.join();
                // Verify that we actually have a non-empty read result.
                Assert.assertTrue(String.format("Empty read result read after seqNo %d after adding op with seqNo %d", readId + 1, operation.getSequenceNumber()), readResult.hasNext());
                // Verify the read result.
                Operation readOp = readResult.next();
                operationComparer.assertEquals(String.format("Unexpected result operation for read after seqNo %d after adding op with seqNo %d", readId + 1, operation.getSequenceNumber()), operation, readOp);
                // Verify that we don't have more than one read result.
                Assert.assertFalse(String.format("Not expecting more than one result for read after seqNo %d after adding op with seqNo %d", readId + 1, operation.getSequenceNumber()), readResult.hasNext());
            }
        }
    }
    // Verify that such reads are cancelled when the DurableLog is closed.
    CompletableFuture<Iterator<Operation>> readFuture = durableLog.read(operationCount + 2, operationCount, TIMEOUT);
    Assert.assertFalse("read() returned a completed future when there is no data available (afterSeqNo = MAX).", readFuture.isDone());
    durableLog.stopAsync().awaitTerminated();
    Assert.assertTrue("A tail read was not cancelled when the DurableLog was stopped.", readFuture.isCompletedExceptionally());
}
Also used : lombok.val(lombok.val) UpdateableSegmentMetadata(io.pravega.segmentstore.server.UpdateableSegmentMetadata) ArrayList(java.util.ArrayList) OperationComparer(io.pravega.segmentstore.server.logs.operations.OperationComparer) StorageMetadataCheckpointOperation(io.pravega.segmentstore.server.logs.operations.StorageMetadataCheckpointOperation) ProbeOperation(io.pravega.segmentstore.server.logs.operations.ProbeOperation) Operation(io.pravega.segmentstore.server.logs.operations.Operation) StreamSegmentMapOperation(io.pravega.segmentstore.server.logs.operations.StreamSegmentMapOperation) MetadataCheckpointOperation(io.pravega.segmentstore.server.logs.operations.MetadataCheckpointOperation) StorageOperation(io.pravega.segmentstore.server.logs.operations.StorageOperation) StreamSegmentAppendOperation(io.pravega.segmentstore.server.logs.operations.StreamSegmentAppendOperation) StreamSegmentAppendOperation(io.pravega.segmentstore.server.logs.operations.StreamSegmentAppendOperation) Cleanup(lombok.Cleanup) CompletableFuture(java.util.concurrent.CompletableFuture) Iterator(java.util.Iterator) Test(org.junit.Test)

Aggregations

UpdateableSegmentMetadata (io.pravega.segmentstore.server.UpdateableSegmentMetadata)52 Test (org.junit.Test)20 Cleanup (lombok.Cleanup)15 lombok.val (lombok.val)15 AtomicLong (java.util.concurrent.atomic.AtomicLong)12 SegmentMetadata (io.pravega.segmentstore.server.SegmentMetadata)11 ArrayList (java.util.ArrayList)11 ReadResult (io.pravega.segmentstore.contracts.ReadResult)8 HashMap (java.util.HashMap)8 HashSet (java.util.HashSet)8 ReadResultEntry (io.pravega.segmentstore.contracts.ReadResultEntry)7 UpdateableContainerMetadata (io.pravega.segmentstore.server.UpdateableContainerMetadata)7 AtomicInteger (java.util.concurrent.atomic.AtomicInteger)7 MetadataBuilder (io.pravega.segmentstore.server.MetadataBuilder)6 MergeTransactionOperation (io.pravega.segmentstore.server.logs.operations.MergeTransactionOperation)6 StreamSegmentAppendOperation (io.pravega.segmentstore.server.logs.operations.StreamSegmentAppendOperation)6 ByteArrayInputStream (java.io.ByteArrayInputStream)6 ByteArrayOutputStream (java.io.ByteArrayOutputStream)6 CachedStreamSegmentAppendOperation (io.pravega.segmentstore.server.logs.operations.CachedStreamSegmentAppendOperation)5 StorageOperation (io.pravega.segmentstore.server.logs.operations.StorageOperation)5