Search in sources :

Example 11 with StreamSegmentMergedException

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

the class ContainerMetadataUpdateTransactionTests method testPreProcessMergeSegment.

// endregion
// region MergeSegmentOperation
/**
 * Tests the preProcess method with MergeTransactionOperations.
 * Scenarios:
 * * Recovery/non-recovery mode
 * * Target StreamSegment is sealed
 * * Target StreamSegment is a Transaction
 * * Source StreamSegment is already merged
 * * Source StreamSegment is not sealed
 */
@Test
public void testPreProcessMergeSegment() throws Exception {
    UpdateableContainerMetadata metadata = createMetadata();
    // When everything is OK (recovery mode).
    MergeSegmentOperation recoveryMergeOp = createMerge();
    metadata.enterRecoveryMode();
    val txn1 = createUpdateTransaction(metadata);
    AssertExtensions.assertThrows("preProcess(Merge) handled an operation with no Transaction StreamSegment Length set.", () -> txn1.preProcessOperation(createMerge()), ex -> ex instanceof MetadataUpdateException);
    // In recovery mode, the updater does not set the length; it just validates that it has one.
    recoveryMergeOp.setLength(metadata.getStreamSegmentMetadata(SEALED_SOURCE_ID).getLength());
    txn1.preProcessOperation(recoveryMergeOp);
    AssertExtensions.assertLessThan("Unexpected Target StreamSegmentOffset after call to preProcess in recovery mode.", 0, recoveryMergeOp.getStreamSegmentOffset());
    checkNoSequenceNumberAssigned(recoveryMergeOp, "call to preProcess in recovery mode");
    Assert.assertFalse("preProcess(Merge) seems to have changed the Updater internal state in recovery mode.", txn1.getStreamSegmentMetadata(SEALED_SOURCE_ID).isMerged());
    Assert.assertFalse("preProcess(Merge) seems to have changed the metadata in recovery mode.", metadata.getStreamSegmentMetadata(SEALED_SOURCE_ID).isMerged());
    // When everything is OK (non-recovery mode).
    MergeSegmentOperation mergeOp = createMerge();
    metadata.exitRecoveryMode();
    val txn2 = createUpdateTransaction(metadata);
    txn2.preProcessOperation(mergeOp);
    Assert.assertEquals("Unexpected Transaction StreamSegmentLength after call to preProcess in non-recovery mode.", SEALED_SOURCE_LENGTH, mergeOp.getLength());
    Assert.assertEquals("Unexpected Target StreamSegmentOffset after call to preProcess in non-recovery mode.", SEGMENT_LENGTH, mergeOp.getStreamSegmentOffset());
    checkNoSequenceNumberAssigned(mergeOp, "call to preProcess in non-recovery mode");
    Assert.assertFalse("preProcess(Merge) seems to have changed the Updater internal state in non-recovery mode.", txn2.getStreamSegmentMetadata(SEALED_SOURCE_ID).isMerged());
    Assert.assertFalse("preProcess(Merge) seems to have changed the metadata in non-recovery mode.", metadata.getStreamSegmentMetadata(SEALED_SOURCE_ID).isMerged());
    // When Target StreamSegment is sealed.
    StreamSegmentSealOperation sealTargetOp = createSeal();
    txn2.preProcessOperation(sealTargetOp);
    txn2.acceptOperation(sealTargetOp);
    AssertExtensions.assertThrows("Unexpected behavior for preProcess(Merge) when Target StreamSegment is sealed.", () -> txn2.preProcessOperation(createMerge()), ex -> ex instanceof StreamSegmentSealedException);
    // Rollback the seal
    txn2.clear();
    // When Transaction is not sealed.
    MergeSegmentOperation mergeNonSealed = new MergeSegmentOperation(NOTSEALED_SOURCE_ID, SEGMENT_ID);
    AssertExtensions.assertThrows("Unexpected behavior for preProcess(Merge) when Transaction StreamSegment is not sealed.", () -> txn2.preProcessOperation(mergeNonSealed), ex -> ex instanceof StreamSegmentNotSealedException);
    // When Transaction is already merged.
    txn2.preProcessOperation(mergeOp);
    txn2.acceptOperation(mergeOp);
    AssertExtensions.assertThrows("Unexpected behavior for preProcess(Merge) when Transaction StreamSegment is already merged (in transaction).", () -> txn2.preProcessOperation(createMerge()), ex -> ex instanceof StreamSegmentMergedException);
    txn2.commit(metadata);
    AssertExtensions.assertThrows("Unexpected behavior for preProcess(Merge) when Transaction StreamSegment is already merged (in metadata).", () -> txn2.preProcessOperation(createMerge()), ex -> ex instanceof StreamSegmentMergedException);
}
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) StreamSegmentNotSealedException(io.pravega.segmentstore.contracts.StreamSegmentNotSealedException) MergeSegmentOperation(io.pravega.segmentstore.server.logs.operations.MergeSegmentOperation) Test(org.junit.Test)

Example 12 with StreamSegmentMergedException

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

the class StreamSegmentContainerTests method testConditionalTransactionOperations.

/**
 * Test the createTransaction, append-to-Transaction, mergeTransaction methods with attribute updates.
 */
@Test
public void testConditionalTransactionOperations() throws Exception {
    @Cleanup TestContext context = createContext();
    context.container.startAsync().awaitRunning();
    // 1. Create the StreamSegments.
    ArrayList<String> segmentNames = createSegments(context);
    HashMap<String, ArrayList<String>> transactionsBySegment = createTransactions(segmentNames, context);
    activateAllSegments(segmentNames, context);
    transactionsBySegment.values().forEach(s -> activateAllSegments(s, context));
    // 2. Add some appends.
    HashMap<String, Long> lengths = new HashMap<>();
    HashMap<String, ByteArrayOutputStream> segmentContents = new HashMap<>();
    appendToParentsAndTransactions(segmentNames, transactionsBySegment, lengths, segmentContents, context);
    // 3. Correctly update attribute on parent Segments. Each source Segment will be initialized with a value and
    // after the merge, that value should have been updated.
    ArrayList<CompletableFuture<Void>> opFutures = new ArrayList<>();
    for (Map.Entry<String, ArrayList<String>> e : transactionsBySegment.entrySet()) {
        String parentName = e.getKey();
        for (String transactionName : e.getValue()) {
            opFutures.add(context.container.updateAttributes(parentName, AttributeUpdateCollection.from(new AttributeUpdate(AttributeId.fromUUID(UUID.nameUUIDFromBytes(transactionName.getBytes())), AttributeUpdateType.None, transactionName.hashCode())), TIMEOUT));
        }
    }
    Futures.allOf(opFutures).get(TIMEOUT.toMillis(), TimeUnit.MILLISECONDS);
    // 4. Merge all the Transactions. Now this should work.
    Futures.allOf(mergeTransactions(transactionsBySegment, lengths, segmentContents, context, true)).get(TIMEOUT.toMillis(), TimeUnit.MILLISECONDS);
    // 5. Add more appends (to the parent segments)
    ArrayList<CompletableFuture<Long>> appendFutures = new ArrayList<>();
    HashMap<String, CompletableFuture<Map<AttributeId, Long>>> getAttributeFutures = new HashMap<>();
    for (int i = 0; i < 5; i++) {
        for (String segmentName : segmentNames) {
            RefCountByteArraySegment appendData = getAppendData(segmentName, APPENDS_PER_SEGMENT + i);
            appendFutures.add(context.container.append(segmentName, appendData, null, TIMEOUT));
            lengths.put(segmentName, lengths.getOrDefault(segmentName, 0L) + appendData.getLength());
            recordAppend(segmentName, appendData, segmentContents, null);
            // Verify that we can no longer append to Transaction.
            for (String transactionName : transactionsBySegment.get(segmentName)) {
                AssertExtensions.assertThrows("An append was allowed to a merged Transaction " + transactionName, context.container.append(transactionName, new ByteArraySegment("foo".getBytes()), null, TIMEOUT)::join, ex -> ex instanceof StreamSegmentMergedException || ex instanceof StreamSegmentNotExistsException);
                getAttributeFutures.put(transactionName, context.container.getAttributes(segmentName, Collections.singletonList(AttributeId.fromUUID(UUID.nameUUIDFromBytes(transactionName.getBytes()))), true, TIMEOUT));
            }
        }
    }
    Futures.allOf(appendFutures).get(TIMEOUT.toMillis(), TimeUnit.MILLISECONDS);
    Futures.allOf(getAttributeFutures.values()).get(TIMEOUT.toMillis(), TimeUnit.MILLISECONDS);
    // 6. Verify their contents.
    checkReadIndex(segmentContents, lengths, context);
    // 7. Writer moving data to Storage.
    waitForSegmentsInStorage(segmentNames, context).get(TIMEOUT.toMillis(), TimeUnit.MILLISECONDS);
    checkStorage(segmentContents, lengths, context);
    // 8. Verify that the parent Segment contains the expected attributes updated.
    for (Map.Entry<String, CompletableFuture<Map<AttributeId, Long>>> transactionAndAttribute : getAttributeFutures.entrySet()) {
        Map<AttributeId, Long> segmentAttributeUpdated = transactionAndAttribute.getValue().join();
        AttributeId transactionAttributeId = AttributeId.fromUUID(UUID.nameUUIDFromBytes(transactionAndAttribute.getKey().getBytes()));
        // Conditional merges in mergeTransactions() update the attribute value to adding 1.
        Assert.assertEquals(transactionAndAttribute.getKey().hashCode() + 1, segmentAttributeUpdated.get(transactionAttributeId).longValue());
    }
    context.container.stopAsync().awaitTerminated();
}
Also used : AttributeUpdate(io.pravega.segmentstore.contracts.AttributeUpdate) DynamicAttributeUpdate(io.pravega.segmentstore.contracts.DynamicAttributeUpdate) ByteArraySegment(io.pravega.common.util.ByteArraySegment) ConcurrentHashMap(java.util.concurrent.ConcurrentHashMap) HashMap(java.util.HashMap) AttributeId(io.pravega.segmentstore.contracts.AttributeId) ArrayList(java.util.ArrayList) Cleanup(lombok.Cleanup) CompletableFuture(java.util.concurrent.CompletableFuture) StreamSegmentMergedException(io.pravega.segmentstore.contracts.StreamSegmentMergedException) ByteArrayOutputStream(java.io.ByteArrayOutputStream) StreamSegmentNotExistsException(io.pravega.segmentstore.contracts.StreamSegmentNotExistsException) AtomicLong(java.util.concurrent.atomic.AtomicLong) Map(java.util.Map) ConcurrentHashMap(java.util.concurrent.ConcurrentHashMap) HashMap(java.util.HashMap) Test(org.junit.Test)

Aggregations

StreamSegmentMergedException (io.pravega.segmentstore.contracts.StreamSegmentMergedException)12 StreamSegmentSealedException (io.pravega.segmentstore.contracts.StreamSegmentSealedException)8 lombok.val (lombok.val)8 Test (org.junit.Test)8 StreamSegmentNotExistsException (io.pravega.segmentstore.contracts.StreamSegmentNotExistsException)6 ArrayList (java.util.ArrayList)6 CompletableFuture (java.util.concurrent.CompletableFuture)6 AttributeUpdate (io.pravega.segmentstore.contracts.AttributeUpdate)5 StreamSegmentStore (io.pravega.segmentstore.contracts.StreamSegmentStore)5 StreamSegmentSealOperation (io.pravega.segmentstore.server.logs.operations.StreamSegmentSealOperation)5 Preconditions (com.google.common.base.Preconditions)4 Exceptions (io.pravega.common.Exceptions)4 LoggerHelpers (io.pravega.common.LoggerHelpers)4 AttributeId (io.pravega.segmentstore.contracts.AttributeId)4 AttributeUpdateType (io.pravega.segmentstore.contracts.AttributeUpdateType)4 Attributes (io.pravega.segmentstore.contracts.Attributes)4 BadAttributeUpdateException (io.pravega.segmentstore.contracts.BadAttributeUpdateException)4 ReadResult (io.pravega.segmentstore.contracts.ReadResult)4 PassingTokenVerifier (io.pravega.segmentstore.server.host.delegationtoken.PassingTokenVerifier)4 SegmentStatsRecorder (io.pravega.segmentstore.server.host.stat.SegmentStatsRecorder)4