use of io.pravega.segmentstore.server.UpdateableContainerMetadata in project pravega by pravega.
the class ContainerMetadataUpdateTransactionTests method testProcessStreamSegmentMap.
// endregion
// region MetadataOperations
/**
* Tests the preProcessOperation and acceptOperation methods with StreamSegmentMap operations.
*/
@Test
public void testProcessStreamSegmentMap() throws Exception {
UpdateableContainerMetadata metadata = createBlankMetadata();
// Part 1: recovery mode (no-op).
metadata.enterRecoveryMode();
val txn1 = createUpdateTransaction(metadata);
// Brand new StreamSegment.
StreamSegmentMapOperation mapOp = createMap();
txn1.preProcessOperation(mapOp);
Assert.assertEquals("preProcessOperation did modify the StreamSegmentId on the operation in recovery mode.", ContainerMetadata.NO_STREAM_SEGMENT_ID, mapOp.getStreamSegmentId());
// Part 2: non-recovery mode.
metadata.exitRecoveryMode();
val txn2 = createUpdateTransaction(metadata);
txn2.preProcessOperation(mapOp);
Assert.assertNotEquals("preProcessOperation did not set the StreamSegmentId on the operation.", ContainerMetadata.NO_STREAM_SEGMENT_ID, mapOp.getStreamSegmentId());
Assert.assertNull("preProcessOperation modified the current transaction.", txn2.getStreamSegmentMetadata(mapOp.getStreamSegmentId()));
Assert.assertNull("preProcessOperation modified the underlying metadata.", metadata.getStreamSegmentMetadata(mapOp.getStreamSegmentId()));
txn2.acceptOperation(mapOp);
val updaterMetadata = txn2.getStreamSegmentMetadata(mapOp.getStreamSegmentId());
Assert.assertEquals("Unexpected StorageLength after call to acceptOperation (in transaction).", mapOp.getLength(), updaterMetadata.getStorageLength());
Assert.assertEquals("Unexpected Length after call to acceptOperation (in transaction).", mapOp.getLength(), updaterMetadata.getLength());
Assert.assertEquals("Unexpected value for isSealed after call to acceptOperation (in transaction).", mapOp.isSealed(), updaterMetadata.isSealed());
Assert.assertEquals("Unexpected value for StartOffset after call to acceptOperation (in transaction).", mapOp.getStartOffset(), updaterMetadata.getStartOffset());
Assert.assertNull("acceptOperation modified the underlying metadata.", metadata.getStreamSegmentMetadata(mapOp.getStreamSegmentId()));
// StreamSegmentName already exists (transaction) and we try to map with new id.
AssertExtensions.assertThrows("Unexpected behavior from preProcessOperation when a StreamSegment with the same Name already exists (in transaction).", () -> txn2.preProcessOperation(createMap(mapOp.getStreamSegmentName())), ex -> ex instanceof MetadataUpdateException);
// Make changes permanent.
txn2.commit(metadata);
val segmentMetadata = metadata.getStreamSegmentMetadata(mapOp.getStreamSegmentId());
AssertExtensions.assertMapEquals("Unexpected attributes in SegmentMetadata after call to commit().", mapOp.getAttributes(), segmentMetadata.getAttributes());
// StreamSegmentName already exists (metadata) and we try to map with new id.
AssertExtensions.assertThrows("Unexpected behavior from preProcessOperation when a StreamSegment with the same Name already exists (in metadata).", () -> txn2.preProcessOperation(createMap(mapOp.getStreamSegmentName())), ex -> ex instanceof MetadataUpdateException);
val length = segmentMetadata.getLength() + 5;
val storageLength = segmentMetadata.getStorageLength() + 1;
val startOffset = segmentMetadata.getStartOffset() + 1;
segmentMetadata.setLength(length);
// StreamSegmentName already exists and we try to map with the same id. Verify that we are able to update its
// StorageLength (if different).
val updateMap = new StreamSegmentMapOperation(StreamSegmentInformation.builder().name(mapOp.getStreamSegmentName()).startOffset(startOffset).length(storageLength).sealed(true).attributes(createAttributes()).build());
updateMap.setStreamSegmentId(mapOp.getStreamSegmentId());
txn2.preProcessOperation(updateMap);
txn2.acceptOperation(updateMap);
Assert.assertEquals("Unexpected StorageLength after call to acceptOperation with remap (in transaction).", storageLength, txn2.getStreamSegmentMetadata(mapOp.getStreamSegmentId()).getStorageLength());
txn2.commit(metadata);
Assert.assertEquals("Unexpected StorageLength after call to acceptOperation with remap (post-commit).", storageLength, metadata.getStreamSegmentMetadata(mapOp.getStreamSegmentId()).getStorageLength());
Assert.assertEquals("Unexpected Length after call to acceptOperation with remap (post-commit).", length, metadata.getStreamSegmentMetadata(mapOp.getStreamSegmentId()).getLength());
Assert.assertEquals("Unexpected StartOffset after call to acceptOperation with remap (post-commit).", startOffset, metadata.getStreamSegmentMetadata(mapOp.getStreamSegmentId()).getStartOffset());
}
use of io.pravega.segmentstore.server.UpdateableContainerMetadata in project pravega by pravega.
the class ContainerMetadataUpdateTransactionTests method testMaxAttributeLimit.
/**
* Tests the ability of the ContainerMetadataUpdateTransaction to enforce the maximum attribute limit on Segments.
*/
@Test
public void testMaxAttributeLimit() throws Exception {
// We check all operations that can update attributes.
val ops = new HashMap<String, Function<Collection<AttributeUpdate>, Operation>>();
ops.put("UpdateAttributes", u -> new UpdateAttributesOperation(SEGMENT_ID, u));
ops.put("Append", u -> new StreamSegmentAppendOperation(SEGMENT_ID, DEFAULT_APPEND_DATA, u));
// Set the maximum allowed number of attributes on a segment.
UpdateableContainerMetadata metadata = createMetadata();
val initialUpdates = new ArrayList<AttributeUpdate>(SegmentMetadata.MAXIMUM_ATTRIBUTE_COUNT);
val expectedValues = new HashMap<UUID, Long>();
for (int i = 0; i < SegmentMetadata.MAXIMUM_ATTRIBUTE_COUNT; i++) {
UUID attributeId;
do {
attributeId = UUID.randomUUID();
} while (expectedValues.containsKey(attributeId));
initialUpdates.add(new AttributeUpdate(attributeId, AttributeUpdateType.None, i));
expectedValues.put(attributeId, (long) i);
}
// And load them up into an UpdateTransaction.
val txn = createUpdateTransaction(metadata);
val initialOp = new UpdateAttributesOperation(SEGMENT_ID, initialUpdates);
txn.preProcessOperation(initialOp);
txn.acceptOperation(initialOp);
// invokes preProcessOperation() - which is responsible with validation, so no changes are made to the UpdateTransaction.
for (val opGenerator : ops.entrySet()) {
// Value replacement.
val replacementUpdates = new ArrayList<AttributeUpdate>();
int i = 0;
for (val e : expectedValues.entrySet()) {
AttributeUpdate u;
switch((i++) % 4) {
case 0:
u = new AttributeUpdate(e.getKey(), AttributeUpdateType.ReplaceIfEquals, e.getValue() + 1, e.getValue());
break;
case 1:
u = new AttributeUpdate(e.getKey(), AttributeUpdateType.ReplaceIfGreater, e.getValue() + 1);
break;
case 2:
u = new AttributeUpdate(e.getKey(), AttributeUpdateType.Accumulate, 1);
break;
default:
u = new AttributeUpdate(e.getKey(), AttributeUpdateType.Replace, 1);
break;
}
replacementUpdates.add(u);
}
// This should not throw anything.
txn.preProcessOperation(opGenerator.getValue().apply(replacementUpdates));
// Removal - this should not throw anything either.
val toRemoveId = initialUpdates.get(0).getAttributeId();
val toRemoveUpdate = new AttributeUpdate(toRemoveId, AttributeUpdateType.Replace, SegmentMetadata.NULL_ATTRIBUTE_VALUE);
txn.preProcessOperation(opGenerator.getValue().apply(Collections.singleton(toRemoveUpdate)));
// Addition - this should throw.
UUID toAddId;
do {
toAddId = UUID.randomUUID();
} while (expectedValues.containsKey(toAddId));
val toAddUpdate = new AttributeUpdate(toAddId, AttributeUpdateType.None, 1);
AssertExtensions.assertThrows("Too many attributes were accepted for operation " + opGenerator.getKey(), () -> txn.preProcessOperation(opGenerator.getValue().apply(Collections.singleton(toAddUpdate))), ex -> ex instanceof TooManyAttributesException);
// Removal+Addition+Replacement: this particular setup should not throw anything.
val mixedUpdates = Arrays.asList(new AttributeUpdate(toAddId, AttributeUpdateType.None, 1), new AttributeUpdate(toRemoveId, AttributeUpdateType.Replace, SegmentMetadata.NULL_ATTRIBUTE_VALUE), new AttributeUpdate(initialUpdates.get(1).getAttributeId(), AttributeUpdateType.Replace, 10));
txn.preProcessOperation(opGenerator.getValue().apply(mixedUpdates));
}
}
use of io.pravega.segmentstore.server.UpdateableContainerMetadata in project pravega by pravega.
the class ContainerMetadataUpdateTransactionTests method testCommitSequenceNumber.
/**
* Tests the ability of the ContainerMetadataUpdateTransaction to set the Sequence Number on the Metadata, when in Recovery Mode.
*/
@Test
public void testCommitSequenceNumber() throws Exception {
final long newSeqNo = 1235;
UpdateableContainerMetadata metadata = createBlankMetadata();
metadata.enterRecoveryMode();
val txn1 = createUpdateTransaction(metadata);
txn1.setOperationSequenceNumber(newSeqNo);
txn1.commit(metadata);
metadata.exitRecoveryMode();
Assert.assertEquals("commit() did not set the metadata sequence number while in recovery mode.", newSeqNo + 1, metadata.nextOperationSequenceNumber());
// Now try again in non-recovery mode.
val txn2 = createUpdateTransaction(metadata);
AssertExtensions.assertThrows("setOperationSequence number should not work in non-recovery mode.", () -> txn2.setOperationSequenceNumber(newSeqNo + 10), ex -> ex instanceof IllegalStateException);
}
use of io.pravega.segmentstore.server.UpdateableContainerMetadata in project pravega by pravega.
the class ContainerMetadataUpdateTransactionTests method testCommitSameTarget.
/**
* Tests the ability of the ContainerMetadataUpdateTransaction to commit all outstanding changes to the same base
* metadata.
*/
@Test
public void testCommitSameTarget() throws Exception {
UpdateableContainerMetadata metadata = createMetadata();
testCommit(metadata, metadata);
}
use of io.pravega.segmentstore.server.UpdateableContainerMetadata in project pravega by pravega.
the class ContainerMetadataUpdateTransactionTests method testProcessMetadataCheckpoint.
/**
* Tests the processMetadataOperation method with MetadataCheckpoint operations.
*/
@Test
public void testProcessMetadataCheckpoint() throws Exception {
// When encountering MetadataCheckpoint in non-Recovery Mode, the ContainerMetadataUpdateTransaction serializes a snapshot
// of the current metadata inside the Operation.
// When encountering MetadataCheckpoint in Recovery Mode, the ContainerMetadataUpdateTransaction deserializes the snapshot-ted
// metadata in it and applies it to the container metadata (inside the transaction). All existing metadata updates
// are cleared.
String newSegmentName = "NewSegmentId";
AtomicLong seqNo = new AtomicLong();
// Create a non-empty metadata, and in addition, seal a segment and truncate it.
this.timeProvider.setElapsedMillis(1234);
UpdateableContainerMetadata metadata = createMetadata();
metadata.getStreamSegmentMetadata(SEGMENT_ID).markSealed();
metadata.getStreamSegmentMetadata(SEGMENT_ID).setStartOffset(SEGMENT_LENGTH / 2);
val txn = createUpdateTransaction(metadata);
// Checkpoint 1: original metadata.
// Checkpoint 2: Checkpoint 1 + 1 StreamSegment and 1 Transaction + 1 Append
MetadataCheckpointOperation checkpoint1 = createMetadataCheckpoint();
MetadataCheckpointOperation checkpoint2 = createMetadataCheckpoint();
// Checkpoint 1 Should have original metadata.
processOperation(checkpoint1, txn, seqNo::incrementAndGet);
UpdateableContainerMetadata checkpointedMetadata = getCheckpointedMetadata(checkpoint1);
assertMetadataSame("Unexpected metadata before any operation.", metadata, checkpointedMetadata);
// Map another StreamSegment, and add an append
StreamSegmentMapOperation mapOp = new StreamSegmentMapOperation(StreamSegmentInformation.builder().name(newSegmentName).length(SEGMENT_LENGTH).build());
processOperation(mapOp, txn, seqNo::incrementAndGet);
processOperation(new StreamSegmentAppendOperation(mapOp.getStreamSegmentId(), DEFAULT_APPEND_DATA, createAttributeUpdates()), txn, seqNo::incrementAndGet);
processOperation(checkpoint2, txn, seqNo::incrementAndGet);
// Checkpoint 2 should have Checkpoint 1 + New StreamSegment + Append.
txn.commit(metadata);
checkpointedMetadata = getCheckpointedMetadata(checkpoint2);
assertMetadataSame("Unexpected metadata after deserializing checkpoint.", metadata, checkpointedMetadata);
}
Aggregations