use of io.pravega.segmentstore.contracts.AttributeUpdate 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 AttributeIdLengthMismatchException If the given AttributeUpdates contains extended Attributes with the
* wrong length (compared to that which is defined on the Segment).
* @throws MetadataUpdateException If the operation cannot not be processed because a Metadata Update
* precondition check failed.
*/
private void preProcessAttributes(AttributeUpdateCollection attributeUpdates) throws BadAttributeUpdateException, MetadataUpdateException {
if (attributeUpdates == null) {
return;
}
// Make sure that the number of existing ExtendedAttributes + incoming ExtendedAttributes does not exceed the limit.
if (type.isTransientSegment() && this.baseAttributeValues.size() > TRANSIENT_ATTRIBUTE_LIMIT) {
throw new MetadataUpdateException(this.containerId, String.format("A Transient Segment ('%s') may not exceed %s Extended Attributes.", this.name, TRANSIENT_ATTRIBUTE_LIMIT));
}
// We must ensure that we aren't trying to set/update attributes that are incompatible with this Segment.
validateAttributeIdLengths(attributeUpdates);
for (AttributeUpdate u : attributeUpdates) {
if (Attributes.isUnmodifiable(u.getAttributeId())) {
throw new MetadataUpdateException(this.containerId, String.format("Attribute Id '%s' on Segment Id %s ('%s') may not be modified.", u.getAttributeId(), this.id, this.name));
}
AttributeUpdateType updateType = u.getUpdateType();
boolean hasValue = false;
long previousValue = Attributes.NULL_ATTRIBUTE_VALUE;
if (this.attributeUpdates.containsKey(u.getAttributeId())) {
hasValue = true;
previousValue = this.attributeUpdates.get(u.getAttributeId());
} else if (this.baseAttributeValues.containsKey(u.getAttributeId())) {
hasValue = true;
previousValue = this.baseAttributeValues.get(u.getAttributeId());
}
// Perform validation, and set the AttributeUpdate.value to the updated value, if necessary.
switch(updateType) {
case ReplaceIfGreater:
// Verify value against existing value, if any.
if (hasValue && u.getValue() <= previousValue) {
throw new BadAttributeUpdateException(this.name, u, false, String.format("Expected greater than '%s'.", previousValue));
}
break;
case ReplaceIfEquals:
// Verify value against existing value, if any.
if (u.getComparisonValue() != previousValue || !hasValue) {
throw new BadAttributeUpdateException(this.name, u, !hasValue, String.format("Expected '%s', given '%s'.", previousValue, u.getComparisonValue()));
}
break;
case None:
// Verify value is not already set.
if (hasValue) {
throw new BadAttributeUpdateException(this.name, u, false, String.format("Attribute value already set (%s).", previousValue));
}
break;
case Accumulate:
if (hasValue) {
u.setValue(previousValue + u.getValue());
}
break;
case Replace:
break;
default:
throw new BadAttributeUpdateException(this.name, u, !hasValue, "Unexpected update type: " + updateType);
}
}
// Evaluate and set DynamicAttributeUpdates.
for (DynamicAttributeUpdate u : attributeUpdates.getDynamicAttributeUpdates()) {
u.setValue(u.getValueReference().evaluate(this));
}
}
use of io.pravega.segmentstore.contracts.AttributeUpdate in project pravega by pravega.
the class TableMetadataStore method initialize.
// region MetadataStore Implementation
@Override
public CompletableFuture<Void> initialize(Duration timeout) {
Preconditions.checkState(!this.initialized.get(), "TableMetadataStore is already initialized.");
// Invoke submitAssignment(), which will ensure that the Metadata Segment is mapped in memory and pinned.
// If this is the first time we initialize the TableMetadataStore for this SegmentContainer, a new id will be
// assigned to it.
val attributes = new HashMap<>(TableAttributes.DEFAULT_VALUES);
// Make sure we enable rollover for this segment.
attributes.putAll(this.config.getDefaultCompactionAttributes());
val attributeUpdates = attributes.entrySet().stream().map(e -> new AttributeUpdate(e.getKey(), AttributeUpdateType.None, e.getValue())).collect(Collectors.toList());
// Container Metadata Segment is a System Table Segment. It is System, Internal, and Critical.
val segmentType = SegmentType.builder().tableSegment().system().critical().internal().build();
return submitAssignment(SegmentInfo.newSegment(this.metadataSegmentName, segmentType, attributeUpdates), true, timeout).thenAccept(segmentId -> {
this.initialized.set(true);
log.info("{}: Metadata Segment pinned. Name = '{}', Id = '{}'", this.traceObjectId, this.metadataSegmentName, segmentId);
});
}
use of io.pravega.segmentstore.contracts.AttributeUpdate in project pravega by pravega.
the class StreamSegmentAppendOperationTests method createAttributes.
static AttributeUpdateCollection createAttributes() {
val result = new AttributeUpdateCollection();
long currentValue = 0;
for (AttributeUpdateType ut : AttributeUpdateType.values()) {
result.add(new AttributeUpdate(AttributeId.uuid(Attributes.CORE_ATTRIBUTE_ID_PREFIX, ut.getTypeId()), ut, ++currentValue, currentValue));
result.add(new AttributeUpdate(AttributeId.random(AttributeId.Variable.MAX_LENGTH), ut, ++currentValue, currentValue));
}
return result;
}
use of io.pravega.segmentstore.contracts.AttributeUpdate in project pravega by pravega.
the class ContainerTableExtensionImpl method createSegment.
// endregion
// region TableStore Implementation
@Override
public CompletableFuture<Void> createSegment(@NonNull String segmentName, SegmentType segmentType, TableSegmentConfig config, Duration timeout) {
Exceptions.checkNotClosed(this.closed.get(), this);
// Ensure at least a TableSegment type.
segmentType = SegmentType.builder(segmentType).tableSegment().build();
val attributes = new HashMap<>(TableAttributes.DEFAULT_VALUES);
attributes.putAll(selectLayout(segmentName, segmentType).getNewSegmentAttributes(config));
val attributeUpdates = attributes.entrySet().stream().map(e -> new AttributeUpdate(e.getKey(), AttributeUpdateType.None, e.getValue())).collect(Collectors.toList());
logRequest("createSegment", segmentName, segmentType, config);
return this.segmentContainer.createStreamSegment(segmentName, segmentType, attributeUpdates, timeout);
}
use of io.pravega.segmentstore.contracts.AttributeUpdate in project pravega by pravega.
the class FixedKeyLengthTableSegmentLayout method put.
@Override
CompletableFuture<List<Long>> put(@NonNull DirectSegmentAccess segment, @NonNull List<TableEntry> entries, long tableSegmentOffset, TimeoutTimer timer) {
val segmentInfo = segment.getInfo();
ensureSegmentType(segmentInfo.getName(), segmentInfo.getType());
val segmentKeyLength = getSegmentKeyLength(segmentInfo);
ensureValidKeyLength(segmentInfo.getName(), segmentKeyLength);
val attributeUpdates = new AttributeUpdateCollection();
int batchOffset = 0;
val batchOffsets = new ArrayList<Integer>();
boolean isConditional = false;
for (val e : entries) {
val key = e.getKey();
Preconditions.checkArgument(key.getKey().getLength() == segmentKeyLength, "Entry Key Length for key `%s` incompatible with segment '%s' which requires key lengths of %s.", key, segmentInfo.getName(), segmentKeyLength);
attributeUpdates.add(createIndexUpdate(key, batchOffset));
isConditional |= key.hasVersion();
batchOffsets.add(batchOffset);
batchOffset += this.serializer.getUpdateLength(e);
}
logRequest("put", segmentInfo.getName(), isConditional, tableSegmentOffset, entries.size(), batchOffset);
if (batchOffset > this.config.getMaxBatchSize()) {
throw new UpdateBatchTooLargeException(batchOffset, this.config.getMaxBatchSize());
}
// Update total number of entries in Table (this includes updates to the same key).
attributeUpdates.add(new AttributeUpdate(TableAttributes.TOTAL_ENTRY_COUNT, AttributeUpdateType.Accumulate, entries.size()));
val serializedEntries = this.serializer.serializeUpdate(entries);
val append = tableSegmentOffset == TableSegmentLayout.NO_OFFSET ? segment.append(serializedEntries, attributeUpdates, timer.getRemaining()) : segment.append(serializedEntries, attributeUpdates, tableSegmentOffset, timer.getRemaining());
return handleConditionalUpdateException(append, segmentInfo).thenApply(segmentOffset -> {
this.compactionService.process(new CompactionCandidate(segment));
return batchOffsets.stream().map(offset -> offset + segmentOffset).collect(Collectors.toList());
});
}
Aggregations