Search in sources :

Example 1 with TooManyAttributesException

use of io.pravega.segmentstore.contracts.TooManyAttributesException 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 2 with TooManyAttributesException

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

the class SegmentMetadataUpdateTransaction method preProcessAttributes.

/**
 * Pre-processes a collection of attributes.
 * After this method returns, all AttributeUpdates in the given collection will have the actual (and updated) value
 * of that attribute in the Segment.
 *
 * @param attributeUpdates The Updates to process (if any).
 * @throws BadAttributeUpdateException If any of the given AttributeUpdates is invalid given the current state of
 *                                     the segment.
 * @throws TooManyAttributesException  If, as a result of applying the given updates, the Segment would exceed the
 *                                     maximum allowed number of Attributes.
 */
private void preProcessAttributes(Collection<AttributeUpdate> attributeUpdates) throws BadAttributeUpdateException, TooManyAttributesException {
    if (attributeUpdates == null) {
        return;
    }
    int newAttributeCount = this.attributeValues.size();
    for (AttributeUpdate u : attributeUpdates) {
        AttributeUpdateType updateType = u.getUpdateType();
        long previousValue = this.attributeValues.getOrDefault(u.getAttributeId(), SegmentMetadata.NULL_ATTRIBUTE_VALUE);
        // Perform validation, and set the AttributeUpdate.value to the updated value, if necessary.
        switch(updateType) {
            case ReplaceIfGreater:
                // Verify value against existing value, if any.
                boolean hasValue = previousValue != SegmentMetadata.NULL_ATTRIBUTE_VALUE;
                if (hasValue && u.getValue() <= previousValue) {
                    throw new BadAttributeUpdateException(this.name, u, String.format("Expected greater than '%s'.", previousValue));
                }
                break;
            case ReplaceIfEquals:
                // Verify value against existing value, if any.
                if (u.getComparisonValue() != previousValue) {
                    throw new BadAttributeUpdateException(this.name, u, String.format("Expected existing value to be '%s', actual '%s'.", u.getComparisonValue(), previousValue));
                }
                break;
            case None:
                // Verify value is not already set.
                if (previousValue != SegmentMetadata.NULL_ATTRIBUTE_VALUE) {
                    throw new BadAttributeUpdateException(this.name, u, String.format("Attribute value already set (%s).", previousValue));
                }
                break;
            case Accumulate:
                if (previousValue != SegmentMetadata.NULL_ATTRIBUTE_VALUE) {
                    u.setValue(previousValue + u.getValue());
                }
                break;
            case Replace:
                break;
            default:
                throw new BadAttributeUpdateException(this.name, u, "Unexpected update type: " + updateType);
        }
        if (previousValue == SegmentMetadata.NULL_ATTRIBUTE_VALUE && u.getValue() != SegmentMetadata.NULL_ATTRIBUTE_VALUE) {
            // This attribute did not exist and is about to be added.
            newAttributeCount++;
        } else if (previousValue != SegmentMetadata.NULL_ATTRIBUTE_VALUE && u.getValue() == SegmentMetadata.NULL_ATTRIBUTE_VALUE) {
            // This attribute existed and is about to be removed.
            newAttributeCount--;
        }
    }
    if (newAttributeCount > SegmentMetadata.MAXIMUM_ATTRIBUTE_COUNT && newAttributeCount > this.attributeValues.size()) {
        // attributes of existing segments, but not increase their count.
        throw new TooManyAttributesException(this.name, SegmentMetadata.MAXIMUM_ATTRIBUTE_COUNT);
    }
}
Also used : AttributeUpdate(io.pravega.segmentstore.contracts.AttributeUpdate) TooManyAttributesException(io.pravega.segmentstore.contracts.TooManyAttributesException) AttributeUpdateType(io.pravega.segmentstore.contracts.AttributeUpdateType) BadAttributeUpdateException(io.pravega.segmentstore.contracts.BadAttributeUpdateException)

Aggregations

AttributeUpdate (io.pravega.segmentstore.contracts.AttributeUpdate)2 TooManyAttributesException (io.pravega.segmentstore.contracts.TooManyAttributesException)2 AttributeUpdateType (io.pravega.segmentstore.contracts.AttributeUpdateType)1 BadAttributeUpdateException (io.pravega.segmentstore.contracts.BadAttributeUpdateException)1 UpdateableContainerMetadata (io.pravega.segmentstore.server.UpdateableContainerMetadata)1 MergeTransactionOperation (io.pravega.segmentstore.server.logs.operations.MergeTransactionOperation)1 MetadataCheckpointOperation (io.pravega.segmentstore.server.logs.operations.MetadataCheckpointOperation)1 Operation (io.pravega.segmentstore.server.logs.operations.Operation)1 StorageMetadataCheckpointOperation (io.pravega.segmentstore.server.logs.operations.StorageMetadataCheckpointOperation)1 StorageOperation (io.pravega.segmentstore.server.logs.operations.StorageOperation)1 StreamSegmentAppendOperation (io.pravega.segmentstore.server.logs.operations.StreamSegmentAppendOperation)1 StreamSegmentMapOperation (io.pravega.segmentstore.server.logs.operations.StreamSegmentMapOperation)1 StreamSegmentSealOperation (io.pravega.segmentstore.server.logs.operations.StreamSegmentSealOperation)1 StreamSegmentTruncateOperation (io.pravega.segmentstore.server.logs.operations.StreamSegmentTruncateOperation)1 UpdateAttributesOperation (io.pravega.segmentstore.server.logs.operations.UpdateAttributesOperation)1 ArrayList (java.util.ArrayList)1 Collection (java.util.Collection)1 HashMap (java.util.HashMap)1 UUID (java.util.UUID)1 lombok.val (lombok.val)1