use of org.opendaylight.controller.cluster.datastore.messages.CanCommitTransactionReply 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.CanCommitTransactionReply in project controller by opendaylight.
the class ThreePhaseCommitCohortProxy method finishCanCommit.
private void finishCanCommit(final SettableFuture<Boolean> returnFuture) {
LOG.debug("Tx {} finishCanCommit", transactionId);
// For empty transactions return immediately
if (cohorts.size() == 0) {
LOG.debug("Tx {}: canCommit returning result true", transactionId);
returnFuture.set(Boolean.TRUE);
return;
}
commitOperationCallback = new TransactionRateLimitingCallback(actorContext);
commitOperationCallback.run();
final Iterator<CohortInfo> iterator = cohorts.iterator();
final OnComplete<Object> onComplete = new OnComplete<Object>() {
@Override
public void onComplete(final Throwable failure, final Object response) {
if (failure != null) {
LOG.debug("Tx {}: a canCommit cohort Future failed", transactionId, failure);
returnFuture.setException(failure);
commitOperationCallback.failure();
return;
}
// Only the first call to pause takes effect - subsequent calls before resume are no-ops. So
// this means we'll only time the first transaction canCommit which should be fine.
commitOperationCallback.pause();
boolean result = true;
if (CanCommitTransactionReply.isSerializedType(response)) {
CanCommitTransactionReply reply = CanCommitTransactionReply.fromSerializable(response);
LOG.debug("Tx {}: received {}", transactionId, response);
if (!reply.getCanCommit()) {
result = false;
}
} else {
LOG.error("Unexpected response type {}", response.getClass());
returnFuture.setException(new IllegalArgumentException(String.format("Unexpected response type %s", response.getClass())));
return;
}
if (iterator.hasNext() && result) {
sendCanCommitTransaction(iterator.next(), this);
} else {
LOG.debug("Tx {}: canCommit returning result: {}", transactionId, result);
returnFuture.set(Boolean.valueOf(result));
}
}
};
sendCanCommitTransaction(iterator.next(), onComplete);
}
use of org.opendaylight.controller.cluster.datastore.messages.CanCommitTransactionReply in project controller by opendaylight.
the class ShardTest method testReadWriteCommitWithPersistenceDisabled.
@Test
public void testReadWriteCommitWithPersistenceDisabled() throws Exception {
dataStoreContextBuilder.persistent(false);
new ShardTestKit(getSystem()) {
{
final TestActorRef<Shard> shard = actorFactory.createTestActor(newShardProps().withDispatcher(Dispatchers.DefaultDispatcherId()), "testCommitWithPersistenceDisabled");
waitUntilLeader(shard);
// Setup a simulated transactions with a mock cohort.
final FiniteDuration duration = duration("5 seconds");
final TransactionIdentifier transactionID = nextTransactionId();
final NormalizedNode<?, ?> containerNode = ImmutableNodes.containerNode(TestModel.TEST_QNAME);
shard.tell(prepareBatchedModifications(transactionID, TestModel.TEST_PATH, containerNode, false), getRef());
expectMsgClass(duration, ReadyTransactionReply.class);
// Send the CanCommitTransaction message.
shard.tell(new CanCommitTransaction(transactionID, CURRENT_VERSION).toSerializable(), getRef());
final CanCommitTransactionReply canCommitReply = CanCommitTransactionReply.fromSerializable(expectMsgClass(duration, CanCommitTransactionReply.class));
assertEquals("Can commit", true, canCommitReply.getCanCommit());
// Send the CanCommitTransaction message.
shard.tell(new CommitTransaction(transactionID, CURRENT_VERSION).toSerializable(), getRef());
expectMsgClass(duration, CommitTransactionReply.class);
final NormalizedNode<?, ?> actualNode = readStore(shard, TestModel.TEST_PATH);
assertEquals(TestModel.TEST_QNAME.getLocalName(), containerNode, actualNode);
}
};
}
use of org.opendaylight.controller.cluster.datastore.messages.CanCommitTransactionReply in project controller by opendaylight.
the class ShardTest method testBatchedModificationsOnTransactionChain.
@Test
public void testBatchedModificationsOnTransactionChain() throws Exception {
new ShardTestKit(getSystem()) {
{
final TestActorRef<Shard> shard = actorFactory.createTestActor(newShardProps().withDispatcher(Dispatchers.DefaultDispatcherId()), "testBatchedModificationsOnTransactionChain");
waitUntilLeader(shard);
final LocalHistoryIdentifier historyId = nextHistoryId();
final TransactionIdentifier transactionID1 = new TransactionIdentifier(historyId, 0);
final TransactionIdentifier transactionID2 = new TransactionIdentifier(historyId, 1);
final FiniteDuration duration = duration("5 seconds");
// Send a BatchedModifications to start a chained write
// transaction and ready it.
final ContainerNode containerNode = ImmutableNodes.containerNode(TestModel.TEST_QNAME);
final YangInstanceIdentifier path = TestModel.TEST_PATH;
shard.tell(newBatchedModifications(transactionID1, path, containerNode, true, false, 1), getRef());
expectMsgClass(duration, ReadyTransactionReply.class);
// Create a read Tx on the same chain.
shard.tell(new CreateTransaction(transactionID2, TransactionType.READ_ONLY.ordinal(), DataStoreVersions.CURRENT_VERSION).toSerializable(), getRef());
final CreateTransactionReply createReply = expectMsgClass(duration("3 seconds"), CreateTransactionReply.class);
getSystem().actorSelection(createReply.getTransactionPath()).tell(new ReadData(path, DataStoreVersions.CURRENT_VERSION), getRef());
final ReadDataReply readReply = expectMsgClass(duration("3 seconds"), ReadDataReply.class);
assertEquals("Read node", containerNode, readReply.getNormalizedNode());
// Commit the write transaction.
shard.tell(new CanCommitTransaction(transactionID1, CURRENT_VERSION).toSerializable(), getRef());
final CanCommitTransactionReply canCommitReply = CanCommitTransactionReply.fromSerializable(expectMsgClass(duration, CanCommitTransactionReply.class));
assertEquals("Can commit", true, canCommitReply.getCanCommit());
shard.tell(new CommitTransaction(transactionID1, CURRENT_VERSION).toSerializable(), getRef());
expectMsgClass(duration, CommitTransactionReply.class);
// Verify data in the data store.
final NormalizedNode<?, ?> actualNode = readStore(shard, path);
assertEquals("Stored node", containerNode, actualNode);
}
};
}
use of org.opendaylight.controller.cluster.datastore.messages.CanCommitTransactionReply in project controller by opendaylight.
the class ShardTest method testCommitWhenTransactionHasModifications.
private void testCommitWhenTransactionHasModifications(final boolean readWrite) throws Exception {
new ShardTestKit(getSystem()) {
{
final DataTree dataTree = createDelegatingMockDataTree();
final TestActorRef<Shard> shard = actorFactory.createTestActor(newShardBuilder().dataTree(dataTree).props().withDispatcher(Dispatchers.DefaultDispatcherId()), "testCommitWhenTransactionHasModifications-" + readWrite);
waitUntilLeader(shard);
final FiniteDuration duration = duration("5 seconds");
final TransactionIdentifier transactionID = nextTransactionId();
if (readWrite) {
shard.tell(prepareForwardedReadyTransaction(shard, transactionID, TestModel.TEST_PATH, ImmutableNodes.containerNode(TestModel.TEST_QNAME), false), getRef());
} else {
shard.tell(prepareBatchedModifications(transactionID, TestModel.TEST_PATH, ImmutableNodes.containerNode(TestModel.TEST_QNAME), false), getRef());
}
expectMsgClass(duration, ReadyTransactionReply.class);
// Send the CanCommitTransaction message.
shard.tell(new CanCommitTransaction(transactionID, CURRENT_VERSION).toSerializable(), getRef());
final CanCommitTransactionReply canCommitReply = CanCommitTransactionReply.fromSerializable(expectMsgClass(duration, CanCommitTransactionReply.class));
assertEquals("Can commit", true, canCommitReply.getCanCommit());
shard.tell(new CommitTransaction(transactionID, CURRENT_VERSION).toSerializable(), getRef());
expectMsgClass(duration, CommitTransactionReply.class);
final InOrder inOrder = inOrder(dataTree);
inOrder.verify(dataTree).validate(any(DataTreeModification.class));
inOrder.verify(dataTree).prepare(any(DataTreeModification.class));
inOrder.verify(dataTree).commit(any(DataTreeCandidate.class));
// Purge request is scheduled as asynchronous, wait for two heartbeats to let it propagate into
// the journal
Thread.sleep(HEARTBEAT_MILLIS * 2);
shard.tell(Shard.GET_SHARD_MBEAN_MESSAGE, getRef());
final ShardStats shardStats = expectMsgClass(duration, ShardStats.class);
// Use MBean for verification
// Committed transaction count should increase as usual
assertEquals(1, shardStats.getCommittedTransactionsCount());
// Commit index should advance as we do not have an empty
// modification
assertEquals(1, shardStats.getCommitIndex());
}
};
}
Aggregations