Search in sources :

Example 1 with AttributeUpdaterOperation

use of io.pravega.segmentstore.server.logs.operations.AttributeUpdaterOperation in project pravega by pravega.

the class AttributeAggregator method add.

/**
 * Adds the given SegmentOperation to the Aggregator.
 *
 * @param operation the Operation to add.
 * @throws DataCorruptionException  If the validation of the given Operation indicates a possible data corruption in
 *                                  the code (offset gaps, out-of-order operations, etc.)
 * @throws IllegalArgumentException If the validation of the given Operation indicates a possible non-corrupting bug
 *                                  in the code.
 */
@Override
public void add(SegmentOperation operation) throws DataCorruptionException {
    Exceptions.checkNotClosed(isClosed(), this);
    Preconditions.checkArgument(operation.getStreamSegmentId() == this.metadata.getId(), "Operation '%s' refers to a different Segment than this one (%s).", operation, this.metadata.getId());
    if (isSegmentDeleted()) {
        return;
    }
    boolean processed = false;
    if (operation instanceof StreamSegmentSealOperation) {
        this.state.seal();
        processed = true;
    } else if (operation instanceof AttributeUpdaterOperation) {
        AttributeUpdaterOperation op = (AttributeUpdaterOperation) operation;
        if (this.state.hasSeal()) {
            if (op.isInternal() && op.hasOnlyCoreAttributes()) {
                log.debug("{}: Ignored internal operation on sealed segment {}.", this.traceObjectId, operation);
                return;
            } else {
                throw new DataCorruptionException(String.format("Illegal operation for a sealed Segment; received '%s'.", operation));
            }
        }
        processed = this.state.include(op);
    }
    if (processed) {
        log.debug("{}: Add {}; OpCount={}.", this.traceObjectId, operation, this.state.size());
    }
}
Also used : StreamSegmentSealOperation(io.pravega.segmentstore.server.logs.operations.StreamSegmentSealOperation) AttributeUpdaterOperation(io.pravega.segmentstore.server.logs.operations.AttributeUpdaterOperation) DataCorruptionException(io.pravega.segmentstore.server.DataCorruptionException)

Example 2 with AttributeUpdaterOperation

use of io.pravega.segmentstore.server.logs.operations.AttributeUpdaterOperation in project pravega by pravega.

the class StreamSegmentContainer method processAttributeUpdaterOperation.

/**
 * Processes the given AttributeUpdateOperation with exactly one retry in case it was rejected because of an attribute
 * update failure due to the attribute value missing from the in-memory cache.
 *
 * @param operation The Operation to process.
 * @param timer     Timer for the operation.
 * @param <T>       Type of the operation.
 * @return A CompletableFuture that, when completed normally, will indicate that the Operation has been successfully
 * processed. If it failed, it will be completed with an appropriate exception.
 */
private <T extends Operation & AttributeUpdaterOperation> CompletableFuture<Void> processAttributeUpdaterOperation(T operation, TimeoutTimer timer) {
    Collection<AttributeUpdate> updates = operation.getAttributeUpdates();
    if (updates == null || updates.isEmpty()) {
        // No need for extra complicated handling.
        return addOperation(operation, timer.getRemaining());
    }
    return Futures.exceptionallyCompose(addOperation(operation, timer.getRemaining()), ex -> {
        // We only retry BadAttributeUpdateExceptions if it has the PreviousValueMissing flag set.
        ex = Exceptions.unwrap(ex);
        if (ex instanceof BadAttributeUpdateException && ((BadAttributeUpdateException) ex).isPreviousValueMissing()) {
            // Get the missing attributes and load them into the cache, then retry the operation, exactly once.
            SegmentMetadata segmentMetadata = this.metadata.getStreamSegmentMetadata(operation.getStreamSegmentId());
            Collection<AttributeId> attributeIds = updates.stream().map(AttributeUpdate::getAttributeId).filter(id -> !Attributes.isCoreAttribute(id)).collect(Collectors.toList());
            if (!attributeIds.isEmpty()) {
                // This only makes sense if a core attribute was missing.
                return getAndCacheAttributes(segmentMetadata, attributeIds, true, timer).thenComposeAsync(attributes -> {
                    // Final attempt - now that we should have the attributes cached.
                    return addOperation(operation, timer.getRemaining());
                }, this.executor);
            }
        }
        // Anything else is non-retryable; rethrow.
        return Futures.failedFuture(ex);
    });
}
Also used : UpdateableSegmentMetadata(io.pravega.segmentstore.server.UpdateableSegmentMetadata) SegmentMetadata(io.pravega.segmentstore.server.SegmentMetadata) ATTRIBUTE_SLTS_LATEST_SNAPSHOT_ID(io.pravega.segmentstore.contracts.Attributes.ATTRIBUTE_SLTS_LATEST_SNAPSHOT_ID) Storage(io.pravega.segmentstore.storage.Storage) StreamSegmentNotExistsException(io.pravega.segmentstore.contracts.StreamSegmentNotExistsException) ContainerEventProcessor(io.pravega.segmentstore.server.ContainerEventProcessor) OperationPriority(io.pravega.segmentstore.server.logs.operations.OperationPriority) SneakyThrows(lombok.SneakyThrows) Retry(io.pravega.common.util.Retry) MergeSegmentOperation(io.pravega.segmentstore.server.logs.operations.MergeSegmentOperation) RequiredArgsConstructor(lombok.RequiredArgsConstructor) ContainerMetadata(io.pravega.segmentstore.server.ContainerMetadata) SnapshotInfoStore(io.pravega.segmentstore.storage.chunklayer.SnapshotInfoStore) UpdateableSegmentMetadata(io.pravega.segmentstore.server.UpdateableSegmentMetadata) SegmentProperties(io.pravega.segmentstore.contracts.SegmentProperties) ReadIndexFactory(io.pravega.segmentstore.server.ReadIndexFactory) AttributeUpdate(io.pravega.segmentstore.contracts.AttributeUpdate) StreamSegmentSealedException(io.pravega.segmentstore.contracts.StreamSegmentSealedException) AttributeIndexFactory(io.pravega.segmentstore.server.attributes.AttributeIndexFactory) BufferView(io.pravega.common.util.BufferView) Duration(java.time.Duration) Map(java.util.Map) AbstractService(com.google.common.util.concurrent.AbstractService) Operation(io.pravega.segmentstore.server.logs.operations.Operation) StreamSegmentTruncateOperation(io.pravega.segmentstore.server.logs.operations.StreamSegmentTruncateOperation) RetryAndThrowConditionally(io.pravega.common.util.Retry.RetryAndThrowConditionally) Services(io.pravega.common.concurrent.Services) ContainerOfflineException(io.pravega.segmentstore.server.ContainerOfflineException) Attributes(io.pravega.segmentstore.contracts.Attributes) SegmentStoreMetrics(io.pravega.segmentstore.server.SegmentStoreMetrics) Collection(java.util.Collection) CompletionException(java.util.concurrent.CompletionException) Writer(io.pravega.segmentstore.server.Writer) Collectors(java.util.stream.Collectors) SimpleStorageFactory(io.pravega.segmentstore.storage.SimpleStorageFactory) Objects(java.util.Objects) List(java.util.List) Slf4j(lombok.extern.slf4j.Slf4j) SegmentContainerFactory(io.pravega.segmentstore.server.SegmentContainerFactory) ContainerTableExtension(io.pravega.segmentstore.server.tables.ContainerTableExtension) ATTRIBUTE_SLTS_LATEST_SNAPSHOT_EPOCH(io.pravega.segmentstore.contracts.Attributes.ATTRIBUTE_SLTS_LATEST_SNAPSHOT_EPOCH) WriterSegmentProcessor(io.pravega.segmentstore.server.WriterSegmentProcessor) Futures(io.pravega.common.concurrent.Futures) ReadResult(io.pravega.segmentstore.contracts.ReadResult) Getter(lombok.Getter) IllegalContainerStateException(io.pravega.segmentstore.server.IllegalContainerStateException) ExtendedChunkInfo(io.pravega.segmentstore.contracts.ExtendedChunkInfo) Exceptions(io.pravega.common.Exceptions) StorageFactory(io.pravega.segmentstore.storage.StorageFactory) AtomicBoolean(java.util.concurrent.atomic.AtomicBoolean) HashMap(java.util.HashMap) CompletableFuture(java.util.concurrent.CompletableFuture) PriorityCalculator(io.pravega.segmentstore.server.logs.PriorityCalculator) BadAttributeUpdateException(io.pravega.segmentstore.contracts.BadAttributeUpdateException) Supplier(java.util.function.Supplier) ArrayList(java.util.ArrayList) SegmentMetadata(io.pravega.segmentstore.server.SegmentMetadata) SegmentType(io.pravega.segmentstore.contracts.SegmentType) ImmutableList(com.google.common.collect.ImmutableList) AttributeUpdaterOperation(io.pravega.segmentstore.server.logs.operations.AttributeUpdaterOperation) ScheduledExecutorService(java.util.concurrent.ScheduledExecutorService) TableBasedMetadataStore(io.pravega.segmentstore.storage.metadata.TableBasedMetadataStore) AttributeIterator(io.pravega.segmentstore.server.AttributeIterator) StreamSegmentMapOperation(io.pravega.segmentstore.server.logs.operations.StreamSegmentMapOperation) Nullable(javax.annotation.Nullable) ChunkedSegmentStorage(io.pravega.segmentstore.storage.chunklayer.ChunkedSegmentStorage) LoggerHelpers(io.pravega.common.LoggerHelpers) SegmentContainerExtension(io.pravega.segmentstore.server.SegmentContainerExtension) WriterFactory(io.pravega.segmentstore.server.WriterFactory) NameUtils(io.pravega.shared.NameUtils) AttributeIndex(io.pravega.segmentstore.server.AttributeIndex) TimeoutTimer(io.pravega.common.TimeoutTimer) UpdateAttributesOperation(io.pravega.segmentstore.server.logs.operations.UpdateAttributesOperation) AttributeId(io.pravega.segmentstore.contracts.AttributeId) lombok.val(lombok.val) OperationLog(io.pravega.segmentstore.server.OperationLog) MergeStreamSegmentResult(io.pravega.segmentstore.contracts.MergeStreamSegmentResult) StreamSegmentMergedException(io.pravega.segmentstore.contracts.StreamSegmentMergedException) UtilsWrapper(io.pravega.segmentstore.storage.chunklayer.UtilsWrapper) Service(com.google.common.util.concurrent.Service) SnapshotInfo(io.pravega.segmentstore.storage.chunklayer.SnapshotInfo) Consumer(java.util.function.Consumer) DirectSegmentAccess(io.pravega.segmentstore.server.DirectSegmentAccess) ContainerAttributeIndex(io.pravega.segmentstore.server.attributes.ContainerAttributeIndex) AttributeUpdateCollection(io.pravega.segmentstore.contracts.AttributeUpdateCollection) SegmentOperation(io.pravega.segmentstore.server.SegmentOperation) StreamSegmentAppendOperation(io.pravega.segmentstore.server.logs.operations.StreamSegmentAppendOperation) OperationLogFactory(io.pravega.segmentstore.server.OperationLogFactory) SegmentContainer(io.pravega.segmentstore.server.SegmentContainer) Preconditions(com.google.common.base.Preconditions) AttributeUpdateType(io.pravega.segmentstore.contracts.AttributeUpdateType) ReadIndex(io.pravega.segmentstore.server.ReadIndex) Collections(java.util.Collections) DeleteSegmentOperation(io.pravega.segmentstore.server.logs.operations.DeleteSegmentOperation) StreamSegmentSealOperation(io.pravega.segmentstore.server.logs.operations.StreamSegmentSealOperation) AttributeUpdate(io.pravega.segmentstore.contracts.AttributeUpdate) BadAttributeUpdateException(io.pravega.segmentstore.contracts.BadAttributeUpdateException) AttributeId(io.pravega.segmentstore.contracts.AttributeId)

Example 3 with AttributeUpdaterOperation

use of io.pravega.segmentstore.server.logs.operations.AttributeUpdaterOperation in project pravega by pravega.

the class AttributeAggregatorTests method testRecovery.

/**
 * Tests the ability to resume operations after a recovery.
 */
@Test
public void testRecovery() throws Exception {
    final WriterConfig config = DEFAULT_CONFIG;
    final int attributesPerUpdate = Math.max(1, config.getFlushAttributesThreshold() / 5);
    final int updateCount = config.getFlushAttributesThreshold() * 10;
    @Cleanup TestContext context = new TestContext(config);
    // Generate some data.
    val operations = new ArrayList<AttributeUpdaterOperation>();
    for (int i = 0; i < updateCount; i++) {
        // Add another operation.
        AttributeUpdaterOperation op = i % 2 == 0 ? generateAppendAndUpdateMetadata(attributesPerUpdate, context) : generateUpdateAttributesAndUpdateMetadata(attributesPerUpdate, context);
        operations.add(op);
    }
    // include all operations with indices less than or equal to recoveryId and observe the results.
    for (int recoveryId = 0; recoveryId < operations.size(); recoveryId++) {
        long lastPersistedSeqNo = context.segmentMetadata.getAttributes().getOrDefault(Attributes.ATTRIBUTE_SEGMENT_PERSIST_SEQ_NO, Operation.NO_SEQUENCE_NUMBER);
        val outstandingAttributes = new HashSet<AttributeId>();
        val firstOutstandingSeqNo = new AtomicLong(Operation.NO_SEQUENCE_NUMBER);
        val lastOutstandingSeqNo = new AtomicLong(Operation.NO_SEQUENCE_NUMBER);
        @Cleanup val aggregator = context.createAggregator();
        val expectedAttributes = new HashMap<AttributeId, Long>();
        for (int i = 0; i <= recoveryId; i++) {
            AttributeUpdaterOperation op = operations.get(i);
            // Collect the latest values from this update.
            op.getAttributeUpdates().stream().filter(au -> !Attributes.isCoreAttribute(au.getAttributeId())).forEach(au -> expectedAttributes.put(au.getAttributeId(), au.getValue()));
            aggregator.add(op);
            // We only expect to process an op if its SeqNo is beyond the last one we committed.
            boolean expectedToProcess = op.getSequenceNumber() > lastPersistedSeqNo;
            if (expectedToProcess) {
                addExtendedAttributes(op, outstandingAttributes);
                firstOutstandingSeqNo.compareAndSet(Operation.NO_SEQUENCE_NUMBER, op.getSequenceNumber());
                lastOutstandingSeqNo.set(op.getSequenceNumber());
            }
            Assert.assertEquals("Unexpected LUSN.", firstOutstandingSeqNo.get(), aggregator.getLowestUncommittedSequenceNumber());
            boolean expectFlush = outstandingAttributes.size() >= config.getFlushAttributesThreshold();
            Assert.assertEquals("Unexpected value returned by mustFlush() (count threshold).", expectFlush, aggregator.mustFlush());
            if (expectFlush) {
                // Call flush() and inspect the result.
                WriterFlushResult flushResult = aggregator.flush(TIMEOUT).join();
                Assert.assertEquals("Not all attributes were flushed (count threshold).", outstandingAttributes.size(), flushResult.getFlushedAttributes());
                // We want to verify just those attributes that we flushed, not all of them (not all may be in yet).
                AssertExtensions.assertMapEquals("Unexpected attributes stored in AttributeIndex.", expectedAttributes, context.dataSource.getPersistedAttributes(SEGMENT_ID));
                checkAutoAttributesEventual(lastOutstandingSeqNo.get(), context);
                outstandingAttributes.clear();
                firstOutstandingSeqNo.set(Operation.NO_SEQUENCE_NUMBER);
                lastOutstandingSeqNo.set(Operation.NO_SEQUENCE_NUMBER);
            }
        }
        // We have reached the end. Flush the rest and perform a full check.
        if (recoveryId == operations.size() - 1) {
            aggregator.add(generateSealAndUpdateMetadata(context));
            aggregator.flush(TIMEOUT).join();
            checkAttributes(context);
            checkAutoAttributesEventual(lastOutstandingSeqNo.get(), context);
        }
    }
}
Also used : lombok.val(lombok.val) StreamSegmentNotExistsException(io.pravega.segmentstore.contracts.StreamSegmentNotExistsException) SneakyThrows(lombok.SneakyThrows) AssertExtensions(io.pravega.test.common.AssertExtensions) RequiredArgsConstructor(lombok.RequiredArgsConstructor) Cleanup(lombok.Cleanup) Random(java.util.Random) UpdateableSegmentMetadata(io.pravega.segmentstore.server.UpdateableSegmentMetadata) AttributeUpdate(io.pravega.segmentstore.contracts.AttributeUpdate) StreamSegmentSealedException(io.pravega.segmentstore.contracts.StreamSegmentSealedException) Duration(java.time.Duration) Operation(io.pravega.segmentstore.server.logs.operations.Operation) WriterFlushResult(io.pravega.segmentstore.server.WriterFlushResult) StreamSegmentTruncateOperation(io.pravega.segmentstore.server.logs.operations.StreamSegmentTruncateOperation) Attributes(io.pravega.segmentstore.contracts.Attributes) Set(java.util.Set) Collectors(java.util.stream.Collectors) ErrorInjector(io.pravega.test.common.ErrorInjector) List(java.util.List) ByteArraySegment(io.pravega.common.util.ByteArraySegment) ThreadPooledTestSuite(io.pravega.test.common.ThreadPooledTestSuite) IntStream(java.util.stream.IntStream) MetadataBuilder(io.pravega.segmentstore.server.MetadataBuilder) HashMap(java.util.HashMap) Callable(java.util.concurrent.Callable) CompletableFuture(java.util.concurrent.CompletableFuture) ArrayList(java.util.ArrayList) HashSet(java.util.HashSet) UpdateableContainerMetadata(io.pravega.segmentstore.server.UpdateableContainerMetadata) AttributeUpdaterOperation(io.pravega.segmentstore.server.logs.operations.AttributeUpdaterOperation) Timeout(org.junit.rules.Timeout) ManualTimer(io.pravega.segmentstore.server.ManualTimer) UpdateAttributesOperation(io.pravega.segmentstore.server.logs.operations.UpdateAttributesOperation) AttributeId(io.pravega.segmentstore.contracts.AttributeId) IntentionalException(io.pravega.test.common.IntentionalException) lombok.val(lombok.val) Test(org.junit.Test) TimeUnit(java.util.concurrent.TimeUnit) AtomicLong(java.util.concurrent.atomic.AtomicLong) AttributeUpdateCollection(io.pravega.segmentstore.contracts.AttributeUpdateCollection) Rule(org.junit.Rule) SegmentOperation(io.pravega.segmentstore.server.SegmentOperation) CachedStreamSegmentAppendOperation(io.pravega.segmentstore.server.logs.operations.CachedStreamSegmentAppendOperation) StorageOperation(io.pravega.segmentstore.server.logs.operations.StorageOperation) StreamSegmentAppendOperation(io.pravega.segmentstore.server.logs.operations.StreamSegmentAppendOperation) AttributeUpdateType(io.pravega.segmentstore.contracts.AttributeUpdateType) DataCorruptionException(io.pravega.segmentstore.server.DataCorruptionException) Assert(org.junit.Assert) Collections(java.util.Collections) StreamSegmentSealOperation(io.pravega.segmentstore.server.logs.operations.StreamSegmentSealOperation) HashMap(java.util.HashMap) AttributeUpdaterOperation(io.pravega.segmentstore.server.logs.operations.AttributeUpdaterOperation) ArrayList(java.util.ArrayList) WriterFlushResult(io.pravega.segmentstore.server.WriterFlushResult) Cleanup(lombok.Cleanup) AtomicLong(java.util.concurrent.atomic.AtomicLong) HashSet(java.util.HashSet) Test(org.junit.Test)

Example 4 with AttributeUpdaterOperation

use of io.pravega.segmentstore.server.logs.operations.AttributeUpdaterOperation in project pravega by pravega.

the class AttributeAggregatorTests method testFlushWithGenericErrors.

/**
 * Tests {@link AttributeAggregator#flush} in the presence of generic errors.
 */
@Test
public void testFlushWithGenericErrors() throws Exception {
    final WriterConfig config = DEFAULT_CONFIG;
    @Cleanup TestContext context = new TestContext(config);
    // Add a single operation, which alone should trigger the flush.
    AttributeUpdaterOperation op = generateUpdateAttributesAndUpdateMetadata(config.getFlushAttributesThreshold(), context);
    context.aggregator.add(op);
    Assert.assertTrue("Unexpected result from mustFlush().", context.aggregator.mustFlush());
    // Cause the attribute update to fail, and validate that the error is bubbled up.
    context.dataSource.setPersistAttributesErrorInjector(new ErrorInjector<>(i -> true, IntentionalException::new));
    AssertExtensions.assertSuppliedFutureThrows("Expected flush() to have failed.", () -> context.aggregator.flush(TIMEOUT), ex -> ex instanceof IntentionalException);
    Assert.assertTrue("Unexpected result from mustFlush() after failed attempt.", context.aggregator.mustFlush());
    checkAutoAttributes(Operation.NO_SEQUENCE_NUMBER, context);
    // Now try again, without errors.
    context.dataSource.setPersistAttributesErrorInjector(null);
    val result = context.aggregator.flush(TIMEOUT).join();
    Assert.assertEquals("Unexpected number of attributes flushed", op.getAttributeUpdates().size() - 1, // Subtract 1 for core attributes.
    result.getFlushedAttributes());
    checkAttributes(context);
    checkAutoAttributesEventual(op.getSequenceNumber(), context);
}
Also used : StreamSegmentNotExistsException(io.pravega.segmentstore.contracts.StreamSegmentNotExistsException) SneakyThrows(lombok.SneakyThrows) AssertExtensions(io.pravega.test.common.AssertExtensions) RequiredArgsConstructor(lombok.RequiredArgsConstructor) Cleanup(lombok.Cleanup) Random(java.util.Random) UpdateableSegmentMetadata(io.pravega.segmentstore.server.UpdateableSegmentMetadata) AttributeUpdate(io.pravega.segmentstore.contracts.AttributeUpdate) StreamSegmentSealedException(io.pravega.segmentstore.contracts.StreamSegmentSealedException) Duration(java.time.Duration) Operation(io.pravega.segmentstore.server.logs.operations.Operation) WriterFlushResult(io.pravega.segmentstore.server.WriterFlushResult) StreamSegmentTruncateOperation(io.pravega.segmentstore.server.logs.operations.StreamSegmentTruncateOperation) Attributes(io.pravega.segmentstore.contracts.Attributes) Set(java.util.Set) Collectors(java.util.stream.Collectors) ErrorInjector(io.pravega.test.common.ErrorInjector) List(java.util.List) ByteArraySegment(io.pravega.common.util.ByteArraySegment) ThreadPooledTestSuite(io.pravega.test.common.ThreadPooledTestSuite) IntStream(java.util.stream.IntStream) MetadataBuilder(io.pravega.segmentstore.server.MetadataBuilder) HashMap(java.util.HashMap) Callable(java.util.concurrent.Callable) CompletableFuture(java.util.concurrent.CompletableFuture) ArrayList(java.util.ArrayList) HashSet(java.util.HashSet) UpdateableContainerMetadata(io.pravega.segmentstore.server.UpdateableContainerMetadata) AttributeUpdaterOperation(io.pravega.segmentstore.server.logs.operations.AttributeUpdaterOperation) Timeout(org.junit.rules.Timeout) ManualTimer(io.pravega.segmentstore.server.ManualTimer) UpdateAttributesOperation(io.pravega.segmentstore.server.logs.operations.UpdateAttributesOperation) AttributeId(io.pravega.segmentstore.contracts.AttributeId) IntentionalException(io.pravega.test.common.IntentionalException) lombok.val(lombok.val) Test(org.junit.Test) TimeUnit(java.util.concurrent.TimeUnit) AtomicLong(java.util.concurrent.atomic.AtomicLong) AttributeUpdateCollection(io.pravega.segmentstore.contracts.AttributeUpdateCollection) Rule(org.junit.Rule) SegmentOperation(io.pravega.segmentstore.server.SegmentOperation) CachedStreamSegmentAppendOperation(io.pravega.segmentstore.server.logs.operations.CachedStreamSegmentAppendOperation) StorageOperation(io.pravega.segmentstore.server.logs.operations.StorageOperation) StreamSegmentAppendOperation(io.pravega.segmentstore.server.logs.operations.StreamSegmentAppendOperation) AttributeUpdateType(io.pravega.segmentstore.contracts.AttributeUpdateType) DataCorruptionException(io.pravega.segmentstore.server.DataCorruptionException) Assert(org.junit.Assert) Collections(java.util.Collections) StreamSegmentSealOperation(io.pravega.segmentstore.server.logs.operations.StreamSegmentSealOperation) lombok.val(lombok.val) AttributeUpdaterOperation(io.pravega.segmentstore.server.logs.operations.AttributeUpdaterOperation) Cleanup(lombok.Cleanup) IntentionalException(io.pravega.test.common.IntentionalException) Test(org.junit.Test)

Example 5 with AttributeUpdaterOperation

use of io.pravega.segmentstore.server.logs.operations.AttributeUpdaterOperation in project pravega by pravega.

the class AttributeAggregatorTests method testRecoverySealedSegment.

/**
 * Tests the ability to resume operations after a recovery on a sealed segment.
 */
@Test
public void testRecoverySealedSegment() throws Exception {
    final WriterConfig config = DEFAULT_CONFIG;
    final int attributesPerUpdate = 1;
    final int updateCount = config.getFlushAttributesThreshold() - 1;
    @Cleanup TestContext context = new TestContext(config);
    val outstandingAttributes = new HashSet<AttributeId>();
    val firstOutstandingSeqNo = new AtomicLong(Operation.NO_SEQUENCE_NUMBER);
    val lastOutstandingSeqNo = new AtomicLong(Operation.NO_SEQUENCE_NUMBER);
    // Generate a few operations.
    val operations = new ArrayList<SegmentOperation>();
    for (int i = 0; i < updateCount; i++) {
        // Add another operation.
        AttributeUpdaterOperation op = i % 2 == 0 ? generateAppendAndUpdateMetadata(attributesPerUpdate, context) : generateUpdateAttributesAndUpdateMetadata(attributesPerUpdate, context);
        operations.add(op);
        addExtendedAttributes(op, outstandingAttributes);
        firstOutstandingSeqNo.compareAndSet(Operation.NO_SEQUENCE_NUMBER, op.getSequenceNumber());
        lastOutstandingSeqNo.set(op.getSequenceNumber());
    }
    operations.add(generateSealAndUpdateMetadata(context));
    // Add them to the first aggregator, then flush them.
    for (val op : operations) {
        context.aggregator.add(op);
    }
    val flushResult = context.aggregator.flush(TIMEOUT).join();
    Assert.assertEquals("Not all attributes were flushed.", outstandingAttributes.size(), flushResult.getFlushedAttributes());
    checkAttributes(context);
    checkAutoAttributesEventual(lastOutstandingSeqNo.get(), context);
    // Create a second (recovered) aggregator and re-add the operations.
    @Cleanup val aggregator2 = context.createAggregator();
    for (val op : operations) {
        aggregator2.add(op);
    }
    Assert.assertEquals("Not expecting any operation outstanding in the second aggregator.", Operation.NO_SEQUENCE_NUMBER, aggregator2.getLowestUncommittedSequenceNumber());
    Assert.assertTrue("Expected a flush of the second aggregator.", aggregator2.mustFlush());
    val flushResult2 = aggregator2.flush(TIMEOUT).join();
    Assert.assertEquals("Not expecting any attributes to be flushed.", 0, flushResult2.getFlushedAttributes());
    checkAttributes(context);
    checkAutoAttributesEventual(lastOutstandingSeqNo.get(), context);
    // Create a third (recovered) aggregator, but clear out the auto-attributes.
    context.segmentMetadata.updateAttributes(Collections.singletonMap(Attributes.ATTRIBUTE_SEGMENT_PERSIST_SEQ_NO, Attributes.NULL_ATTRIBUTE_VALUE));
    @Cleanup val aggregator3 = context.createAggregator();
    for (val op : operations) {
        aggregator3.add(op);
    }
    Assert.assertEquals("Unexpected LUSN for the third aggregator.", firstOutstandingSeqNo.get(), aggregator3.getLowestUncommittedSequenceNumber());
    Assert.assertTrue("Expected a flush of the third aggregator.", aggregator3.mustFlush());
    val flushResult3 = aggregator2.flush(TIMEOUT).join();
    Assert.assertEquals("Not expecting any attributes to be flushed.", 0, flushResult3.getFlushedAttributes());
    checkAttributes(context);
    // Segment is sealed, so it couldn't have updated this value.
    checkAutoAttributesEventual(Operation.NO_SEQUENCE_NUMBER, context);
}
Also used : lombok.val(lombok.val) AtomicLong(java.util.concurrent.atomic.AtomicLong) AttributeUpdaterOperation(io.pravega.segmentstore.server.logs.operations.AttributeUpdaterOperation) ArrayList(java.util.ArrayList) Cleanup(lombok.Cleanup) HashSet(java.util.HashSet) Test(org.junit.Test)

Aggregations

AttributeUpdaterOperation (io.pravega.segmentstore.server.logs.operations.AttributeUpdaterOperation)8 HashSet (java.util.HashSet)6 AtomicLong (java.util.concurrent.atomic.AtomicLong)6 Cleanup (lombok.Cleanup)6 lombok.val (lombok.val)6 Test (org.junit.Test)6 StreamSegmentSealedException (io.pravega.segmentstore.contracts.StreamSegmentSealedException)4 WriterFlushResult (io.pravega.segmentstore.server.WriterFlushResult)4 StreamSegmentSealOperation (io.pravega.segmentstore.server.logs.operations.StreamSegmentSealOperation)4 AttributeId (io.pravega.segmentstore.contracts.AttributeId)3 AttributeUpdate (io.pravega.segmentstore.contracts.AttributeUpdate)3 AttributeUpdateCollection (io.pravega.segmentstore.contracts.AttributeUpdateCollection)3 AttributeUpdateType (io.pravega.segmentstore.contracts.AttributeUpdateType)3 Attributes (io.pravega.segmentstore.contracts.Attributes)3 StreamSegmentNotExistsException (io.pravega.segmentstore.contracts.StreamSegmentNotExistsException)3 DataCorruptionException (io.pravega.segmentstore.server.DataCorruptionException)3 ArrayList (java.util.ArrayList)3 ByteArraySegment (io.pravega.common.util.ByteArraySegment)2 ManualTimer (io.pravega.segmentstore.server.ManualTimer)2 MetadataBuilder (io.pravega.segmentstore.server.MetadataBuilder)2