Search in sources :

Example 6 with CommitTransaction

use of org.opendaylight.controller.cluster.datastore.messages.CommitTransaction in project controller by opendaylight.

the class ShardTest method testCommitPhaseFailure.

@Test
public void testCommitPhaseFailure() throws Exception {
    new ShardTestKit(getSystem()) {

        {
            final DataTree dataTree = createDelegatingMockDataTree();
            final TestActorRef<Shard> shard = actorFactory.createTestActor(newShardBuilder().dataTree(dataTree).props().withDispatcher(Dispatchers.DefaultDispatcherId()), "testCommitPhaseFailure");
            waitUntilLeader(shard);
            final FiniteDuration duration = duration("5 seconds");
            final Timeout timeout = new Timeout(duration);
            // Setup 2 simulated transactions with mock cohorts. The first
            // one fails in the
            // commit phase.
            doThrow(new RuntimeException("mock commit failure")).when(dataTree).commit(any(DataTreeCandidate.class));
            final TransactionIdentifier transactionID1 = nextTransactionId();
            shard.tell(newBatchedModifications(transactionID1, TestModel.TEST_PATH, ImmutableNodes.containerNode(TestModel.TEST_QNAME), true, false, 1), getRef());
            expectMsgClass(duration, ReadyTransactionReply.class);
            final TransactionIdentifier transactionID2 = nextTransactionId();
            shard.tell(newBatchedModifications(transactionID2, TestModel.TEST_PATH, ImmutableNodes.containerNode(TestModel.TEST_QNAME), true, false, 1), getRef());
            expectMsgClass(duration, ReadyTransactionReply.class);
            // Send the CanCommitTransaction message for the first Tx.
            shard.tell(new CanCommitTransaction(transactionID1, CURRENT_VERSION).toSerializable(), getRef());
            final CanCommitTransactionReply canCommitReply = CanCommitTransactionReply.fromSerializable(expectMsgClass(duration, CanCommitTransactionReply.class));
            assertEquals("Can commit", true, canCommitReply.getCanCommit());
            // Send the CanCommitTransaction message for the 2nd Tx. This
            // should get queued and
            // processed after the first Tx completes.
            final Future<Object> canCommitFuture = Patterns.ask(shard, new CanCommitTransaction(transactionID2, CURRENT_VERSION).toSerializable(), timeout);
            // Send the CommitTransaction message for the first Tx. This
            // should send back an error
            // and trigger the 2nd Tx to proceed.
            shard.tell(new CommitTransaction(transactionID1, CURRENT_VERSION).toSerializable(), getRef());
            expectMsgClass(duration, akka.actor.Status.Failure.class);
            // Wait for the 2nd Tx to complete the canCommit phase.
            final CountDownLatch latch = new CountDownLatch(1);
            canCommitFuture.onComplete(new OnComplete<Object>() {

                @Override
                public void onComplete(final Throwable failure, final Object resp) {
                    latch.countDown();
                }
            }, getSystem().dispatcher());
            assertEquals("2nd CanCommit complete", true, latch.await(5, TimeUnit.SECONDS));
            final InOrder inOrder = inOrder(dataTree);
            inOrder.verify(dataTree).validate(any(DataTreeModification.class));
            inOrder.verify(dataTree).prepare(any(DataTreeModification.class));
            // FIXME: this invocation is done on the result of validate(). To test it, we need to make sure mock
            // validate performs wrapping and we capture that mock
            // inOrder.verify(dataTree).validate(any(DataTreeModification.class));
            inOrder.verify(dataTree).commit(any(DataTreeCandidate.class));
        }
    };
}
Also used : FollowerInitialSyncUpStatus(org.opendaylight.controller.cluster.raft.base.messages.FollowerInitialSyncUpStatus) DataTreeModification(org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeModification) InOrder(org.mockito.InOrder) Timeout(akka.util.Timeout) ElectionTimeout(org.opendaylight.controller.cluster.raft.base.messages.ElectionTimeout) FiniteDuration(scala.concurrent.duration.FiniteDuration) CountDownLatch(java.util.concurrent.CountDownLatch) CanCommitTransactionReply(org.opendaylight.controller.cluster.datastore.messages.CanCommitTransactionReply) DataTreeCandidate(org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeCandidate) CanCommitTransaction(org.opendaylight.controller.cluster.datastore.messages.CanCommitTransaction) CommitTransaction(org.opendaylight.controller.cluster.datastore.messages.CommitTransaction) DataTree(org.opendaylight.yangtools.yang.data.api.schema.tree.DataTree) TransactionIdentifier(org.opendaylight.controller.cluster.access.concepts.TransactionIdentifier) CanCommitTransaction(org.opendaylight.controller.cluster.datastore.messages.CanCommitTransaction) Test(org.junit.Test)

Example 7 with CommitTransaction

use of org.opendaylight.controller.cluster.datastore.messages.CommitTransaction in project controller by opendaylight.

the class ShardTest method testPreCommitPhaseFailure.

@Test
public void testPreCommitPhaseFailure() throws Exception {
    new ShardTestKit(getSystem()) {

        {
            final DataTree dataTree = createDelegatingMockDataTree();
            final TestActorRef<Shard> shard = actorFactory.createTestActor(newShardBuilder().dataTree(dataTree).props().withDispatcher(Dispatchers.DefaultDispatcherId()), "testPreCommitPhaseFailure");
            waitUntilLeader(shard);
            final FiniteDuration duration = duration("5 seconds");
            final Timeout timeout = new Timeout(duration);
            doThrow(new RuntimeException("mock preCommit failure")).when(dataTree).prepare(any(DataTreeModification.class));
            final TransactionIdentifier transactionID1 = nextTransactionId();
            shard.tell(newBatchedModifications(transactionID1, TestModel.TEST_PATH, ImmutableNodes.containerNode(TestModel.TEST_QNAME), true, false, 1), getRef());
            expectMsgClass(duration, ReadyTransactionReply.class);
            final TransactionIdentifier transactionID2 = nextTransactionId();
            shard.tell(newBatchedModifications(transactionID2, TestModel.TEST_PATH, ImmutableNodes.containerNode(TestModel.TEST_QNAME), true, false, 1), getRef());
            expectMsgClass(duration, ReadyTransactionReply.class);
            // Send the CanCommitTransaction message for the first Tx.
            shard.tell(new CanCommitTransaction(transactionID1, CURRENT_VERSION).toSerializable(), getRef());
            final CanCommitTransactionReply canCommitReply = CanCommitTransactionReply.fromSerializable(expectMsgClass(duration, CanCommitTransactionReply.class));
            assertEquals("Can commit", true, canCommitReply.getCanCommit());
            // Send the CanCommitTransaction message for the 2nd Tx. This
            // should get queued and
            // processed after the first Tx completes.
            final Future<Object> canCommitFuture = Patterns.ask(shard, new CanCommitTransaction(transactionID2, CURRENT_VERSION).toSerializable(), timeout);
            // Send the CommitTransaction message for the first Tx. This
            // should send back an error
            // and trigger the 2nd Tx to proceed.
            shard.tell(new CommitTransaction(transactionID1, CURRENT_VERSION).toSerializable(), getRef());
            expectMsgClass(duration, akka.actor.Status.Failure.class);
            // Wait for the 2nd Tx to complete the canCommit phase.
            final CountDownLatch latch = new CountDownLatch(1);
            canCommitFuture.onComplete(new OnComplete<Object>() {

                @Override
                public void onComplete(final Throwable failure, final Object resp) {
                    latch.countDown();
                }
            }, getSystem().dispatcher());
            assertEquals("2nd CanCommit complete", true, latch.await(5, TimeUnit.SECONDS));
            final InOrder inOrder = inOrder(dataTree);
            inOrder.verify(dataTree).validate(any(DataTreeModification.class));
            inOrder.verify(dataTree).prepare(any(DataTreeModification.class));
            inOrder.verify(dataTree).validate(any(DataTreeModification.class));
        }
    };
}
Also used : DataTreeModification(org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeModification) FollowerInitialSyncUpStatus(org.opendaylight.controller.cluster.raft.base.messages.FollowerInitialSyncUpStatus) InOrder(org.mockito.InOrder) Timeout(akka.util.Timeout) ElectionTimeout(org.opendaylight.controller.cluster.raft.base.messages.ElectionTimeout) FiniteDuration(scala.concurrent.duration.FiniteDuration) CountDownLatch(java.util.concurrent.CountDownLatch) CanCommitTransactionReply(org.opendaylight.controller.cluster.datastore.messages.CanCommitTransactionReply) CanCommitTransaction(org.opendaylight.controller.cluster.datastore.messages.CanCommitTransaction) CommitTransaction(org.opendaylight.controller.cluster.datastore.messages.CommitTransaction) DataTree(org.opendaylight.yangtools.yang.data.api.schema.tree.DataTree) TransactionIdentifier(org.opendaylight.controller.cluster.access.concepts.TransactionIdentifier) CanCommitTransaction(org.opendaylight.controller.cluster.datastore.messages.CanCommitTransaction) Test(org.junit.Test)

Example 8 with CommitTransaction

use of org.opendaylight.controller.cluster.datastore.messages.CommitTransaction in project controller by opendaylight.

the class ShardCommitCoordinator method convertPendingTransactionsToMessages.

Collection<?> convertPendingTransactionsToMessages(final int maxModificationsPerBatch) {
    final Collection<VersionedExternalizableMessage> messages = new ArrayList<>();
    for (ShardDataTreeCohort cohort : dataTree.getAndClearPendingTransactions()) {
        CohortEntry cohortEntry = cohortCache.remove(cohort.getIdentifier());
        if (cohortEntry == null) {
            continue;
        }
        final Deque<BatchedModifications> newMessages = new ArrayDeque<>();
        cohortEntry.getDataTreeModification().applyToCursor(new AbstractBatchedModificationsCursor() {

            @Override
            protected BatchedModifications getModifications() {
                final BatchedModifications lastBatch = newMessages.peekLast();
                if (lastBatch != null && lastBatch.getModifications().size() >= maxModificationsPerBatch) {
                    return lastBatch;
                }
                // Allocate a new message
                final BatchedModifications ret = new BatchedModifications(cohortEntry.getTransactionId(), cohortEntry.getClientVersion());
                newMessages.add(ret);
                return ret;
            }
        });
        final BatchedModifications last = newMessages.peekLast();
        if (last != null) {
            final boolean immediate = cohortEntry.isDoImmediateCommit();
            last.setDoCommitOnReady(immediate);
            last.setReady(true);
            last.setTotalMessagesSent(newMessages.size());
            messages.addAll(newMessages);
            if (!immediate) {
                switch(cohort.getState()) {
                    case CAN_COMMIT_COMPLETE:
                    case CAN_COMMIT_PENDING:
                        messages.add(new CanCommitTransaction(cohortEntry.getTransactionId(), cohortEntry.getClientVersion()));
                        break;
                    case PRE_COMMIT_COMPLETE:
                    case PRE_COMMIT_PENDING:
                        messages.add(new CommitTransaction(cohortEntry.getTransactionId(), cohortEntry.getClientVersion()));
                        break;
                    default:
                        break;
                }
            }
        }
    }
    return messages;
}
Also used : VersionedExternalizableMessage(org.opendaylight.controller.cluster.datastore.messages.VersionedExternalizableMessage) ArrayList(java.util.ArrayList) ArrayDeque(java.util.ArrayDeque) BatchedModifications(org.opendaylight.controller.cluster.datastore.messages.BatchedModifications) CommitTransaction(org.opendaylight.controller.cluster.datastore.messages.CommitTransaction) CanCommitTransaction(org.opendaylight.controller.cluster.datastore.messages.CanCommitTransaction) CanCommitTransaction(org.opendaylight.controller.cluster.datastore.messages.CanCommitTransaction) AbstractBatchedModificationsCursor(org.opendaylight.controller.cluster.datastore.utils.AbstractBatchedModificationsCursor)

Example 9 with CommitTransaction

use of org.opendaylight.controller.cluster.datastore.messages.CommitTransaction in project controller by opendaylight.

the class ShardTest method testTransactionCommitWithSubsequentExpiredCohortEntry.

@Test
public void testTransactionCommitWithSubsequentExpiredCohortEntry() throws Exception {
    dataStoreContextBuilder.shardTransactionCommitTimeoutInSeconds(1);
    new ShardTestKit(getSystem()) {

        {
            final TestActorRef<Shard> shard = actorFactory.createTestActor(newShardProps().withDispatcher(Dispatchers.DefaultDispatcherId()), "testTransactionCommitWithSubsequentExpiredCohortEntry");
            waitUntilLeader(shard);
            final FiniteDuration duration = duration("5 seconds");
            final ShardDataTree dataStore = shard.underlyingActor().getDataStore();
            final TransactionIdentifier transactionID1 = nextTransactionId();
            shard.tell(prepareBatchedModifications(transactionID1, TestModel.TEST_PATH, ImmutableNodes.containerNode(TestModel.TEST_QNAME), false), getRef());
            expectMsgClass(duration, ReadyTransactionReply.class);
            // CanCommit the first Tx so it's the current in-progress Tx.
            shard.tell(new CanCommitTransaction(transactionID1, CURRENT_VERSION).toSerializable(), getRef());
            expectMsgClass(duration, CanCommitTransactionReply.class);
            // Ready the second Tx.
            final TransactionIdentifier transactionID2 = nextTransactionId();
            shard.tell(prepareBatchedModifications(transactionID2, TestModel.TEST_PATH, ImmutableNodes.containerNode(TestModel.TEST_QNAME), false), getRef());
            expectMsgClass(duration, ReadyTransactionReply.class);
            // Ready the third Tx.
            final TransactionIdentifier transactionID3 = nextTransactionId();
            final DataTreeModification modification3 = dataStore.newModification();
            new WriteModification(TestModel.TEST2_PATH, ImmutableNodes.containerNode(TestModel.TEST2_QNAME)).apply(modification3);
            modification3.ready();
            final ReadyLocalTransaction readyMessage = new ReadyLocalTransaction(transactionID3, modification3, true);
            shard.tell(readyMessage, getRef());
            // Commit the first Tx. After completing, the second should
            // expire from the queue and the third
            // Tx committed.
            shard.tell(new CommitTransaction(transactionID1, CURRENT_VERSION).toSerializable(), getRef());
            expectMsgClass(duration, CommitTransactionReply.class);
            // Expect commit reply from the third Tx.
            expectMsgClass(duration, CommitTransactionReply.class);
            final NormalizedNode<?, ?> node = readStore(shard, TestModel.TEST2_PATH);
            assertNotNull(TestModel.TEST2_PATH + " not found", node);
        }
    };
}
Also used : DataTreeModification(org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeModification) WriteModification(org.opendaylight.controller.cluster.datastore.modification.WriteModification) CanCommitTransaction(org.opendaylight.controller.cluster.datastore.messages.CanCommitTransaction) CommitTransaction(org.opendaylight.controller.cluster.datastore.messages.CommitTransaction) ReadyLocalTransaction(org.opendaylight.controller.cluster.datastore.messages.ReadyLocalTransaction) TransactionIdentifier(org.opendaylight.controller.cluster.access.concepts.TransactionIdentifier) CanCommitTransaction(org.opendaylight.controller.cluster.datastore.messages.CanCommitTransaction) FiniteDuration(scala.concurrent.duration.FiniteDuration) Test(org.junit.Test)

Example 10 with CommitTransaction

use of org.opendaylight.controller.cluster.datastore.messages.CommitTransaction in project controller by opendaylight.

the class ShardTest method testAbortQueuedTransaction.

@Test
public void testAbortQueuedTransaction() throws Exception {
    new ShardTestKit(getSystem()) {

        {
            final TestActorRef<Shard> shard = actorFactory.createTestActor(newShardProps().withDispatcher(Dispatchers.DefaultDispatcherId()), "testAbortAfterReady");
            waitUntilLeader(shard);
            final FiniteDuration duration = duration("5 seconds");
            // Ready 3 tx's.
            final TransactionIdentifier transactionID1 = nextTransactionId();
            shard.tell(newBatchedModifications(transactionID1, TestModel.TEST_PATH, ImmutableNodes.containerNode(TestModel.TEST_QNAME), true, false, 1), getRef());
            expectMsgClass(duration, ReadyTransactionReply.class);
            final TransactionIdentifier transactionID2 = nextTransactionId();
            shard.tell(newBatchedModifications(transactionID2, TestModel.TEST_PATH, ImmutableNodes.containerNode(TestModel.TEST_QNAME), true, false, 1), getRef());
            expectMsgClass(duration, ReadyTransactionReply.class);
            final TransactionIdentifier transactionID3 = nextTransactionId();
            shard.tell(newBatchedModifications(transactionID3, TestModel.OUTER_LIST_PATH, ImmutableNodes.mapNodeBuilder(TestModel.OUTER_LIST_QNAME).build(), true, false, 1), getRef());
            expectMsgClass(duration, ReadyTransactionReply.class);
            // Abort the second tx while it's queued.
            shard.tell(new AbortTransaction(transactionID2, CURRENT_VERSION).toSerializable(), getRef());
            expectMsgClass(duration, AbortTransactionReply.class);
            // Commit the other 2.
            shard.tell(new CanCommitTransaction(transactionID1, CURRENT_VERSION).toSerializable(), getRef());
            expectMsgClass(duration, CanCommitTransactionReply.class);
            shard.tell(new CommitTransaction(transactionID1, CURRENT_VERSION).toSerializable(), getRef());
            expectMsgClass(duration, CommitTransactionReply.class);
            shard.tell(new CanCommitTransaction(transactionID3, CURRENT_VERSION).toSerializable(), getRef());
            expectMsgClass(duration, CanCommitTransactionReply.class);
            shard.tell(new CommitTransaction(transactionID3, CURRENT_VERSION).toSerializable(), getRef());
            expectMsgClass(duration, CommitTransactionReply.class);
            assertEquals("getPendingTxCommitQueueSize", 0, shard.underlyingActor().getPendingTxCommitQueueSize());
        }
    };
}
Also used : CanCommitTransaction(org.opendaylight.controller.cluster.datastore.messages.CanCommitTransaction) CommitTransaction(org.opendaylight.controller.cluster.datastore.messages.CommitTransaction) TransactionIdentifier(org.opendaylight.controller.cluster.access.concepts.TransactionIdentifier) CanCommitTransaction(org.opendaylight.controller.cluster.datastore.messages.CanCommitTransaction) FiniteDuration(scala.concurrent.duration.FiniteDuration) AbortTransaction(org.opendaylight.controller.cluster.datastore.messages.AbortTransaction) Test(org.junit.Test)

Aggregations

CanCommitTransaction (org.opendaylight.controller.cluster.datastore.messages.CanCommitTransaction)13 CommitTransaction (org.opendaylight.controller.cluster.datastore.messages.CommitTransaction)13 TransactionIdentifier (org.opendaylight.controller.cluster.access.concepts.TransactionIdentifier)12 Test (org.junit.Test)11 FiniteDuration (scala.concurrent.duration.FiniteDuration)11 CanCommitTransactionReply (org.opendaylight.controller.cluster.datastore.messages.CanCommitTransactionReply)8 DataTreeModification (org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeModification)5 Timeout (akka.util.Timeout)3 CountDownLatch (java.util.concurrent.CountDownLatch)3 InOrder (org.mockito.InOrder)3 ElectionTimeout (org.opendaylight.controller.cluster.raft.base.messages.ElectionTimeout)3 FollowerInitialSyncUpStatus (org.opendaylight.controller.cluster.raft.base.messages.FollowerInitialSyncUpStatus)3 YangInstanceIdentifier (org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier)3 DataTree (org.opendaylight.yangtools.yang.data.api.schema.tree.DataTree)3 LocalHistoryIdentifier (org.opendaylight.controller.cluster.access.concepts.LocalHistoryIdentifier)2 ReadyLocalTransaction (org.opendaylight.controller.cluster.datastore.messages.ReadyLocalTransaction)2 WriteModification (org.opendaylight.controller.cluster.datastore.modification.WriteModification)2 ContainerNode (org.opendaylight.yangtools.yang.data.api.schema.ContainerNode)2 DataTreeCandidate (org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeCandidate)2 OnComplete (akka.dispatch.OnComplete)1