Search in sources :

Example 1 with UpdateableContainerMetadata

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());
}
Also used : lombok.val(lombok.val) StreamSegmentMapOperation(io.pravega.segmentstore.server.logs.operations.StreamSegmentMapOperation) UpdateableContainerMetadata(io.pravega.segmentstore.server.UpdateableContainerMetadata) Test(org.junit.Test)

Example 2 with UpdateableContainerMetadata

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));
    }
}
Also used : lombok.val(lombok.val) AttributeUpdate(io.pravega.segmentstore.contracts.AttributeUpdate) TooManyAttributesException(io.pravega.segmentstore.contracts.TooManyAttributesException) UpdateAttributesOperation(io.pravega.segmentstore.server.logs.operations.UpdateAttributesOperation) HashMap(java.util.HashMap) ArrayList(java.util.ArrayList) Collection(java.util.Collection) StorageMetadataCheckpointOperation(io.pravega.segmentstore.server.logs.operations.StorageMetadataCheckpointOperation) Operation(io.pravega.segmentstore.server.logs.operations.Operation) StreamSegmentMapOperation(io.pravega.segmentstore.server.logs.operations.StreamSegmentMapOperation) StreamSegmentTruncateOperation(io.pravega.segmentstore.server.logs.operations.StreamSegmentTruncateOperation) UpdateAttributesOperation(io.pravega.segmentstore.server.logs.operations.UpdateAttributesOperation) MetadataCheckpointOperation(io.pravega.segmentstore.server.logs.operations.MetadataCheckpointOperation) StorageOperation(io.pravega.segmentstore.server.logs.operations.StorageOperation) StreamSegmentAppendOperation(io.pravega.segmentstore.server.logs.operations.StreamSegmentAppendOperation) MergeTransactionOperation(io.pravega.segmentstore.server.logs.operations.MergeTransactionOperation) StreamSegmentSealOperation(io.pravega.segmentstore.server.logs.operations.StreamSegmentSealOperation) UpdateableContainerMetadata(io.pravega.segmentstore.server.UpdateableContainerMetadata) StreamSegmentAppendOperation(io.pravega.segmentstore.server.logs.operations.StreamSegmentAppendOperation) UUID(java.util.UUID) Test(org.junit.Test)

Example 3 with UpdateableContainerMetadata

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);
}
Also used : lombok.val(lombok.val) UpdateableContainerMetadata(io.pravega.segmentstore.server.UpdateableContainerMetadata) Test(org.junit.Test)

Example 4 with UpdateableContainerMetadata

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);
}
Also used : UpdateableContainerMetadata(io.pravega.segmentstore.server.UpdateableContainerMetadata) Test(org.junit.Test)

Example 5 with UpdateableContainerMetadata

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);
}
Also used : lombok.val(lombok.val) AtomicLong(java.util.concurrent.atomic.AtomicLong) StorageMetadataCheckpointOperation(io.pravega.segmentstore.server.logs.operations.StorageMetadataCheckpointOperation) MetadataCheckpointOperation(io.pravega.segmentstore.server.logs.operations.MetadataCheckpointOperation) StreamSegmentMapOperation(io.pravega.segmentstore.server.logs.operations.StreamSegmentMapOperation) UpdateableContainerMetadata(io.pravega.segmentstore.server.UpdateableContainerMetadata) StreamSegmentAppendOperation(io.pravega.segmentstore.server.logs.operations.StreamSegmentAppendOperation) Test(org.junit.Test)

Aggregations

UpdateableContainerMetadata (io.pravega.segmentstore.server.UpdateableContainerMetadata)39 Test (org.junit.Test)35 lombok.val (lombok.val)26 StreamSegmentMapOperation (io.pravega.segmentstore.server.logs.operations.StreamSegmentMapOperation)17 StreamSegmentAppendOperation (io.pravega.segmentstore.server.logs.operations.StreamSegmentAppendOperation)16 MetadataBuilder (io.pravega.segmentstore.server.MetadataBuilder)15 Operation (io.pravega.segmentstore.server.logs.operations.Operation)12 ArrayList (java.util.ArrayList)12 StorageOperation (io.pravega.segmentstore.server.logs.operations.StorageOperation)11 MergeTransactionOperation (io.pravega.segmentstore.server.logs.operations.MergeTransactionOperation)10 MetadataCheckpointOperation (io.pravega.segmentstore.server.logs.operations.MetadataCheckpointOperation)10 StorageMetadataCheckpointOperation (io.pravega.segmentstore.server.logs.operations.StorageMetadataCheckpointOperation)10 StreamSegmentSealOperation (io.pravega.segmentstore.server.logs.operations.StreamSegmentSealOperation)9 SegmentMetadata (io.pravega.segmentstore.server.SegmentMetadata)7 UpdateableSegmentMetadata (io.pravega.segmentstore.server.UpdateableSegmentMetadata)7 HashMap (java.util.HashMap)7 AttributeUpdate (io.pravega.segmentstore.contracts.AttributeUpdate)6 UUID (java.util.UUID)6 ReadIndex (io.pravega.segmentstore.server.ReadIndex)5 LogAddress (io.pravega.segmentstore.storage.LogAddress)5