use of io.pravega.segmentstore.server.logs.operations.UpdateAttributesOperation 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.logs.operations.UpdateAttributesOperation in project pravega by pravega.
the class StreamSegmentContainer method updateAttributes.
@Override
public CompletableFuture<Void> updateAttributes(String streamSegmentName, Collection<AttributeUpdate> attributeUpdates, Duration timeout) {
ensureRunning();
TimeoutTimer timer = new TimeoutTimer(timeout);
logRequest("updateAttributes", streamSegmentName, attributeUpdates);
this.metrics.updateAttributes();
return this.segmentMapper.getOrAssignStreamSegmentId(streamSegmentName, timer.getRemaining(), streamSegmentId -> {
UpdateAttributesOperation operation = new UpdateAttributesOperation(streamSegmentId, attributeUpdates);
return this.durableLog.add(operation, timer.getRemaining());
});
}
use of io.pravega.segmentstore.server.logs.operations.UpdateAttributesOperation in project pravega by pravega.
the class ContainerMetadataUpdateTransaction method preProcessOperation.
/**
* Pre-processes the given Operation. See OperationMetadataUpdater.preProcessOperation for more details on behavior.
*
* @param operation The operation to pre-process.
* @throws ContainerException If the given operation was rejected given the current state of the container metadata.
* @throws StreamSegmentException If the given operation was incompatible with the current state of the Segment.
* For example: StreamSegmentNotExistsException, StreamSegmentSealedException or
* StreamSegmentMergedException.
*/
void preProcessOperation(Operation operation) throws ContainerException, StreamSegmentException {
checkNotSealed();
SegmentMetadataUpdateTransaction segmentMetadata = null;
if (operation instanceof SegmentOperation) {
segmentMetadata = getSegmentUpdateTransaction(((SegmentOperation) operation).getStreamSegmentId());
if (segmentMetadata.isDeleted()) {
throw new StreamSegmentNotExistsException(segmentMetadata.getName());
}
}
if (operation instanceof StreamSegmentAppendOperation) {
segmentMetadata.preProcessOperation((StreamSegmentAppendOperation) operation);
} else if (operation instanceof StreamSegmentSealOperation) {
segmentMetadata.preProcessOperation((StreamSegmentSealOperation) operation);
} else if (operation instanceof MergeTransactionOperation) {
MergeTransactionOperation mbe = (MergeTransactionOperation) operation;
SegmentMetadataUpdateTransaction transactionMetadata = getSegmentUpdateTransaction(mbe.getTransactionSegmentId());
transactionMetadata.preProcessAsTransactionSegment(mbe);
segmentMetadata.preProcessAsParentSegment(mbe, transactionMetadata);
} else if (operation instanceof StreamSegmentMapOperation) {
preProcessMetadataOperation((StreamSegmentMapOperation) operation);
} else if (operation instanceof UpdateAttributesOperation) {
segmentMetadata.preProcessOperation((UpdateAttributesOperation) operation);
} else if (operation instanceof MetadataCheckpointOperation) {
// MetadataCheckpointOperations do not require preProcess and accept; they can be handled in a single stage.
processMetadataOperation((MetadataCheckpointOperation) operation);
} else if (operation instanceof StorageMetadataCheckpointOperation) {
// StorageMetadataCheckpointOperation do not require preProcess and accept; they can be handled in a single stage.
processMetadataOperation((StorageMetadataCheckpointOperation) operation);
} else if (operation instanceof StreamSegmentTruncateOperation) {
segmentMetadata.preProcessOperation((StreamSegmentTruncateOperation) operation);
}
}
use of io.pravega.segmentstore.server.logs.operations.UpdateAttributesOperation in project pravega by pravega.
the class ContainerMetadataUpdateTransaction method acceptOperation.
/**
* Accepts the given Operation. The Operation's effects are reflected in the pending transaction.
* This method has no effect on Metadata Operations.
* See OperationMetadataUpdater.acceptOperation for more details on behavior.
*
* @param operation The operation to accept.
* @throws MetadataUpdateException If the given operation was rejected given the current state of the metadata.
* @throws NullPointerException If the operation is null.
*/
void acceptOperation(Operation operation) throws MetadataUpdateException {
checkNotSealed();
SegmentMetadataUpdateTransaction segmentMetadata = null;
if (operation instanceof SegmentOperation) {
segmentMetadata = getSegmentUpdateTransaction(((SegmentOperation) operation).getStreamSegmentId());
segmentMetadata.setLastUsed(operation.getSequenceNumber());
}
if (operation instanceof StreamSegmentAppendOperation) {
segmentMetadata.acceptOperation((StreamSegmentAppendOperation) operation);
} else if (operation instanceof StreamSegmentSealOperation) {
segmentMetadata.acceptOperation((StreamSegmentSealOperation) operation);
} else if (operation instanceof MergeTransactionOperation) {
MergeTransactionOperation mto = (MergeTransactionOperation) operation;
SegmentMetadataUpdateTransaction transactionMetadata = getSegmentUpdateTransaction(mto.getTransactionSegmentId());
transactionMetadata.acceptAsTransactionSegment(mto);
transactionMetadata.setLastUsed(operation.getSequenceNumber());
segmentMetadata.acceptAsParentSegment(mto, transactionMetadata);
} else if (operation instanceof MetadataCheckpointOperation) {
// A MetadataCheckpointOperation represents a valid truncation point. Record it as such.
this.newTruncationPoints.add(operation.getSequenceNumber());
} else if (operation instanceof StreamSegmentMapOperation) {
acceptMetadataOperation((StreamSegmentMapOperation) operation);
} else if (operation instanceof UpdateAttributesOperation) {
segmentMetadata.acceptOperation((UpdateAttributesOperation) operation);
} else if (operation instanceof StreamSegmentTruncateOperation) {
segmentMetadata.acceptOperation((StreamSegmentTruncateOperation) operation);
}
}
Aggregations