Search in sources :

Example 6 with CommitEvent

use of io.pravega.shared.controller.event.CommitEvent in project pravega by pravega.

the class StreamTransactionMetadataTasksTest method idempotentOperationsTests.

@Test(timeout = 10000)
public void idempotentOperationsTests() throws CheckpointStoreException, InterruptedException {
    // Create mock writer objects.
    EventStreamWriterMock<CommitEvent> commitWriter = new EventStreamWriterMock<>();
    EventStreamWriterMock<AbortEvent> abortWriter = new EventStreamWriterMock<>();
    EventStreamReader<CommitEvent> commitReader = commitWriter.getReader();
    EventStreamReader<AbortEvent> abortReader = abortWriter.getReader();
    // Create transaction tasks.
    txnTasks = new StreamTransactionMetadataTasks(streamStore, hostStore, segmentHelperMock, executor, "host", connectionFactory, false, "");
    txnTasks.initializeStreamWriters("commitStream", commitWriter, "abortStream", abortWriter);
    consumer = new ControllerService(streamStore, hostStore, streamMetadataTasks, txnTasks, segmentHelperMock, executor, null);
    final ScalingPolicy policy1 = ScalingPolicy.fixed(2);
    final StreamConfiguration configuration1 = StreamConfiguration.builder().scope(SCOPE).streamName(STREAM).scalingPolicy(policy1).build();
    // Create stream and scope
    Assert.assertEquals(Controller.CreateScopeStatus.Status.SUCCESS, consumer.createScope(SCOPE).join().getStatus());
    Assert.assertEquals(Controller.CreateStreamStatus.Status.SUCCESS, streamMetadataTasks.createStream(SCOPE, STREAM, configuration1, System.currentTimeMillis()).join());
    // Create 2 transactions
    final long lease = 5000;
    final long scaleGracePeriod = 10000;
    VersionedTransactionData txData1 = txnTasks.createTxn(SCOPE, STREAM, lease, scaleGracePeriod, null).join().getKey();
    VersionedTransactionData txData2 = txnTasks.createTxn(SCOPE, STREAM, lease, scaleGracePeriod, null).join().getKey();
    UUID tx1 = txData1.getId();
    UUID tx2 = txData2.getId();
    int tx2Version = txData2.getVersion();
    // Commit the first one
    Assert.assertEquals(TxnStatus.COMMITTING, txnTasks.commitTxn(SCOPE, STREAM, tx1, null).join());
    // Ensure that transaction state is COMMITTING.
    assertEquals(TxnStatus.COMMITTING, streamStore.transactionStatus(SCOPE, STREAM, tx1, null, executor).join());
    // Abort the second one
    Assert.assertEquals(TxnStatus.ABORTING, txnTasks.abortTxn(SCOPE, STREAM, tx2, tx2Version, null).join());
    // Ensure that transactions state is ABORTING.
    assertEquals(TxnStatus.ABORTING, streamStore.transactionStatus(SCOPE, STREAM, tx2, null, executor).join());
    // Ensure that commit (resp. abort) transaction tasks are idempotent
    // when transaction is in COMMITTING state (resp. ABORTING state).
    assertEquals(TxnStatus.COMMITTING, txnTasks.commitTxn(SCOPE, STREAM, tx1, null).join());
    assertEquals(TxnStatus.ABORTING, txnTasks.abortTxn(SCOPE, STREAM, tx2, null, null).join());
    // Create commit and abort event processors.
    ConnectionFactory connectionFactory = Mockito.mock(ConnectionFactory.class);
    BlockingQueue<CommitEvent> processedCommitEvents = new LinkedBlockingQueue<>();
    BlockingQueue<AbortEvent> processedAbortEvents = new LinkedBlockingQueue<>();
    createEventProcessor("commitRG", "commitStream", commitReader, commitWriter, () -> new CommitEventProcessor(streamStore, streamMetadataTasks, hostStore, executor, segmentHelperMock, connectionFactory, processedCommitEvents));
    createEventProcessor("abortRG", "abortStream", abortReader, abortWriter, () -> new ConcurrentEventProcessor<>(new AbortRequestHandler(streamStore, streamMetadataTasks, hostStore, executor, segmentHelperMock, connectionFactory, processedAbortEvents), executor));
    // Wait until the commit event is processed and ensure that the txn state is COMMITTED.
    CommitEvent commitEvent = processedCommitEvents.take();
    assertEquals(tx1, commitEvent.getTxid());
    assertEquals(TxnStatus.COMMITTED, streamStore.transactionStatus(SCOPE, STREAM, tx1, null, executor).join());
    // Wait until the abort event is processed and ensure that the txn state is ABORTED.
    AbortEvent abortEvent = processedAbortEvents.take();
    assertEquals(tx2, abortEvent.getTxid());
    assertEquals(TxnStatus.ABORTED, streamStore.transactionStatus(SCOPE, STREAM, tx2, null, executor).join());
    // Ensure that commit (resp. abort) transaction tasks are idempotent
    // even after transaction is committed (resp. aborted)
    assertEquals(TxnStatus.COMMITTED, txnTasks.commitTxn(SCOPE, STREAM, tx1, null).join());
    assertEquals(TxnStatus.ABORTED, txnTasks.abortTxn(SCOPE, STREAM, tx2, null, null).join());
}
Also used : ScalingPolicy(io.pravega.client.stream.ScalingPolicy) CommitEventProcessor(io.pravega.controller.server.eventProcessor.CommitEventProcessor) EventStreamWriterMock(io.pravega.controller.mocks.EventStreamWriterMock) VersionedTransactionData(io.pravega.controller.store.stream.VersionedTransactionData) LinkedBlockingQueue(java.util.concurrent.LinkedBlockingQueue) ControllerService(io.pravega.controller.server.ControllerService) ConnectionFactory(io.pravega.client.netty.impl.ConnectionFactory) StreamConfiguration(io.pravega.client.stream.StreamConfiguration) AbortRequestHandler(io.pravega.controller.server.eventProcessor.requesthandlers.AbortRequestHandler) CommitEvent(io.pravega.shared.controller.event.CommitEvent) AbortEvent(io.pravega.shared.controller.event.AbortEvent) UUID(java.util.UUID) Test(org.junit.Test)

Example 7 with CommitEvent

use of io.pravega.shared.controller.event.CommitEvent in project pravega by pravega.

the class ControllerEventProcessorTest method testCommitEventProcessorFailedWrite.

@Test(timeout = 10000)
public void testCommitEventProcessorFailedWrite() {
    UUID txnId = UUID.randomUUID();
    VersionedTransactionData txnData = streamStore.createTransaction(SCOPE, STREAM, txnId, 10000, 10000, 10000, null, executor).join();
    CommitEventProcessor commitEventProcessor = spy(new CommitEventProcessor(streamStore, streamMetadataTasks, hostStore, executor, segmentHelperMock, null));
    EventProcessor.Writer<CommitEvent> successWriter = event -> CompletableFuture.completedFuture(null);
    EventProcessor.Writer<CommitEvent> failedWriter = event -> {
        CompletableFuture<Void> future = new CompletableFuture<>();
        future.completeExceptionally(new RuntimeException("Error"));
        return future;
    };
    // Simulate a failed write
    when(commitEventProcessor.getSelfWriter()).thenReturn(failedWriter).thenReturn(successWriter);
    // invoke process with epoch > txnData.
    commitEventProcessor.process(new CommitEvent(SCOPE, STREAM, txnData.getEpoch() + 1, txnData.getId()), null);
    verify(commitEventProcessor, times(2)).getSelfWriter();
}
Also used : CommitEvent(io.pravega.shared.controller.event.CommitEvent) CuratorFrameworkFactory(org.apache.curator.framework.CuratorFrameworkFactory) StreamStoreFactory(io.pravega.controller.store.stream.StreamStoreFactory) SegmentHelper(io.pravega.controller.server.SegmentHelper) EventProcessor(io.pravega.controller.eventProcessor.impl.EventProcessor) CompletableFuture(java.util.concurrent.CompletableFuture) Mockito.spy(org.mockito.Mockito.spy) StreamConfiguration(io.pravega.client.stream.StreamConfiguration) RetryOneTime(org.apache.curator.retry.RetryOneTime) AbortEvent(io.pravega.shared.controller.event.AbortEvent) AbortRequestHandler(io.pravega.controller.server.eventProcessor.requesthandlers.AbortRequestHandler) TestingServerStarter(io.pravega.test.common.TestingServerStarter) After(org.junit.After) ScheduledExecutorService(java.util.concurrent.ScheduledExecutorService) TestingServer(org.apache.curator.test.TestingServer) StreamMetadataTasks(io.pravega.controller.task.Stream.StreamMetadataTasks) ConnectionFactory(io.pravega.client.netty.impl.ConnectionFactory) HostMonitorConfigImpl(io.pravega.controller.store.host.impl.HostMonitorConfigImpl) Before(org.junit.Before) SegmentHelperMock(io.pravega.controller.mocks.SegmentHelperMock) Test(org.junit.Test) Mockito.times(org.mockito.Mockito.times) UUID(java.util.UUID) Mockito.when(org.mockito.Mockito.when) State(io.pravega.controller.store.stream.tables.State) HostStoreFactory(io.pravega.controller.store.host.HostStoreFactory) Executors(java.util.concurrent.Executors) Mockito.verify(org.mockito.Mockito.verify) TaskStoreFactory(io.pravega.controller.store.task.TaskStoreFactory) CuratorFramework(org.apache.curator.framework.CuratorFramework) HostControllerStore(io.pravega.controller.store.host.HostControllerStore) TxnStatus(io.pravega.controller.store.stream.TxnStatus) VersionedTransactionData(io.pravega.controller.store.stream.VersionedTransactionData) Optional(java.util.Optional) StreamMetadataStore(io.pravega.controller.store.stream.StreamMetadataStore) Assert(org.junit.Assert) ScalingPolicy(io.pravega.client.stream.ScalingPolicy) Mockito.mock(org.mockito.Mockito.mock) CompletableFuture(java.util.concurrent.CompletableFuture) EventProcessor(io.pravega.controller.eventProcessor.impl.EventProcessor) CommitEvent(io.pravega.shared.controller.event.CommitEvent) UUID(java.util.UUID) VersionedTransactionData(io.pravega.controller.store.stream.VersionedTransactionData) Test(org.junit.Test)

Example 8 with CommitEvent

use of io.pravega.shared.controller.event.CommitEvent in project pravega by pravega.

the class ControllerEventProcessorTest method testCommitEventProcessor.

@Test(timeout = 10000)
public void testCommitEventProcessor() {
    UUID txnId = UUID.randomUUID();
    VersionedTransactionData txnData = streamStore.createTransaction(SCOPE, STREAM, txnId, 10000, 10000, 10000, null, executor).join();
    Assert.assertNotNull(txnData);
    checkTransactionState(SCOPE, STREAM, txnId, TxnStatus.OPEN);
    streamStore.sealTransaction(SCOPE, STREAM, txnData.getId(), true, Optional.empty(), null, executor).join();
    checkTransactionState(SCOPE, STREAM, txnData.getId(), TxnStatus.COMMITTING);
    CommitEventProcessor commitEventProcessor = new CommitEventProcessor(streamStore, streamMetadataTasks, hostStore, executor, segmentHelperMock, null);
    commitEventProcessor.process(new CommitEvent(SCOPE, STREAM, txnData.getEpoch(), txnData.getId()), null);
    checkTransactionState(SCOPE, STREAM, txnData.getId(), TxnStatus.COMMITTED);
}
Also used : CommitEvent(io.pravega.shared.controller.event.CommitEvent) UUID(java.util.UUID) VersionedTransactionData(io.pravega.controller.store.stream.VersionedTransactionData) Test(org.junit.Test)

Example 9 with CommitEvent

use of io.pravega.shared.controller.event.CommitEvent in project pravega by pravega.

the class StreamTransactionMetadataTasks method sealTxnBody.

/**
 * Seals a txn and transitions it to COMMITTING (resp. ABORTING) state if commit param is true (resp. false).
 *
 * Post-condition:
 * 1. If seal completes successfully, then
 *     (a) txn state is COMMITTING/ABORTING,
 *     (b) CommitEvent/AbortEvent is present in the commit stream/abort stream,
 *     (c) txn is removed from host-txn index,
 *     (d) txn is removed from the timeout service.
 *
 * 2. If process fails after transitioning txn to COMMITTING/ABORTING state, but before responding to client, then
 * since txn is present in the host-txn index, some other controller process shall put CommitEvent/AbortEvent to
 * commit stream/abort stream.
 *
 * @param host    host id. It is different from hostId iff invoked from TxnSweeper for aborting orphaned txn.
 * @param scope   scope name.
 * @param stream  stream name.
 * @param commit  boolean indicating whether to commit txn.
 * @param txnId   txn id.
 * @param version expected version of txn node in store.
 * @param ctx     context.
 * @return        Txn status after sealing it.
 */
CompletableFuture<TxnStatus> sealTxnBody(final String host, final String scope, final String stream, final boolean commit, final UUID txnId, final Integer version, final OperationContext ctx) {
    TxnResource resource = new TxnResource(scope, stream, txnId);
    Optional<Integer> versionOpt = Optional.ofNullable(version);
    // Step 1. Add txn to current host's index, if it is not already present
    CompletableFuture<Void> addIndex = host.equals(hostId) && !timeoutService.containsTxn(scope, stream, txnId) ? // then txn would no longer be open.
    streamMetadataStore.addTxnToIndex(hostId, resource, Integer.MAX_VALUE) : CompletableFuture.completedFuture(null);
    addIndex.whenComplete((v, e) -> {
        if (e != null) {
            log.debug("Txn={}, already present/newly added to host-txn index of host={}", txnId, hostId);
        } else {
            log.debug("Txn={}, added txn to host-txn index of host={}", txnId, hostId);
        }
    });
    // Step 2. Seal txn
    CompletableFuture<AbstractMap.SimpleEntry<TxnStatus, Integer>> sealFuture = addIndex.thenComposeAsync(x -> streamMetadataStore.sealTransaction(scope, stream, txnId, commit, versionOpt, ctx, executor), executor).whenComplete((v, e) -> {
        if (e != null) {
            log.debug("Txn={}, failed sealing txn", txnId);
        } else {
            log.debug("Txn={}, sealed successfully, commit={}", txnId, commit);
        }
    });
    // Step 3. write event to corresponding stream.
    return sealFuture.thenComposeAsync(pair -> {
        TxnStatus status = pair.getKey();
        switch(status) {
            case COMMITTING:
                return writeCommitEvent(scope, stream, pair.getValue(), txnId, status);
            case ABORTING:
                return writeAbortEvent(scope, stream, pair.getValue(), txnId, status);
            case ABORTED:
            case COMMITTED:
                return CompletableFuture.completedFuture(status);
            case OPEN:
            case UNKNOWN:
            default:
                // exception would be thrown.
                return CompletableFuture.completedFuture(status);
        }
    }, executor).thenComposeAsync(status -> {
        // Step 4. Remove txn from timeoutService, and from the index.
        timeoutService.removeTxn(scope, stream, txnId);
        log.debug("Txn={}, removed from timeout service", txnId);
        return streamMetadataStore.removeTxnFromIndex(host, resource, true).whenComplete((v, e) -> {
            if (e != null) {
                log.debug("Txn={}, failed removing txn from host-txn index of host={}", txnId, hostId);
            } else {
                log.debug("Txn={}, removed txn from host-txn index of host={}", txnId, hostId);
            }
        }).thenApply(x -> status);
    }, executor);
}
Also used : CommitEvent(io.pravega.shared.controller.event.CommitEvent) OperationContext(io.pravega.controller.store.stream.OperationContext) ControllerEventProcessors(io.pravega.controller.server.eventProcessor.ControllerEventProcessors) Getter(lombok.Getter) EventStreamWriter(io.pravega.client.stream.EventStreamWriter) SegmentHelper(io.pravega.controller.server.SegmentHelper) PravegaInterceptor(io.pravega.controller.server.rpc.auth.PravegaInterceptor) CompletableFuture(java.util.concurrent.CompletableFuture) TimeoutServiceConfig(io.pravega.controller.timeout.TimeoutServiceConfig) Status(io.pravega.controller.stream.api.grpc.v1.Controller.PingTxnStatus.Status) AbortEvent(io.pravega.shared.controller.event.AbortEvent) Pair(org.apache.commons.lang3.tuple.Pair) Duration(java.time.Duration) ScheduledExecutorService(java.util.concurrent.ScheduledExecutorService) RETRYABLE_PREDICATE(io.pravega.controller.util.RetryHelper.RETRYABLE_PREDICATE) Segment(io.pravega.controller.store.stream.Segment) TimerWheelTimeoutService(io.pravega.controller.timeout.TimerWheelTimeoutService) ConnectionFactory(io.pravega.client.netty.impl.ConnectionFactory) EventWriterConfig(io.pravega.client.stream.EventWriterConfig) RetryHelper.withRetriesAsync(io.pravega.controller.util.RetryHelper.withRetriesAsync) ControllerEventProcessorConfig(io.pravega.controller.server.eventProcessor.ControllerEventProcessorConfig) BlockingQueue(java.util.concurrent.BlockingQueue) UUID(java.util.UUID) Collectors(java.util.stream.Collectors) TxnResource(io.pravega.controller.store.task.TxnResource) ImmutablePair(org.apache.commons.lang3.tuple.ImmutablePair) TimeUnit(java.util.concurrent.TimeUnit) CountDownLatch(java.util.concurrent.CountDownLatch) AbstractMap(java.util.AbstractMap) List(java.util.List) Slf4j(lombok.extern.slf4j.Slf4j) Config(io.pravega.controller.util.Config) HostControllerStore(io.pravega.controller.store.host.HostControllerStore) TxnStatus(io.pravega.controller.store.stream.TxnStatus) ClientFactory(io.pravega.client.ClientFactory) VersionedTransactionData(io.pravega.controller.store.stream.VersionedTransactionData) Optional(java.util.Optional) TimeoutService(io.pravega.controller.timeout.TimeoutService) VisibleForTesting(com.google.common.annotations.VisibleForTesting) StreamMetadataStore(io.pravega.controller.store.stream.StreamMetadataStore) PingTxnStatus(io.pravega.controller.stream.api.grpc.v1.Controller.PingTxnStatus) Futures(io.pravega.common.concurrent.Futures) TxnResource(io.pravega.controller.store.task.TxnResource) TxnStatus(io.pravega.controller.store.stream.TxnStatus) PingTxnStatus(io.pravega.controller.stream.api.grpc.v1.Controller.PingTxnStatus)

Example 10 with CommitEvent

use of io.pravega.shared.controller.event.CommitEvent in project pravega by pravega.

the class StreamTransactionMetadataTasks method writeCommitEvent.

CompletableFuture<TxnStatus> writeCommitEvent(String scope, String stream, int epoch, UUID txnId, TxnStatus status) {
    String key = scope + stream;
    CommitEvent event = new CommitEvent(scope, stream, epoch, txnId);
    return TaskStepsRetryHelper.withRetries(() -> writeEvent(commitEventEventStreamWriter, commitStreamName, key, event, txnId, status), executor);
}
Also used : CommitEvent(io.pravega.shared.controller.event.CommitEvent)

Aggregations

CommitEvent (io.pravega.shared.controller.event.CommitEvent)11 AbortEvent (io.pravega.shared.controller.event.AbortEvent)8 UUID (java.util.UUID)8 Test (org.junit.Test)7 ConnectionFactory (io.pravega.client.netty.impl.ConnectionFactory)6 ScalingPolicy (io.pravega.client.stream.ScalingPolicy)6 StreamConfiguration (io.pravega.client.stream.StreamConfiguration)6 CompletableFuture (java.util.concurrent.CompletableFuture)6 SegmentHelper (io.pravega.controller.server.SegmentHelper)5 HostControllerStore (io.pravega.controller.store.host.HostControllerStore)5 StreamMetadataStore (io.pravega.controller.store.stream.StreamMetadataStore)5 VersionedTransactionData (io.pravega.controller.store.stream.VersionedTransactionData)5 ScheduledExecutorService (java.util.concurrent.ScheduledExecutorService)5 Futures (io.pravega.common.concurrent.Futures)4 ControllerService (io.pravega.controller.server.ControllerService)4 List (java.util.List)4 Slf4j (lombok.extern.slf4j.Slf4j)4 VisibleForTesting (com.google.common.annotations.VisibleForTesting)3 ClientFactory (io.pravega.client.ClientFactory)3 EventStreamWriterMock (io.pravega.controller.mocks.EventStreamWriterMock)3