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));
}
};
}
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));
}
};
}
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;
}
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);
}
};
}
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());
}
};
}
Aggregations