use of io.pravega.segmentstore.server.UpdateableContainerMetadata in project pravega by pravega.
the class ContainerMetadataUpdateTransactionTests method testAcceptStreamSegmentAppend.
/**
* Tests the accept method with StreamSegmentAppend operations.
*/
@Test
public void testAcceptStreamSegmentAppend() throws Exception {
UpdateableContainerMetadata metadata = createMetadata();
val txn = createUpdateTransaction(metadata);
StreamSegmentAppendOperation appendOp = createAppendNoOffset();
// When no pre-process has happened.
AssertExtensions.assertThrows("Unexpected behavior from acceptOperation() when no pre-processing was made.", () -> txn.acceptOperation(appendOp), ex -> ex instanceof MetadataUpdateException);
Assert.assertEquals("acceptOperation updated the transaction even if it threw an exception.", SEGMENT_LENGTH, txn.getStreamSegmentMetadata(SEGMENT_ID).getLength());
Assert.assertEquals("acceptOperation updated the metadata.", SEGMENT_LENGTH, metadata.getStreamSegmentMetadata(SEGMENT_ID).getLength());
// When all is good.
txn.preProcessOperation(appendOp);
txn.acceptOperation(appendOp);
Assert.assertEquals("acceptOperation did not update the transaction.", SEGMENT_LENGTH + appendOp.getData().length, txn.getStreamSegmentMetadata(SEGMENT_ID).getLength());
Assert.assertEquals("acceptOperation updated the metadata.", SEGMENT_LENGTH, metadata.getStreamSegmentMetadata(SEGMENT_ID).getLength());
}
use of io.pravega.segmentstore.server.UpdateableContainerMetadata in project pravega by pravega.
the class ContainerMetadataUpdateTransactionTests method testRollback.
/**
* Tests the ability of the ContainerMetadataUpdateTransaction to rollback all outstanding changes.
*/
@Test
public void testRollback() throws Exception {
// Create a couple of operations, commit them, and then create a few more appends, merge a Transaction and seal the parent stream.
// Then call rollback(); verify no changes have been applied after the call to commit().
UpdateableContainerMetadata metadata = createMetadata();
val txn = createUpdateTransaction(metadata);
StreamSegmentAppendOperation committedAppend = createAppendNoOffset();
txn.preProcessOperation(committedAppend);
txn.acceptOperation(committedAppend);
// This is the last extent of the modifications to the metadata.
txn.commit(metadata);
int appendCount = 500;
ArrayList<StorageOperation> operations = new ArrayList<>();
for (int i = 0; i < appendCount; i++) {
operations.add(createAppendNoOffset());
}
operations.add(createMerge());
operations.add(createSeal());
long seqNo = 0;
for (StorageOperation op : operations) {
txn.preProcessOperation(op);
op.setSequenceNumber(++seqNo);
txn.acceptOperation(op);
}
txn.clear();
long expectedLength = SEGMENT_LENGTH + DEFAULT_APPEND_DATA.length;
// Verify metadata is untouched and that the updater has truly rolled back.
SegmentMetadata parentMetadata = metadata.getStreamSegmentMetadata(SEGMENT_ID);
Assert.assertEquals("Unexpected Length in metadata after rollback.", expectedLength, parentMetadata.getLength());
Assert.assertFalse("Unexpected value for isSealed in metadata after rollback.", parentMetadata.isSealed());
checkLastKnownSequenceNumber("Unexpected lastUsed for Parent after rollback.", 0, parentMetadata);
SegmentMetadata transactionMetadata = metadata.getStreamSegmentMetadata(SEALED_TRANSACTION_ID);
Assert.assertFalse("Unexpected value for isMerged in transaction segment metadata after rollback.", transactionMetadata.isMerged());
checkLastKnownSequenceNumber("Unexpected lastUsed for Transaction segment after rollback.", 0, transactionMetadata);
// Now the updater
parentMetadata = txn.getStreamSegmentMetadata(SEGMENT_ID);
Assert.assertEquals("Unexpected Length in transaction after rollback.", expectedLength, parentMetadata.getLength());
Assert.assertFalse("Unexpected value for isSealed in transaction after rollback.", parentMetadata.isSealed());
checkLastKnownSequenceNumber("Unexpected lastUsed for Parent (txn) after rollback.", 0, parentMetadata);
transactionMetadata = txn.getStreamSegmentMetadata(SEALED_TRANSACTION_ID);
Assert.assertFalse("Unexpected value for isMerged in transaction segment in update transaction after rollback.", transactionMetadata.isMerged());
checkLastKnownSequenceNumber("Unexpected lastUsed for Transaction segment in update transaction after rollback.", 0, transactionMetadata);
}
use of io.pravega.segmentstore.server.UpdateableContainerMetadata in project pravega by pravega.
the class ContainerMetadataUpdateTransactionTests method testAcceptMergeTransaction.
/**
* Tests the accept method with MergeTransactionOperations.
*/
@Test
public void testAcceptMergeTransaction() throws Exception {
UpdateableContainerMetadata metadata = createMetadata();
val txn = createUpdateTransaction(metadata);
MergeTransactionOperation mergeOp = createMerge();
// When no pre-process has happened
AssertExtensions.assertThrows("Unexpected behavior from acceptOperation() when no pre-processing was made.", () -> txn.acceptOperation(mergeOp), ex -> ex instanceof MetadataUpdateException);
Assert.assertEquals("acceptOperation updated the transaction even if it threw an exception (parent segment).", SEGMENT_LENGTH, txn.getStreamSegmentMetadata(SEGMENT_ID).getLength());
Assert.assertEquals("acceptOperation updated the metadata (parent segment).", SEGMENT_LENGTH, metadata.getStreamSegmentMetadata(SEGMENT_ID).getLength());
// This would naturally happen in case of a failure, so we need to simulate this here too.
txn.clear();
// When all is good.
txn.preProcessOperation(mergeOp);
txn.acceptOperation(mergeOp);
Assert.assertTrue("acceptOperation did not update the transaction(Transaction).", txn.getStreamSegmentMetadata(SEALED_TRANSACTION_ID).isMerged());
Assert.assertFalse("acceptOperation updated the metadata (Transaction).", metadata.getStreamSegmentMetadata(SEALED_TRANSACTION_ID).isMerged());
Assert.assertEquals("acceptOperation did not update the transaction.", SEGMENT_LENGTH + SEALED_TRANSACTION_LENGTH, txn.getStreamSegmentMetadata(SEGMENT_ID).getLength());
Assert.assertEquals("acceptOperation updated the metadata.", SEGMENT_LENGTH, metadata.getStreamSegmentMetadata(SEGMENT_ID).getLength());
}
use of io.pravega.segmentstore.server.UpdateableContainerMetadata in project pravega by pravega.
the class ContainerMetadataUpdateTransactionTests method testPreProcessAndAcceptWithInvalidSegmentId.
// endregion
// region Other tests
/**
* Tests the behavior of preProcessOperation and acceptOperation when encountering an invalid StreamSegmentId, or
* when encountering a StreamSegment Id for a deleted StreamSegment.
*/
@Test
public void testPreProcessAndAcceptWithInvalidSegmentId() throws Exception {
UpdateableContainerMetadata metadata = createBlankMetadata();
val txn = createUpdateTransaction(metadata);
ArrayList<StorageOperation> testOperations = new ArrayList<>();
testOperations.add(createAppendNoOffset());
testOperations.add(createSeal());
testOperations.add(createMerge());
for (StorageOperation op : testOperations) {
AssertExtensions.assertThrows("Unexpected behavior from preProcessOperation when processing an operation for a non-existent Segment: " + op, () -> txn.preProcessOperation(op), ex -> ex instanceof MetadataUpdateException);
AssertExtensions.assertThrows("Unexpected behavior from acceptOperation when processing an operation for a non-existent Segment: " + op, () -> txn.acceptOperation(op), ex -> ex instanceof MetadataUpdateException);
}
// If the StreamSegment was previously marked as deleted.
UpdateableSegmentMetadata segmentMetadata = metadata.mapStreamSegmentId("foo", SEGMENT_ID);
segmentMetadata.markDeleted();
for (StorageOperation op : testOperations) {
AssertExtensions.assertThrows("Unexpected behavior from preProcessOperation when processing an operation for deleted Segment: " + op, () -> txn.preProcessOperation(op), ex -> ex instanceof StreamSegmentNotExistsException);
}
}
use of io.pravega.segmentstore.server.UpdateableContainerMetadata in project pravega by pravega.
the class ContainerMetadataUpdateTransactionTests method testPreProcessMergeTransaction.
// endregion
// region MergeTransactionOperation
/**
* Tests the preProcess method with MergeTransactionOperations.
* Scenarios:
* * Recovery/non-recovery mode
* * Target StreamSegment is sealed
* * Target StreamSegment is a Transaction
* * Transaction StreamSegment is already merged
* * Transaction StreamSegment is not sealed
*/
@Test
public void testPreProcessMergeTransaction() throws Exception {
UpdateableContainerMetadata metadata = createMetadata();
// When everything is OK (recovery mode).
MergeTransactionOperation 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_TRANSACTION_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_TRANSACTION_ID).isMerged());
Assert.assertFalse("preProcess(Merge) seems to have changed the metadata in recovery mode.", metadata.getStreamSegmentMetadata(SEALED_TRANSACTION_ID).isMerged());
// When everything is OK (non-recovery mode).
MergeTransactionOperation 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_TRANSACTION_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_TRANSACTION_ID).isMerged());
Assert.assertFalse("preProcess(Merge) seems to have changed the metadata in non-recovery mode.", metadata.getStreamSegmentMetadata(SEALED_TRANSACTION_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 Target StreamSegment is a Transaction.
MergeTransactionOperation mergeToTransactionOp = new MergeTransactionOperation(NOTSEALED_TRANSACTION_ID, SEALED_TRANSACTION_ID);
AssertExtensions.assertThrows("Unexpected behavior for preProcess(Merge) when Target StreamSegment is a Transaction.", () -> txn2.preProcessOperation(mergeToTransactionOp), ex -> ex instanceof MetadataUpdateException);
// When Transaction is not sealed.
MergeTransactionOperation mergeNonSealed = new MergeTransactionOperation(NOTSEALED_TRANSACTION_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);
}
Aggregations