import org.opendaylight.controller.cluster.datastore.messages.ShardLeaderStateChanged;
import org.opendaylight.controller.cluster.datastore.messages.UpdateSchemaContext;
import org.opendaylight.controller.cluster.datastore.modification.Modification;
-import org.opendaylight.controller.cluster.datastore.modification.ModificationPayload;
import org.opendaylight.controller.cluster.datastore.modification.MutableCompositeModification;
import org.opendaylight.controller.cluster.datastore.utils.Dispatchers;
import org.opendaylight.controller.cluster.datastore.utils.MessageTracker;
txCommitTimeoutCheckSchedule.cancel();
}
+ commitCoordinator.abortPendingTransactions("Transaction aborted due to shutdown.", this);
+
shardMBean.unregisterMBean();
}
}
try {
- if (CreateTransaction.SERIALIZABLE_CLASS.isInstance(message)) {
+ if (CreateTransaction.isSerializedType(message)) {
handleCreateTransaction(message);
} else if (BatchedModifications.class.isInstance(message)) {
handleBatchedModifications((BatchedModifications)message);
handleForwardedReadyTransaction((ForwardedReadyTransaction) message);
} else if (message instanceof ReadyLocalTransaction) {
handleReadyLocalTransaction((ReadyLocalTransaction)message);
- } else if (CanCommitTransaction.SERIALIZABLE_CLASS.isInstance(message)) {
+ } else if (CanCommitTransaction.isSerializedType(message)) {
handleCanCommitTransaction(CanCommitTransaction.fromSerializable(message));
- } else if (CommitTransaction.SERIALIZABLE_CLASS.isInstance(message)) {
+ } else if (CommitTransaction.isSerializedType(message)) {
handleCommitTransaction(CommitTransaction.fromSerializable(message));
- } else if (AbortTransaction.SERIALIZABLE_CLASS.isInstance(message)) {
+ } else if (AbortTransaction.isSerializedType(message)) {
handleAbortTransaction(AbortTransaction.fromSerializable(message));
- } else if (CloseTransactionChain.SERIALIZABLE_CLASS.isInstance(message)) {
+ } else if (CloseTransactionChain.isSerializedType(message)) {
closeTransactionChain(CloseTransactionChain.fromSerializable(message));
} else if (message instanceof RegisterChangeListener) {
changeSupport.onMessage((RegisterChangeListener) message, isLeader(), hasLeader());
setPeerAddress(resolved.getPeerId().toString(),
resolved.getPeerAddress());
} else if (message.equals(TX_COMMIT_TIMEOUT_CHECK_MESSAGE)) {
- handleTransactionCommitTimeoutCheck();
+ commitCoordinator.checkForExpiredTransactions(transactionCommitTimeout, this);
} else if(message instanceof DatastoreContext) {
onDatastoreContext((DatastoreContext)message);
} else if(message instanceof RegisterRoleChangeListener){
return commitCoordinator.getQueueSize();
}
+ public int getCohortCacheSize() {
+ return commitCoordinator.getCohortCacheSize();
+ }
+
@Override
protected Optional<ActorRef> getRoleChangeNotifier() {
return roleChangeNotifier;
updateConfigParams(datastoreContext.getShardRaftConfig());
}
- private void handleTransactionCommitTimeoutCheck() {
- CohortEntry cohortEntry = commitCoordinator.getCurrentCohortEntry();
- if(cohortEntry != null) {
- if(cohortEntry.isExpired(transactionCommitTimeout)) {
- LOG.warn("{}: Current transaction {} has timed out after {} ms - aborting",
- persistenceId(), cohortEntry.getTransactionID(), transactionCommitTimeout);
-
- doAbortTransaction(cohortEntry.getTransactionID(), null);
- }
- }
-
- commitCoordinator.cleanupExpiredCohortEntries();
- }
-
private static boolean isEmptyCommit(final DataTreeCandidate candidate) {
return ModificationType.UNMODIFIED.equals(candidate.getRootNode().getModificationType());
}
try {
cohortEntry.commit();
- sender.tell(CommitTransactionReply.INSTANCE.toSerializable(), getSelf());
+ sender.tell(CommitTransactionReply.instance(cohortEntry.getClientVersion()).toSerializable(), getSelf());
shardMBean.incrementCommittedTransactionCount();
shardMBean.setLastCommittedTransactionTime(System.currentTimeMillis());
LOG.error("{}: Failed to re-apply transaction {}", persistenceId(), transactionID, e);
}
- sender.tell(CommitTransactionReply.INSTANCE.toSerializable(), getSelf());
+ sender.tell(CommitTransactionReply.instance(cohortEntry.getClientVersion()).toSerializable(),
+ getSelf());
} else {
// This really shouldn't happen - it likely means that persistence or replication
// took so long to complete such that the cohort entry was expired from the cache.
// the primary/leader shard. However with timing and caching on the front-end, there's a small
// window where it could have a stale leader during leadership transitions.
//
- if(isLeader()) {
- failIfIsolatedLeader(getSender());
-
+ boolean isLeaderActive = isLeaderActive();
+ if (isLeader() && isLeaderActive) {
handleBatchedModificationsLocal(batched, getSender());
} else {
ActorSelection leader = getLeader();
- if(leader != null) {
+ if (!isLeaderActive || leader == null) {
+ messageRetrySupport.addMessageToRetry(batched, getSender(),
+ "Could not commit transaction " + batched.getTransactionID());
+ } else {
// TODO: what if this is not the first batch and leadership changed in between batched messages?
// We could check if the commitCoordinator already has a cached entry and forward all the previous
// batched modifications.
LOG.debug("{}: Forwarding BatchedModifications to leader {}", persistenceId(), leader);
leader.forward(batched, getContext());
- } else {
- messageRetrySupport.addMessageToRetry(batched, getSender(),
- "Could not commit transaction " + batched.getTransactionID());
}
}
}
}
private void handleReadyLocalTransaction(final ReadyLocalTransaction message) {
- if (isLeader()) {
- failIfIsolatedLeader(getSender());
+ LOG.debug("{}: handleReadyLocalTransaction for {}", persistenceId(), message.getTransactionID());
+ boolean isLeaderActive = isLeaderActive();
+ if (isLeader() && isLeaderActive) {
try {
commitCoordinator.handleReadyLocalTransaction(message, getSender(), this);
} catch (Exception e) {
}
} else {
ActorSelection leader = getLeader();
- if (leader != null) {
+ if (!isLeaderActive || leader == null) {
+ messageRetrySupport.addMessageToRetry(message, getSender(),
+ "Could not commit transaction " + message.getTransactionID());
+ } else {
LOG.debug("{}: Forwarding ReadyLocalTransaction to leader {}", persistenceId(), leader);
message.setRemoteVersion(getCurrentBehavior().getLeaderPayloadVersion());
leader.forward(message, getContext());
- } else {
- messageRetrySupport.addMessageToRetry(message, getSender(),
- "Could not commit transaction " + message.getTransactionID());
}
}
}
private void handleForwardedReadyTransaction(ForwardedReadyTransaction forwardedReady) {
- if (isLeader()) {
- failIfIsolatedLeader(getSender());
+ LOG.debug("{}: handleForwardedReadyTransaction for {}", persistenceId(), forwardedReady.getTransactionID());
+ boolean isLeaderActive = isLeaderActive();
+ if (isLeader() && isLeaderActive) {
commitCoordinator.handleForwardedReadyTransaction(forwardedReady, getSender(), this);
} else {
ActorSelection leader = getLeader();
- if (leader != null) {
+ if (!isLeaderActive || leader == null) {
+ messageRetrySupport.addMessageToRetry(forwardedReady, getSender(),
+ "Could not commit transaction " + forwardedReady.getTransactionID());
+ } else {
LOG.debug("{}: Forwarding ForwardedReadyTransaction to leader {}", persistenceId(), leader);
ReadyLocalTransaction readyLocal = new ReadyLocalTransaction(forwardedReady.getTransactionID(),
forwardedReady.getTransaction().getSnapshot(), forwardedReady.isDoImmediateCommit());
readyLocal.setRemoteVersion(getCurrentBehavior().getLeaderPayloadVersion());
leader.forward(readyLocal, getContext());
- } else {
- messageRetrySupport.addMessageToRetry(forwardedReady, getSender(),
- "Could not commit transaction " + forwardedReady.getTransactionID());
}
}
}
}
private ActorRef createTypedTransactionActor(int transactionType,
- ShardTransactionIdentifier transactionId, String transactionChainId,
- short clientVersion ) {
+ ShardTransactionIdentifier transactionId, String transactionChainId) {
return transactionActorFactory.newShardTransaction(TransactionType.fromInt(transactionType),
- transactionId, transactionChainId, clientVersion);
+ transactionId, transactionChainId);
}
private void createTransaction(CreateTransaction createTransaction) {
}
ActorRef transactionActor = createTransaction(createTransaction.getTransactionType(),
- createTransaction.getTransactionId(), createTransaction.getTransactionChainId(),
- createTransaction.getVersion());
+ createTransaction.getTransactionId(), createTransaction.getTransactionChainId());
getSender().tell(new CreateTransactionReply(Serialization.serializedActorPath(transactionActor),
- createTransaction.getTransactionId()).toSerializable(), getSelf());
+ createTransaction.getTransactionId(), createTransaction.getVersion()).toSerializable(), getSelf());
} catch (Exception e) {
getSender().tell(new akka.actor.Status.Failure(e), getSelf());
}
}
private ActorRef createTransaction(int transactionType, String remoteTransactionId,
- String transactionChainId, short clientVersion) {
+ String transactionChainId) {
ShardTransactionIdentifier transactionId = new ShardTransactionIdentifier(remoteTransactionId);
}
ActorRef transactionActor = createTypedTransactionActor(transactionType, transactionId,
- transactionChainId, clientVersion);
+ transactionChainId);
return transactionActor;
}
// Replication consensus reached, proceed to commit
finishCommit(clientActor, identifier);
}
- } else if (data instanceof ModificationPayload) {
- try {
- applyModificationToState(clientActor, identifier, ((ModificationPayload) data).getModification());
- } catch (ClassNotFoundException | IOException e) {
- LOG.error("{}: Error extracting ModificationPayload", persistenceId(), e);
- }
} else if (data instanceof CompositeModificationPayload) {
Object modification = ((CompositeModificationPayload) data).getModification();
}
store.closeAllTransactionChains();
+
+ commitCoordinator.abortPendingTransactions(
+ "The transacton was aborted due to inflight leadership change.", this);
+ }
+
+ if(hasLeader && !isIsolatedLeader()) {
+ messageRetrySupport.retryMessages();
}
}
protected void onLeaderChanged(String oldLeader, String newLeader) {
shardMBean.incrementLeadershipChangeCount();
- if(hasLeader()) {
+ if(hasLeader() && !isIsolatedLeader()) {
messageRetrySupport.retryMessages();
}
}
+ @Override
+ protected void pauseLeader(Runnable operation) {
+ LOG.debug("{}: In pauseLeader, operation: {}", persistenceId(), operation);
+ commitCoordinator.setRunOnPendingTransactionsComplete(operation);
+ }
+
@Override
public String persistenceId() {
return this.name;