Search in sources :

Example 11 with CommittingTransactionsRecord

use of io.pravega.controller.store.stream.records.CommittingTransactionsRecord in project pravega by pravega.

the class StreamTestBase method segmentQueriesDuringRollingTxn.

@Test(timeout = 30000L)
public void segmentQueriesDuringRollingTxn() {
    OperationContext context = getContext();
    // start scale and perform `getSegment`, `getActiveEpoch` and `getEpoch` during different phases of scale
    int startingSegmentNumber = new Random().nextInt(2000);
    long time = System.currentTimeMillis();
    Stream stream = createStream("scope", "stream" + startingSegmentNumber, time, 5, startingSegmentNumber);
    StreamSegmentRecord segment = stream.getSegment(startingSegmentNumber, context).join();
    assertEquals(segment.segmentId(), startingSegmentNumber + 0L);
    assertEquals(segment.getKeyStart(), 0, 0);
    assertEquals(segment.getKeyEnd(), 1.0 / 5, 0);
    createAndCommitTransaction(stream, 0, 0L);
    List<Map.Entry<Double, Double>> newRanges = new ArrayList<>();
    newRanges.add(new AbstractMap.SimpleEntry<>(0.0, 0.5));
    newRanges.add(new AbstractMap.SimpleEntry<>(0.5, 1.0));
    time = time + 1;
    scaleStream(stream, time, Lists.newArrayList(startingSegmentNumber + 0L, startingSegmentNumber + 1L, startingSegmentNumber + 2L, startingSegmentNumber + 3L, startingSegmentNumber + 4L), newRanges, Collections.emptyMap());
    List<StreamSegmentRecord> activeSegmentsBefore = stream.getActiveSegments(context).join();
    // start commit transactions
    VersionedMetadata<CommittingTransactionsRecord> ctr = stream.startCommittingTransactions(100, context).join().getKey();
    stream.getVersionedState(context).thenCompose(s -> stream.updateVersionedState(s, State.COMMITTING_TXN, context)).join();
    // start rolling transaction
    ctr = stream.startRollingTxn(1, ctr, context).join();
    List<StreamSegmentRecord> activeSegments1 = stream.getActiveSegments(context).join();
    assertEquals(activeSegments1, activeSegmentsBefore);
    Map<StreamSegmentRecord, List<Long>> successorsWithPredecessors = stream.getSuccessorsWithPredecessors(computeSegmentId(startingSegmentNumber + 5, 1), context).join();
    assertTrue(successorsWithPredecessors.isEmpty());
    // rolling txn create duplicate epochs. We should be able to get successors and predecessors after this step.
    time = time + 1;
    stream.rollingTxnCreateDuplicateEpochs(Collections.emptyMap(), time, ctr, context).join();
    activeSegments1 = stream.getActiveSegments(context).join();
    assertEquals(activeSegments1, activeSegmentsBefore);
    successorsWithPredecessors = stream.getSuccessorsWithPredecessors(computeSegmentId(startingSegmentNumber + 5, 1), context).join();
    Set<StreamSegmentRecord> successors = successorsWithPredecessors.keySet();
    assertEquals(3, successors.size());
    assertTrue(successors.stream().allMatch(x -> x.getCreationEpoch() == 2));
    assertTrue(successors.stream().anyMatch(x -> x.getSegmentNumber() == startingSegmentNumber + 0));
    assertTrue(successors.stream().anyMatch(x -> x.getSegmentNumber() == startingSegmentNumber + 1));
    assertTrue(successors.stream().anyMatch(x -> x.getSegmentNumber() == startingSegmentNumber + 2));
    successorsWithPredecessors = stream.getSuccessorsWithPredecessors(computeSegmentId(startingSegmentNumber + 0, 2), context).join();
    successors = successorsWithPredecessors.keySet();
    assertEquals(1, successors.size());
    assertTrue(successors.stream().allMatch(x -> x.segmentId() == computeSegmentId(startingSegmentNumber + 5, 3)));
    stream.completeRollingTxn(Collections.emptyMap(), ctr, context).join();
    stream.completeCommittingTransactions(ctr, context, Collections.emptyMap()).join();
}
Also used : TestOperationContext(io.pravega.controller.store.TestOperationContext) StreamSegmentRecord(io.pravega.controller.store.stream.records.StreamSegmentRecord) AssertExtensions(io.pravega.test.common.AssertExtensions) Random(java.util.Random) StreamConfiguration(io.pravega.client.stream.StreamConfiguration) VersionedMetadata(io.pravega.controller.store.VersionedMetadata) Mockito.anyBoolean(org.mockito.Mockito.anyBoolean) Map(java.util.Map) After(org.junit.After) Mockito.doAnswer(org.mockito.Mockito.doAnswer) EpochTransitionRecord(io.pravega.controller.store.stream.records.EpochTransitionRecord) StreamTruncationRecord(io.pravega.controller.store.stream.records.StreamTruncationRecord) ImmutableMap(com.google.common.collect.ImmutableMap) Set(java.util.Set) ActiveTxnRecord(io.pravega.controller.store.stream.records.ActiveTxnRecord) UUID(java.util.UUID) Collectors(java.util.stream.Collectors) List(java.util.List) Optional(java.util.Optional) HistoryTimeSeries(io.pravega.controller.store.stream.records.HistoryTimeSeries) Futures(io.pravega.common.concurrent.Futures) ArgumentMatchers.any(org.mockito.ArgumentMatchers.any) ArgumentMatchers.anyLong(org.mockito.ArgumentMatchers.anyLong) CommittingTransactionsRecord(io.pravega.controller.store.stream.records.CommittingTransactionsRecord) NameUtils.computeSegmentId(io.pravega.shared.NameUtils.computeSegmentId) Exceptions(io.pravega.common.Exceptions) AtomicBoolean(java.util.concurrent.atomic.AtomicBoolean) HashMap(java.util.HashMap) Mockito.spy(org.mockito.Mockito.spy) AtomicReference(java.util.concurrent.atomic.AtomicReference) Supplier(java.util.function.Supplier) ArrayList(java.util.ArrayList) HashSet(java.util.HashSet) Lists(com.google.common.collect.Lists) ScheduledExecutorService(java.util.concurrent.ScheduledExecutorService) LinkedList(java.util.LinkedList) SealedSegmentsMapShard(io.pravega.controller.store.stream.records.SealedSegmentsMapShard) Before(org.junit.Before) NameUtils.getEpoch(io.pravega.shared.NameUtils.getEpoch) NameUtils(io.pravega.shared.NameUtils) WriterMark(io.pravega.controller.store.stream.records.WriterMark) Assert.assertTrue(org.junit.Assert.assertTrue) Test(org.junit.Test) Mockito.times(org.mockito.Mockito.times) Assert.assertNotEquals(org.junit.Assert.assertNotEquals) Mockito.verify(org.mockito.Mockito.verify) AtomicLong(java.util.concurrent.atomic.AtomicLong) StreamConfigurationRecord(io.pravega.controller.store.stream.records.StreamConfigurationRecord) AbstractMap(java.util.AbstractMap) EpochRecord(io.pravega.controller.store.stream.records.EpochRecord) Version(io.pravega.controller.store.Version) TestOperationContext(io.pravega.controller.store.TestOperationContext) ExecutorServiceHelpers(io.pravega.common.concurrent.ExecutorServiceHelpers) Collections(java.util.Collections) ScalingPolicy(io.pravega.client.stream.ScalingPolicy) Assert.assertEquals(org.junit.Assert.assertEquals) ArgumentMatchers.anyString(org.mockito.ArgumentMatchers.anyString) CommittingTransactionsRecord(io.pravega.controller.store.stream.records.CommittingTransactionsRecord) ArrayList(java.util.ArrayList) AbstractMap(java.util.AbstractMap) StreamSegmentRecord(io.pravega.controller.store.stream.records.StreamSegmentRecord) Random(java.util.Random) List(java.util.List) ArrayList(java.util.ArrayList) LinkedList(java.util.LinkedList) Test(org.junit.Test)

Example 12 with CommittingTransactionsRecord

use of io.pravega.controller.store.stream.records.CommittingTransactionsRecord in project pravega by pravega.

the class RequestHandlersTest method concurrentRollingTxnCommit.

private void concurrentRollingTxnCommit(String stream, String func, boolean expectFailureOnFirstJob, Predicate<Throwable> firstExceptionPredicate, Map<String, Integer> invocationCount, int expectedVersion) {
    StreamMetadataStore streamStore1 = getStore();
    StreamMetadataStore streamStore1Spied = spy(getStore());
    StreamConfiguration config = StreamConfiguration.builder().scalingPolicy(ScalingPolicy.byEventRate(1, 2, 1)).build();
    streamStore1.createStream(scope, stream, config, System.currentTimeMillis(), null, executor).join();
    streamStore1.setState(scope, stream, State.ACTIVE, null, executor).join();
    StreamMetadataStore streamStore2 = getStore();
    CommitRequestHandler requestHandler1 = new CommitRequestHandler(streamStore1Spied, streamMetadataTasks, streamTransactionMetadataTasks, bucketStore, executor);
    CommitRequestHandler requestHandler2 = new CommitRequestHandler(streamStore2, streamMetadataTasks, streamTransactionMetadataTasks, bucketStore, executor);
    ScaleOperationTask scaleRequesthandler = new ScaleOperationTask(streamMetadataTasks, streamStore2, executor);
    // create txn on epoch 0 and set it to committing
    UUID txnId = streamStore1.generateTransactionId(scope, stream, null, executor).join();
    VersionedTransactionData txnEpoch0 = streamStore1.createTransaction(scope, stream, txnId, 1000L, 10000L, null, executor).join();
    streamStore1.sealTransaction(scope, stream, txnId, true, Optional.of(txnEpoch0.getVersion()), "", Long.MIN_VALUE, null, executor).join();
    // perform scale
    ScaleOpEvent event = new ScaleOpEvent(scope, stream, Lists.newArrayList(0L), Lists.newArrayList(new AbstractMap.SimpleEntry<>(0.0, 1.0)), false, System.currentTimeMillis(), System.currentTimeMillis());
    scaleRequesthandler.execute(event).join();
    // regular commit
    // start commit transactions
    CompletableFuture<Void> wait = new CompletableFuture<>();
    CompletableFuture<Void> signal = new CompletableFuture<>();
    // test rolling transaction --> since transaction on epoch 0 is committing, it will get committed first.
    CommitEvent commitOnEpoch0 = new CommitEvent(scope, stream, 0);
    setMockCommitTxnLatch(streamStore1, streamStore1Spied, func, signal, wait);
    // start rolling txn
    // stall rolling transaction in different stages
    CompletableFuture<Void> future1Rolling = CompletableFuture.completedFuture(null).thenComposeAsync(v -> requestHandler1.execute(commitOnEpoch0), executor);
    signal.join();
    requestHandler2.execute(commitOnEpoch0).join();
    wait.complete(null);
    if (expectFailureOnFirstJob) {
        AssertExtensions.assertSuppliedFutureThrows("first commit should fail", () -> future1Rolling, firstExceptionPredicate);
        verify(streamStore1Spied, times(invocationCount.get("startCommitTransactions"))).startCommitTransactions(anyString(), anyString(), anyInt(), any(), any());
        verify(streamStore1Spied, times(invocationCount.get("startRollingTxn"))).startRollingTxn(anyString(), anyString(), anyInt(), any(), any(), any());
        verify(streamStore1Spied, times(invocationCount.get("rollingTxnCreateDuplicateEpochs"))).rollingTxnCreateDuplicateEpochs(anyString(), anyString(), any(), anyLong(), any(), any(), any());
        verify(streamStore1Spied, times(invocationCount.get("completeRollingTxn"))).completeRollingTxn(anyString(), anyString(), any(), any(), any(), any());
        verify(streamStore1Spied, times(invocationCount.get("completeCommitTransactions"))).completeCommitTransactions(anyString(), anyString(), any(), any(), any(), any());
        verify(streamStore1Spied, times(invocationCount.get("updateVersionedState"))).updateVersionedState(anyString(), anyString(), any(), any(), any(), any());
    } else {
        future1Rolling.join();
    }
    // validate rolling txn done and first job has updated the CTR with new txn record
    VersionedMetadata<CommittingTransactionsRecord> versioned = streamStore1.getVersionedCommittingTransactionsRecord(scope, stream, null, executor).join();
    assertEquals(CommittingTransactionsRecord.EMPTY, versioned.getObject());
    assertEquals(expectedVersion, getVersionNumber(versioned.getVersion()));
    assertEquals(3, streamStore1.getActiveEpoch(scope, stream, null, true, executor).join().getEpoch());
    assertEquals(State.ACTIVE, streamStore1.getState(scope, stream, true, null, executor).join());
}
Also used : CommittingTransactionsRecord(io.pravega.controller.store.stream.records.CommittingTransactionsRecord) StreamMetadataStore(io.pravega.controller.store.stream.StreamMetadataStore) ScaleOperationTask(io.pravega.controller.server.eventProcessor.requesthandlers.ScaleOperationTask) VersionedTransactionData(io.pravega.controller.store.stream.VersionedTransactionData) CommitRequestHandler(io.pravega.controller.server.eventProcessor.requesthandlers.CommitRequestHandler) ScaleOpEvent(io.pravega.shared.controller.event.ScaleOpEvent) CompletableFuture(java.util.concurrent.CompletableFuture) StreamConfiguration(io.pravega.client.stream.StreamConfiguration) CommitEvent(io.pravega.shared.controller.event.CommitEvent) UUID(java.util.UUID)

Example 13 with CommittingTransactionsRecord

use of io.pravega.controller.store.stream.records.CommittingTransactionsRecord in project pravega by pravega.

the class CommitRequestHandler method commitTransactions.

/**
 * This method loops over each transaction in the list, and commits them in order
 * At the end of this method's execution, all transactions in the list would have committed into given list of segments.
 */
private CompletableFuture<Void> commitTransactions(CommitTxnContext commitContext, VersionedMetadata<CommittingTransactionsRecord> txnRecord, List<Long> segments) {
    // Chain all transaction commit futures one after the other. This will ensure that order of commit
    // if honoured and is based on the order in the list.
    List<UUID> transactionsToCommit = txnRecord.getObject().getTransactionsToCommit();
    boolean noteTime = commitContext.writerMarks.size() > 0;
    Timer segMergeTimer = new Timer();
    return streamMetadataTasks.mergeTxnSegmentsIntoStreamSegments(commitContext.scope, commitContext.stream, segments, transactionsToCommit, commitContext.context.getRequestId()).thenCompose(segmentOffsets -> {
        TransactionMetrics.getInstance().commitTransactionSegments(segMergeTimer.getElapsed());
        if (noteTime) {
            for (int i = 0; i < transactionsToCommit.size(); i++) {
                int index = i;
                val txnOffsets = segmentOffsets.entrySet().stream().collect(Collectors.toMap(Map.Entry::getKey, x -> x.getValue().get(index)));
                val txnId = transactionsToCommit.get(i);
                String writerId = commitContext.txnIdToWriterId.get(txnId);
                if (!Strings.isNullOrEmpty(writerId) && commitContext.writerMarks.get(writerId).getTransactionId().equals(txnId)) {
                    TxnWriterMark mark = commitContext.writerMarks.get(writerId);
                    commitContext.writerMarks.put(writerId, new TxnWriterMark(mark.getTimestamp(), txnOffsets, mark.getTransactionId()));
                }
            }
            return bucketStore.addStreamToBucketStore(BucketStore.ServiceType.WatermarkingService, commitContext.scope, commitContext.stream, executor);
        }
        return CompletableFuture.completedFuture(null);
    });
}
Also used : lombok.val(lombok.val) CommitEvent(io.pravega.shared.controller.event.CommitEvent) OperationContext(io.pravega.controller.store.stream.OperationContext) TransactionMetrics(io.pravega.controller.metrics.TransactionMetrics) CommittingTransactionsRecord(io.pravega.controller.store.stream.records.CommittingTransactionsRecord) NameUtils.computeSegmentId(io.pravega.shared.NameUtils.computeSegmentId) Exceptions(io.pravega.common.Exceptions) LoggerFactory(org.slf4j.LoggerFactory) HashMap(java.util.HashMap) CompletableFuture(java.util.concurrent.CompletableFuture) AtomicReference(java.util.concurrent.atomic.AtomicReference) ArrayList(java.util.ArrayList) BucketStore(io.pravega.controller.store.stream.BucketStore) TagLogger(io.pravega.common.tracing.TagLogger) VersionedMetadata(io.pravega.controller.store.VersionedMetadata) StoreException(io.pravega.controller.store.stream.StoreException) Map(java.util.Map) ScheduledExecutorService(java.util.concurrent.ScheduledExecutorService) StreamMetadataTasks(io.pravega.controller.task.Stream.StreamMetadataTasks) ImmutableMap(com.google.common.collect.ImmutableMap) lombok.val(lombok.val) BlockingQueue(java.util.concurrent.BlockingQueue) UUID(java.util.UUID) Strings(org.apache.curator.shaded.com.google.common.base.Strings) Timer(io.pravega.common.Timer) Collectors(java.util.stream.Collectors) List(java.util.List) EpochRecord(io.pravega.controller.store.stream.records.EpochRecord) TxnWriterMark(io.pravega.controller.store.stream.TxnWriterMark) StreamTransactionMetadataTasks(io.pravega.controller.task.Stream.StreamTransactionMetadataTasks) Preconditions(com.google.common.base.Preconditions) State(io.pravega.controller.store.stream.State) VisibleForTesting(com.google.common.annotations.VisibleForTesting) StreamMetadataStore(io.pravega.controller.store.stream.StreamMetadataStore) AllArgsConstructor(lombok.AllArgsConstructor) ScalingPolicy(io.pravega.client.stream.ScalingPolicy) Futures(io.pravega.common.concurrent.Futures) TxnWriterMark(io.pravega.controller.store.stream.TxnWriterMark) Timer(io.pravega.common.Timer) UUID(java.util.UUID) HashMap(java.util.HashMap) Map(java.util.Map) ImmutableMap(com.google.common.collect.ImmutableMap)

Example 14 with CommittingTransactionsRecord

use of io.pravega.controller.store.stream.records.CommittingTransactionsRecord in project pravega by pravega.

the class PersistentStreamBase method startCommittingTransactions.

@Override
public CompletableFuture<Map.Entry<VersionedMetadata<CommittingTransactionsRecord>, List<VersionedTransactionData>>> startCommittingTransactions(int limit, OperationContext context) {
    Preconditions.checkNotNull(context, "Operation context cannot be null");
    return getVersionedCommitTransactionsRecord(context).thenCompose(versioned -> {
        if (versioned.getObject().equals(CommittingTransactionsRecord.EMPTY)) {
            return getOrderedCommittingTxnInLowestEpoch(limit, context).thenCompose(list -> {
                if (list.isEmpty()) {
                    List<VersionedTransactionData> emptyTransactionData = new LinkedList<>();
                    return CompletableFuture.completedFuture(new SimpleEntry<>(versioned, emptyTransactionData));
                } else {
                    ImmutableList.Builder<UUID> txIdList = ImmutableList.builder();
                    list.forEach(x -> {
                        txIdList.add(x.getId());
                    });
                    List<Long> positions = list.stream().map(VersionedTransactionData::getCommitOrder).collect(Collectors.toList());
                    int epoch = RecordHelper.getTransactionEpoch(list.get(0).getId());
                    CommittingTransactionsRecord record = new CommittingTransactionsRecord(epoch, txIdList.build());
                    return updateCommittingTxnRecord(new VersionedMetadata<>(record, versioned.getVersion()), context).thenCompose(version -> removeTxnsFromCommitOrder(positions, context).thenApply(v -> new SimpleEntry<>(new VersionedMetadata<>(record, version), list)));
                }
            });
        } else {
            List<String> transactionsToCommit = versioned.getObject().getTransactionsToCommit().stream().map(UUID::toString).collect(Collectors.toList());
            return getVersionedTransactionRecords(versioned.getObject().getEpoch(), transactionsToCommit, context).thenApply(x -> new SimpleEntry<>(versioned, x));
        }
    });
}
Also used : StreamSegmentRecord(io.pravega.controller.store.stream.records.StreamSegmentRecord) SneakyThrows(lombok.SneakyThrows) BiFunction(java.util.function.BiFunction) LoggerFactory(org.slf4j.LoggerFactory) StreamConfiguration(io.pravega.client.stream.StreamConfiguration) TagLogger(io.pravega.common.tracing.TagLogger) VersionedMetadata(io.pravega.controller.store.VersionedMetadata) AtomicInteger(java.util.concurrent.atomic.AtomicInteger) Map(java.util.Map) DataNotFoundException(io.pravega.controller.store.stream.StoreException.DataNotFoundException) EpochTransitionRecord(io.pravega.controller.store.stream.records.EpochTransitionRecord) ImmutableSet(com.google.common.collect.ImmutableSet) StreamCutReferenceRecord(io.pravega.controller.store.stream.records.StreamCutReferenceRecord) StreamTruncationRecord(io.pravega.controller.store.stream.records.StreamTruncationRecord) ImmutableMap(com.google.common.collect.ImmutableMap) Predicate(java.util.function.Predicate) Collection(java.util.Collection) Set(java.util.Set) CompletionException(java.util.concurrent.CompletionException) ActiveTxnRecord(io.pravega.controller.store.stream.records.ActiveTxnRecord) UUID(java.util.UUID) Collectors(java.util.stream.Collectors) List(java.util.List) CompletionStage(java.util.concurrent.CompletionStage) Optional(java.util.Optional) HistoryTimeSeries(io.pravega.controller.store.stream.records.HistoryTimeSeries) Futures(io.pravega.common.concurrent.Futures) IntStream(java.util.stream.IntStream) CompletedTxnRecord(io.pravega.controller.store.stream.records.CompletedTxnRecord) CommittingTransactionsRecord(io.pravega.controller.store.stream.records.CommittingTransactionsRecord) NameUtils.computeSegmentId(io.pravega.shared.NameUtils.computeSegmentId) Exceptions(io.pravega.common.Exceptions) HistoryTimeSeriesRecord(io.pravega.controller.store.stream.records.HistoryTimeSeriesRecord) HashMap(java.util.HashMap) CompletableFuture(java.util.concurrent.CompletableFuture) RetentionSet(io.pravega.controller.store.stream.records.RetentionSet) DATA_NOT_FOUND_PREDICATE(io.pravega.controller.store.stream.AbstractStreamMetadataStore.DATA_NOT_FOUND_PREDICATE) AtomicReference(java.util.concurrent.atomic.AtomicReference) Function(java.util.function.Function) NameUtils.getSegmentNumber(io.pravega.shared.NameUtils.getSegmentNumber) ArrayList(java.util.ArrayList) HashSet(java.util.HashSet) Lists(com.google.common.collect.Lists) ImmutableList(com.google.common.collect.ImmutableList) StateRecord(io.pravega.controller.store.stream.records.StateRecord) StreamSubscriber(io.pravega.controller.store.stream.records.StreamSubscriber) LinkedList(java.util.LinkedList) RecordHelper(io.pravega.controller.store.stream.records.RecordHelper) SimpleEntry(java.util.AbstractMap.SimpleEntry) LongSummaryStatistics(java.util.LongSummaryStatistics) CollectionHelpers(io.pravega.common.util.CollectionHelpers) SealedSegmentsMapShard(io.pravega.controller.store.stream.records.SealedSegmentsMapShard) NameUtils(io.pravega.shared.NameUtils) Executor(java.util.concurrent.Executor) WriterMark(io.pravega.controller.store.stream.records.WriterMark) lombok.val(lombok.val) StreamCutRecord(io.pravega.controller.store.stream.records.StreamCutRecord) AtomicLong(java.util.concurrent.atomic.AtomicLong) StreamConfigurationRecord(io.pravega.controller.store.stream.records.StreamConfigurationRecord) EpochRecord(io.pravega.controller.store.stream.records.EpochRecord) ConcurrentSkipListSet(java.util.concurrent.ConcurrentSkipListSet) Version(io.pravega.controller.store.Version) Preconditions(com.google.common.base.Preconditions) VisibleForTesting(com.google.common.annotations.VisibleForTesting) Comparator(java.util.Comparator) Collections(java.util.Collections) ImmutableList(com.google.common.collect.ImmutableList) CommittingTransactionsRecord(io.pravega.controller.store.stream.records.CommittingTransactionsRecord) SimpleEntry(java.util.AbstractMap.SimpleEntry) LinkedList(java.util.LinkedList) AtomicLong(java.util.concurrent.atomic.AtomicLong) UUID(java.util.UUID) VersionedMetadata(io.pravega.controller.store.VersionedMetadata)

Example 15 with CommittingTransactionsRecord

use of io.pravega.controller.store.stream.records.CommittingTransactionsRecord in project pravega by pravega.

the class StreamMetadataStoreTest method scaleWithTxTest.

@Test(timeout = 30000)
public void scaleWithTxTest() throws Exception {
    final String scope = "ScopeScaleWithTx";
    final String stream = "StreamScaleWithTx";
    final ScalingPolicy policy = ScalingPolicy.fixed(2);
    final StreamConfiguration configuration = StreamConfiguration.builder().scalingPolicy(policy).build();
    long start = System.currentTimeMillis();
    store.createScope(scope, null, executor).get();
    store.createStream(scope, stream, configuration, start, null, executor).get();
    store.setState(scope, stream, State.ACTIVE, null, executor).get();
    long scaleTs = System.currentTimeMillis();
    SimpleEntry<Double, Double> segment2 = new SimpleEntry<>(0.5, 0.75);
    SimpleEntry<Double, Double> segment3 = new SimpleEntry<>(0.75, 1.0);
    List<Long> scale1SealedSegments = Collections.singletonList(1L);
    // region Txn created before scale and during scale
    // scale with transaction test
    // first txn created before-scale
    UUID txnId = store.generateTransactionId(scope, stream, null, executor).join();
    VersionedTransactionData tx01 = store.createTransaction(scope, stream, txnId, 100, 100, null, executor).get();
    assertEquals(0, tx01.getEpoch());
    VersionedMetadata<EpochTransitionRecord> versioned = store.submitScale(scope, stream, scale1SealedSegments, Arrays.asList(segment2, segment3), scaleTs, null, null, executor).join();
    EpochTransitionRecord response = versioned.getObject();
    Map<Long, Map.Entry<Double, Double>> scale1SegmentsCreated = response.getNewSegmentsWithRange();
    final int epoch = response.getActiveEpoch();
    assertEquals(0, epoch);
    assertNotNull(scale1SegmentsCreated);
    VersionedMetadata<State> state = store.getVersionedState(scope, stream, null, executor).join();
    state = store.updateVersionedState(scope, stream, State.SCALING, state, null, executor).join();
    versioned = store.startScale(scope, stream, false, versioned, state, null, executor).join();
    // second txn created after new segments are created in segment table but not yet in history table
    // assert that txn is created on old epoch
    store.scaleCreateNewEpochs(scope, stream, versioned, null, executor).join();
    txnId = store.generateTransactionId(scope, stream, null, executor).join();
    VersionedTransactionData tx02 = store.createTransaction(scope, stream, txnId, 100, 100, null, executor).get();
    assertEquals(0, tx02.getEpoch());
    assertEquals(0, (int) (tx02.getId().getMostSignificantBits() >> 32));
    // third transaction created after new epoch created
    txnId = store.generateTransactionId(scope, stream, null, executor).join();
    store.sealTransaction(scope, stream, tx02.getId(), true, Optional.of(tx02.getVersion()), "", Long.MIN_VALUE, null, executor).get();
    store.sealTransaction(scope, stream, tx01.getId(), true, Optional.of(tx01.getVersion()), "", Long.MIN_VALUE, null, executor).get();
    store.scaleSegmentsSealed(scope, stream, scale1SealedSegments.stream().collect(Collectors.toMap(x -> x, x -> 0L)), versioned, null, executor).join();
    store.completeScale(scope, stream, versioned, null, executor).join();
    VersionedTransactionData tx03 = store.createTransaction(scope, stream, txnId, 100, 100, null, executor).get();
    assertEquals(0, tx03.getEpoch());
    assertEquals(0, (int) (tx03.getId().getMostSignificantBits() >> 32));
    store.setState(scope, stream, State.ACTIVE, null, executor).join();
    // ensure that we can commit transactions on old epoch and roll over.
    EpochRecord activeEpoch = store.getActiveEpoch(scope, stream, null, true, executor).join();
    // submit another scale request without starting the scale
    List<Long> scale2SealedSegments = Collections.singletonList(0L);
    long scaleTs2 = System.currentTimeMillis();
    SimpleEntry<Double, Double> segment4 = new SimpleEntry<>(0.0, 0.25);
    SimpleEntry<Double, Double> segment5 = new SimpleEntry<>(0.25, 0.5);
    VersionedMetadata<EpochTransitionRecord> versioned2 = store.submitScale(scope, stream, scale2SealedSegments, Arrays.asList(segment4, segment5), scaleTs2, null, null, executor).join();
    EpochTransitionRecord response2 = versioned2.getObject();
    assertEquals(activeEpoch.getEpoch(), response2.getActiveEpoch());
    VersionedMetadata<CommittingTransactionsRecord> record = store.startCommitTransactions(scope, stream, 100, null, executor).join().getKey();
    store.setState(scope, stream, State.COMMITTING_TXN, null, executor).join();
    record = store.startRollingTxn(scope, stream, activeEpoch.getEpoch(), record, null, executor).join();
    store.rollingTxnCreateDuplicateEpochs(scope, stream, Collections.emptyMap(), System.currentTimeMillis(), record, null, executor).join();
    store.completeRollingTxn(scope, stream, Collections.emptyMap(), record, null, executor).join();
    store.completeCommitTransactions(scope, stream, record, null, executor, Collections.emptyMap()).join();
    store.setState(scope, stream, State.ACTIVE, null, executor).join();
    activeEpoch = store.getActiveEpoch(scope, stream, null, true, executor).join();
    assertEquals(3, activeEpoch.getEpoch());
    assertEquals(1, activeEpoch.getReferenceEpoch());
    assertEquals(3, activeEpoch.getSegments().size());
    List<StreamSegmentRecord> txnDuplicate = store.getSegmentsInEpoch(scope, stream, 2, null, executor).join();
    assertEquals(2, txnDuplicate.size());
    List<StreamSegmentRecord> activeEpochDuplicate = store.getSegmentsInEpoch(scope, stream, 3, null, executor).join();
    assertEquals(3, activeEpochDuplicate.size());
    EpochRecord txnCommittedEpoch = store.getEpoch(scope, stream, 2, null, executor).join();
    assertEquals(0, txnCommittedEpoch.getReferenceEpoch());
    assertEquals(store.transactionStatus(scope, stream, tx01.getId(), null, executor).join(), TxnStatus.COMMITTED);
    assertEquals(store.transactionStatus(scope, stream, tx02.getId(), null, executor).join(), TxnStatus.COMMITTED);
    assertEquals(store.transactionStatus(scope, stream, tx03.getId(), null, executor).join(), TxnStatus.OPEN);
    store.sealTransaction(scope, stream, tx03.getId(), true, Optional.of(tx03.getVersion()), "", Long.MIN_VALUE, null, executor).get();
    // endregion
    // region verify migrate request for manual scale
    // now start manual scale against previously submitted scale request that was on old epoch from before rolling txn.
    // verify that it gets migrated to latest duplicate epoch
    state = store.getVersionedState(scope, stream, null, executor).join();
    state = store.updateVersionedState(scope, stream, State.SCALING, state, null, executor).join();
    versioned2 = store.submitScale(scope, stream, scale2SealedSegments, Arrays.asList(segment4, segment5), scaleTs2, null, null, executor).join();
    versioned2 = store.startScale(scope, stream, true, versioned2, state, null, executor).join();
    store.scaleCreateNewEpochs(scope, stream, versioned2, null, executor).join();
    txnId = store.generateTransactionId(scope, stream, null, executor).join();
    VersionedTransactionData tx14 = store.createTransaction(scope, stream, txnId, 100, 100, null, executor).get();
    assertEquals(1, tx14.getEpoch());
    store.sealTransaction(scope, stream, tx14.getId(), true, Optional.of(tx14.getVersion()), "", Long.MIN_VALUE, null, executor).get();
    // verify that new txns can be created and are created on original epoch
    txnId = store.generateTransactionId(scope, stream, null, executor).join();
    VersionedTransactionData tx15 = store.createTransaction(scope, stream, txnId, 100, 100, null, executor).get();
    assertEquals(1, tx15.getEpoch());
    store.scaleCreateNewEpochs(scope, stream, versioned2, null, executor).join();
    store.scaleSegmentsSealed(scope, stream, Collections.emptyMap(), versioned2, null, executor).join();
    store.completeScale(scope, stream, versioned2, null, executor).join();
    store.setState(scope, stream, State.ACTIVE, null, executor).get();
    activeEpoch = store.getActiveEpoch(scope, stream, null, true, executor).join();
    assertEquals(4, activeEpoch.getEpoch());
    assertEquals(4, activeEpoch.getReferenceEpoch());
    store.sealTransaction(scope, stream, tx15.getId(), true, Optional.of(tx15.getVersion()), "", Long.MIN_VALUE, null, executor).get();
    record = store.startCommitTransactions(scope, stream, 100, null, executor).join().getKey();
    store.setState(scope, stream, State.COMMITTING_TXN, null, executor).get();
    record = store.startRollingTxn(scope, stream, activeEpoch.getEpoch(), record, null, executor).join();
    store.rollingTxnCreateDuplicateEpochs(scope, stream, Collections.emptyMap(), System.currentTimeMillis(), record, null, executor).join();
    store.completeRollingTxn(scope, stream, Collections.emptyMap(), record, null, executor).join();
    store.completeCommitTransactions(scope, stream, record, null, executor, Collections.emptyMap()).join();
    store.setState(scope, stream, State.ACTIVE, null, executor).join();
    activeEpoch = store.getActiveEpoch(scope, stream, null, true, executor).join();
    assertEquals(6, activeEpoch.getEpoch());
    assertEquals(4, activeEpoch.getReferenceEpoch());
// endregion
}
Also used : Arrays(java.util.Arrays) StreamCut(io.pravega.client.stream.StreamCut) ArgumentMatchers(org.mockito.ArgumentMatchers) StreamSegmentRecord(io.pravega.controller.store.stream.records.StreamSegmentRecord) AssertExtensions(io.pravega.test.common.AssertExtensions) Random(java.util.Random) StreamConfiguration(io.pravega.client.stream.StreamConfiguration) VersionedMetadata(io.pravega.controller.store.VersionedMetadata) Pair(org.apache.commons.lang3.tuple.Pair) Stream(io.pravega.client.stream.Stream) Duration(java.time.Duration) Map(java.util.Map) After(org.junit.After) Mockito.doAnswer(org.mockito.Mockito.doAnswer) Controller(io.pravega.controller.stream.api.grpc.v1.Controller) ReaderGroupConfig(io.pravega.client.stream.ReaderGroupConfig) DeleteScopeStatus(io.pravega.controller.stream.api.grpc.v1.Controller.DeleteScopeStatus) EpochTransitionRecord(io.pravega.controller.store.stream.records.EpochTransitionRecord) StreamCutReferenceRecord(io.pravega.controller.store.stream.records.StreamCutReferenceRecord) StreamTruncationRecord(io.pravega.controller.store.stream.records.StreamTruncationRecord) ImmutableMap(com.google.common.collect.ImmutableMap) Set(java.util.Set) CompletionException(java.util.concurrent.CompletionException) UUID(java.util.UUID) Collectors(java.util.stream.Collectors) List(java.util.List) Assert.assertFalse(org.junit.Assert.assertFalse) Optional(java.util.Optional) HistoryTimeSeries(io.pravega.controller.store.stream.records.HistoryTimeSeries) Futures(io.pravega.common.concurrent.Futures) Segment(io.pravega.client.segment.impl.Segment) CommittingTransactionsRecord(io.pravega.controller.store.stream.records.CommittingTransactionsRecord) NameUtils.computeSegmentId(io.pravega.shared.NameUtils.computeSegmentId) RetentionPolicy(io.pravega.client.stream.RetentionPolicy) Exceptions(io.pravega.common.Exceptions) HashMap(java.util.HashMap) CompletableFuture(java.util.concurrent.CompletableFuture) RetentionSet(io.pravega.controller.store.stream.records.RetentionSet) Mockito.spy(org.mockito.Mockito.spy) ArrayList(java.util.ArrayList) Strings(com.google.common.base.Strings) ReaderGroupConfigRecord(io.pravega.controller.store.stream.records.ReaderGroupConfigRecord) Lists(com.google.common.collect.Lists) StreamCutImpl(io.pravega.client.stream.impl.StreamCutImpl) ScheduledExecutorService(java.util.concurrent.ScheduledExecutorService) RecordHelper(io.pravega.controller.store.stream.records.RecordHelper) SimpleEntry(java.util.AbstractMap.SimpleEntry) SealedSegmentsMapShard(io.pravega.controller.store.stream.records.SealedSegmentsMapShard) Before(org.junit.Before) NameUtils(io.pravega.shared.NameUtils) Assert.assertNotNull(org.junit.Assert.assertNotNull) WriterMark(io.pravega.controller.store.stream.records.WriterMark) Assert.assertTrue(org.junit.Assert.assertTrue) Test(org.junit.Test) StreamCutRecord(io.pravega.controller.store.stream.records.StreamCutRecord) TxnResource(io.pravega.controller.store.task.TxnResource) Assert.assertNotEquals(org.junit.Assert.assertNotEquals) ExecutionException(java.util.concurrent.ExecutionException) StreamConfigurationRecord(io.pravega.controller.store.stream.records.StreamConfigurationRecord) AbstractMap(java.util.AbstractMap) EpochRecord(io.pravega.controller.store.stream.records.EpochRecord) Assert.assertNull(org.junit.Assert.assertNull) Version(io.pravega.controller.store.Version) ExecutorServiceHelpers(io.pravega.common.concurrent.ExecutorServiceHelpers) Assert(org.junit.Assert) Collections(java.util.Collections) Mockito.reset(org.mockito.Mockito.reset) ScalingPolicy(io.pravega.client.stream.ScalingPolicy) Assert.assertEquals(org.junit.Assert.assertEquals) ScalingPolicy(io.pravega.client.stream.ScalingPolicy) EpochRecord(io.pravega.controller.store.stream.records.EpochRecord) EpochTransitionRecord(io.pravega.controller.store.stream.records.EpochTransitionRecord) SimpleEntry(java.util.AbstractMap.SimpleEntry) CommittingTransactionsRecord(io.pravega.controller.store.stream.records.CommittingTransactionsRecord) StreamSegmentRecord(io.pravega.controller.store.stream.records.StreamSegmentRecord) SimpleEntry(java.util.AbstractMap.SimpleEntry) StreamConfiguration(io.pravega.client.stream.StreamConfiguration) UUID(java.util.UUID) Test(org.junit.Test)

Aggregations

CommittingTransactionsRecord (io.pravega.controller.store.stream.records.CommittingTransactionsRecord)17 UUID (java.util.UUID)14 StreamConfiguration (io.pravega.client.stream.StreamConfiguration)12 VersionedMetadata (io.pravega.controller.store.VersionedMetadata)11 EpochRecord (io.pravega.controller.store.stream.records.EpochRecord)11 CompletableFuture (java.util.concurrent.CompletableFuture)11 ImmutableMap (com.google.common.collect.ImmutableMap)10 Exceptions (io.pravega.common.Exceptions)10 Futures (io.pravega.common.concurrent.Futures)10 NameUtils.computeSegmentId (io.pravega.shared.NameUtils.computeSegmentId)10 ArrayList (java.util.ArrayList)10 HashMap (java.util.HashMap)10 List (java.util.List)10 Map (java.util.Map)10 Collectors (java.util.stream.Collectors)10 EpochTransitionRecord (io.pravega.controller.store.stream.records.EpochTransitionRecord)9 StreamTruncationRecord (io.pravega.controller.store.stream.records.StreamTruncationRecord)9 WriterMark (io.pravega.controller.store.stream.records.WriterMark)9 Lists (com.google.common.collect.Lists)8 ScalingPolicy (io.pravega.client.stream.ScalingPolicy)8