/** * Generates a set of {@link AttributeUpdate}s that set the initial Attributes on a newly create Table Segment. * TODO cleanup as described in https://github.com/pravega/pravega/issues/3273. * * Attributes: * * {@link Attributes#TABLE_INDEX_OFFSET} is initialized to 0. * * {@link Attributes#TABLE_ENTRY_COUNT} is initialized to 0. * * {@link Attributes#TABLE_BUCKET_COUNT} is initialized to 0. * * @return A Collection of {@link AttributeUpdate}s. */ static Collection<AttributeUpdate> getInitialTableAttributes() { return Arrays.asList( new AttributeUpdate(Attributes.TABLE_INDEX_OFFSET, AttributeUpdateType.None, 0L), new AttributeUpdate(Attributes.TABLE_ENTRY_COUNT, AttributeUpdateType.None, 0L), new AttributeUpdate(Attributes.TABLE_BUCKET_COUNT, AttributeUpdateType.None, 0L)); }
private void writeAttributeUpdate00(RevisionDataOutput target, AttributeUpdate au) throws IOException { target.writeUUID(au.getAttributeId()); target.writeByte(au.getUpdateType().getTypeId()); target.writeLong(au.getValue()); target.writeLong(au.getComparisonValue()); }
/** * Accepts a collection of AttributeUpdates in the metadata. * * @param attributeUpdates The Attribute updates to accept. */ private void acceptAttributes(Collection<AttributeUpdate> attributeUpdates) { if (attributeUpdates == null) { return; } for (AttributeUpdate au : attributeUpdates) { this.attributeUpdates.put(au.getAttributeId(), au.getValue()); } }
private void verifyAttributeUpdates(String stepName, ContainerMetadata containerMetadata, Collection<AttributeUpdate> attributeUpdates, Map<UUID, Long> expectedValues) { // Verify that the Attribute Updates have their expected values and that the updater has internalized the attribute updates. val transactionMetadata = containerMetadata.getStreamSegmentMetadata(SEGMENT_ID); val expectedTransactionAttributes = new HashMap<UUID, Long>(expectedValues); attributeUpdates.forEach(au -> expectedTransactionAttributes.put(au.getAttributeId(), au.getValue())); SegmentMetadataComparer.assertSameAttributes("Unexpected attributes in transaction metadata " + stepName + ".", expectedTransactionAttributes, transactionMetadata); for (AttributeUpdate au : attributeUpdates) { Assert.assertEquals("Unexpected updated value for AttributeUpdate[" + au.getUpdateType() + "] " + stepName, (long) expectedValues.get(au.getAttributeId()), au.getValue()); } }
private void recordAppend(long segmentId, int length, OperationMetadataUpdater updater, UpdateableContainerMetadata referenceMetadata) throws Exception { byte[] data = new byte[length]; val attributeUpdates = Arrays.asList( new AttributeUpdate(Attributes.CREATION_TIME, AttributeUpdateType.Replace, NEXT_ATTRIBUTE_VALUE.get()), new AttributeUpdate(Attributes.EVENT_COUNT, AttributeUpdateType.Accumulate, NEXT_ATTRIBUTE_VALUE.get())); val op = new StreamSegmentAppendOperation(segmentId, data, attributeUpdates); process(op, updater); if (referenceMetadata != null) { val rsm = referenceMetadata.getStreamSegmentMetadata(segmentId); rsm.setLength(rsm.getLength() + length); val attributes = new HashMap<UUID, Long>(); op.getAttributeUpdates().forEach(au -> attributes.put(au.getAttributeId(), au.getValue())); rsm.updateAttributes(attributes); } }
val coreAttributeUpdates = Collections.singletonList(new AttributeUpdate(Attributes.EVENT_COUNT, AttributeUpdateType.Replace, 1)); processOperation(new StreamSegmentAppendOperation(mapOp.getStreamSegmentId(), DEFAULT_APPEND_DATA, coreAttributeUpdates), txn, seqNo::incrementAndGet); Assert.assertFalse("Extended attribute was serialized.", checkpointedSm.getAttributes().containsKey(e.getAttributeId()));
/** * Creates a new instance of the BadAttributeUpdateException class. * * @param streamSegmentName The name of the StreamSegment. * @param attributeUpdate The AttributeUpdate that failed the check. * @param previousValueMissing If true, indicates that the previous value for this attempted Attribute Update was missing * and was likely the cause for the failed update. * @param errorMessage The Event Number that was given as part of the Operation. */ public BadAttributeUpdateException(String streamSegmentName, AttributeUpdate attributeUpdate, boolean previousValueMissing, String errorMessage) { super(streamSegmentName, getMessage(attributeUpdate, previousValueMissing, errorMessage)); this.previousValueMissing = previousValueMissing; this.attributeId = attributeUpdate == null ? null : attributeUpdate.getAttributeId(); }
private void applyAttributes(Collection<AttributeUpdate> updates, Map<UUID, Long> target) { updates.forEach(au -> target.put(au.getAttributeId(), au.getValue())); }
/** * Collects the extended Attributes from the AttributeUpdates of the given operation. */ private Map<UUID, Long> getExtendedAttributes(AttributeUpdaterOperation operation) { Collection<AttributeUpdate> updates = operation.getAttributeUpdates(); if (updates == null) { return Collections.emptyMap(); } return updates.stream() .filter(au -> !Attributes.isCoreAttribute(au.getAttributeId())) .collect(Collectors.toMap(AttributeUpdate::getAttributeId, AttributeUpdate::getValue)); }
/** * Generates an AttributeUpdate that removes a Backpointer, whether it exists or not. * * @param fromOffset The offset at which the Backpointer originates. */ private AttributeUpdate generateBackpointerRemoval(long fromOffset) { return new AttributeUpdate(getBackpointerAttributeKey(fromOffset), AttributeUpdateType.Replace, Attributes.NULL_ATTRIBUTE_VALUE); }
private void writeAttributeUpdate00(RevisionDataOutput target, AttributeUpdate au) throws IOException { target.writeUUID(au.getAttributeId()); target.writeByte(au.getUpdateType().getTypeId()); target.writeLong(au.getValue()); target.writeLong(au.getComparisonValue()); }
private void assertSame(String message, Collection<AttributeUpdate> expected, Collection<AttributeUpdate> actual) { if (expected == null || expected.size() == 0) { Assert.assertTrue(message + " Not expecting attributes.", actual == null || actual.size() == 0); return; } else { Assert.assertNotNull(message + " Expected attributes, but none found.", actual); } Assert.assertEquals(message + " Unexpected number of attributes.", expected.size(), actual.size()); val expectedIndexed = expected.stream().collect(Collectors.toMap(AttributeUpdate::getAttributeId, AttributeUpdate::getValue)); for (AttributeUpdate au : actual) { Assert.assertTrue(message + " Found extra AttributeUpdate: " + au, expectedIndexed.containsKey(au.getAttributeId())); long expectedValue = expectedIndexed.get(au.getAttributeId()); Assert.assertEquals(message + " Unexpected value for AttributeUpdate: " + au, expectedValue, au.getValue()); } }
/** * Generates an AttributeUpdate that creates a new or updates an existing Backpointer. * * @param fromOffset The offset at which the Backpointer originates. * @param toOffset The offset at which the Backpointer ends. */ private AttributeUpdate generateBackpointerUpdate(long fromOffset, long toOffset) { return new AttributeUpdate(getBackpointerAttributeKey(fromOffset), AttributeUpdateType.Replace, toOffset); }
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()); case ReplaceIfGreater: if (hasValue && u.getValue() <= previousValue) { throw new BadAttributeUpdateException(this.name, u, false, String.format("Expected greater than '%s'.", previousValue)); case ReplaceIfEquals: if (u.getComparisonValue() != previousValue || !hasValue) { throw new BadAttributeUpdateException(this.name, u, !hasValue, String.format("Expected existing value to be '%s', actual '%s'.", u.getComparisonValue(), previousValue)); case Accumulate: if (hasValue) { u.setValue(previousValue + u.getValue());
private Collection<AttributeUpdate> updateEventNumber(UUID clientId, long eventNum, long previousValue, long eventCount) { return Arrays.asList(new AttributeUpdate(clientId, AttributeUpdateType.ReplaceIfEquals, eventNum, previousValue), new AttributeUpdate(EVENT_COUNT, AttributeUpdateType.Accumulate, eventCount)); }
@GuardedBy("this") @SneakyThrows(BadAttributeUpdateException.class) private void collectAttributeValue(AttributeUpdate update, Map<UUID, Long> values) { long newValue = update.getValue(); boolean hasValue = false; long previousValue = Attributes.NULL_ATTRIBUTE_VALUE; if (this.metadata.getAttributes().containsKey(update.getAttributeId())) { hasValue = true; previousValue = this.metadata.getAttributes().get(update.getAttributeId()); switch (update.getUpdateType()) { case ReplaceIfGreater: if (hasValue && newValue <= previousValue) { if (update.getComparisonValue() != previousValue || !hasValue) { throw new BadAttributeUpdateException("Segment", update, !hasValue, String.format("ReplaceIfEquals (E=%s, A=%s)", previousValue, update.getComparisonValue())); if (hasValue) { newValue += previousValue; update.setValue(newValue); values.put(update.getAttributeId(), update.getValue());
private Collection<AttributeUpdate> createAttributeUpdates(UUID[] attributes) { return Arrays.stream(attributes) .map(a -> new AttributeUpdate(a, AttributeUpdateType.Replace, System.nanoTime())) .collect(Collectors.toList()); }
private Collection<AttributeUpdate> createAttributeUpdates() { return ATTRIBUTES.stream() .map(id -> new AttributeUpdate(id, AttributeUpdateType.Accumulate, 1)) .collect(Collectors.toList()); }
private Collection<AttributeUpdate> createAttributeUpdates() { return Arrays.stream(ATTRIBUTE_UPDATE_TYPES) .map(ut -> new AttributeUpdate(UUID.randomUUID(), ut, NEXT_ATTRIBUTE_VALUE.get())) .collect(Collectors.toList()); }
/** * Generates conditional {@link AttributeUpdate}s that update the values for Core Attributes representing the indexing * state of the Table Segment. * * @param currentOffset The offset from which this indexing batch began. This will be checked against {@link Attributes#TABLE_INDEX_OFFSET}. * @param newOffset The new offset to set for {@link Attributes#TABLE_INDEX_OFFSET}. * @param update A {@link UpdateInstructions} object to collect updates into. */ private void generateTableAttributeUpdates(long currentOffset, long newOffset, UpdateInstructions update) { // Add an Update for the TABLE_INDEX_OFFSET to indicate we have indexed everything up to this offset. Preconditions.checkArgument(currentOffset <= newOffset, "newOffset must be larger than existingOffset"); update.withAttribute(new AttributeUpdate(Attributes.TABLE_INDEX_OFFSET, AttributeUpdateType.ReplaceIfEquals, newOffset, currentOffset)); // Update Bucket and Entry counts. if (update.getEntryCountDelta() != 0) { update.withAttribute(new AttributeUpdate(Attributes.TABLE_ENTRY_COUNT, AttributeUpdateType.Accumulate, update.getEntryCountDelta())); } if (update.getBucketCountDelta() != 0) { update.withAttribute(new AttributeUpdate(Attributes.TABLE_BUCKET_COUNT, AttributeUpdateType.Accumulate, update.getBucketCountDelta())); } }