* terms of the Eclipse Public License v1.0 which accompanies this distribution,
* and is available at http://www.eclipse.org/legal/epl-v10.html
*/
-
package org.opendaylight.controller.cluster.datastore;
+import static com.google.common.base.Verify.verify;
+
import akka.actor.ActorRef;
import akka.actor.ActorSelection;
import akka.actor.Cancellable;
import org.opendaylight.controller.cluster.datastore.persisted.AbortTransactionPayload;
import org.opendaylight.controller.cluster.datastore.persisted.DatastoreSnapshot;
import org.opendaylight.controller.cluster.datastore.persisted.DatastoreSnapshot.ShardSnapshot;
+import org.opendaylight.controller.cluster.datastore.persisted.DisableTrackingPayload;
+import org.opendaylight.controller.cluster.datastore.persisted.PurgeTransactionPayload;
import org.opendaylight.controller.cluster.messaging.MessageAssembler;
import org.opendaylight.controller.cluster.messaging.MessageSlicer;
import org.opendaylight.controller.cluster.messaging.SliceOptions;
import org.opendaylight.yangtools.yang.data.api.schema.tree.TreeType;
import org.opendaylight.yangtools.yang.model.api.SchemaContext;
import org.opendaylight.yangtools.yang.model.api.SchemaContextProvider;
-import scala.concurrent.duration.Duration;
import scala.concurrent.duration.FiniteDuration;
/**
(DataTreeCohortActorRegistry.CohortRegistryCommand) message);
} else if (message instanceof PersistAbortTransactionPayload) {
final TransactionIdentifier txId = ((PersistAbortTransactionPayload) message).getTransactionId();
- persistPayload(txId, AbortTransactionPayload.create(txId), true);
+ persistPayload(txId, AbortTransactionPayload.create(txId,
+ datastoreContext.getInitialPayloadSerializedBufferCapacity()), true);
+ persistPayload(txId, PurgeTransactionPayload.create(txId,
+ datastoreContext.getInitialPayloadSerializedBufferCapacity()), false);
} else if (message instanceof MakeLeaderLocal) {
onMakeLeaderLocal();
} else if (RESUME_NEXT_PENDING_TRANSACTION.equals(message)) {
return Optional.of(state.getLastConnectTicks());
}
+ private void disableTracking(final DisableTrackingPayload payload) {
+ final ClientIdentifier clientId = payload.getIdentifier();
+ LOG.debug("{}: disabling tracking of {}", persistenceId(), clientId);
+ frontendMetadata.disableTracking(clientId);
+
+ if (isLeader()) {
+ final FrontendIdentifier frontendId = clientId.getFrontendId();
+ final LeaderFrontendState frontend = knownFrontends.get(frontendId);
+ if (frontend != null) {
+ if (clientId.equals(frontend.getIdentifier())) {
+ if (!(frontend instanceof LeaderFrontendState.Disabled)) {
+ verify(knownFrontends.replace(frontendId, frontend,
+ new LeaderFrontendState.Disabled(persistenceId(), clientId, store)));
+ LOG.debug("{}: leader state for {} disabled", persistenceId(), clientId);
+ } else {
+ LOG.debug("{}: leader state {} is already disabled", persistenceId(), frontend);
+ }
+ } else {
+ LOG.debug("{}: leader state {} does not match {}", persistenceId(), frontend, clientId);
+ }
+ } else {
+ LOG.debug("{}: leader state for {} not found", persistenceId(), clientId);
+ }
+ }
+ }
+
private void onMakeLeaderLocal() {
LOG.debug("{}: onMakeLeaderLocal received", persistenceId());
if (isLeader()) {
final ABIVersion selectedVersion = selectVersion(message);
final LeaderFrontendState frontend;
if (existing == null) {
- frontend = new LeaderFrontendState(persistenceId(), clientId, store);
+ frontend = new LeaderFrontendState.Enabled(persistenceId(), clientId, store);
knownFrontends.put(clientId.getFrontendId(), frontend);
LOG.debug("{}: created state {} for client {}", persistenceId(), frontend, clientId);
} else {
}
private void handleCommitTransaction(final CommitTransaction commit) {
+ final TransactionIdentifier txId = commit.getTransactionId();
if (isLeader()) {
- commitCoordinator.handleCommit(commit.getTransactionId(), getSender(), this);
+ askProtocolEncountered(txId);
+ commitCoordinator.handleCommit(txId, getSender(), this);
} else {
ActorSelection leader = getLeader();
if (leader == null) {
- messageRetrySupport.addMessageToRetry(commit, getSender(),
- "Could not commit transaction " + commit.getTransactionId());
+ messageRetrySupport.addMessageToRetry(commit, getSender(), "Could not commit transaction " + txId);
} else {
LOG.debug("{}: Forwarding CommitTransaction to leader {}", persistenceId(), leader);
leader.forward(commit, getContext());
}
private void handleCanCommitTransaction(final CanCommitTransaction canCommit) {
- LOG.debug("{}: Can committing transaction {}", persistenceId(), canCommit.getTransactionId());
+ final TransactionIdentifier txId = canCommit.getTransactionId();
+ LOG.debug("{}: Can committing transaction {}", persistenceId(), txId);
if (isLeader()) {
- commitCoordinator.handleCanCommit(canCommit.getTransactionId(), getSender(), this);
+ askProtocolEncountered(txId);
+ commitCoordinator.handleCanCommit(txId, getSender(), this);
} else {
ActorSelection leader = getLeader();
if (leader == null) {
messageRetrySupport.addMessageToRetry(canCommit, getSender(),
- "Could not canCommit transaction " + canCommit.getTransactionId());
+ "Could not canCommit transaction " + txId);
} else {
LOG.debug("{}: Forwarding CanCommitTransaction to leader {}", persistenceId(), leader);
leader.forward(canCommit, getContext());
@SuppressWarnings("checkstyle:IllegalCatch")
protected void handleBatchedModificationsLocal(final BatchedModifications batched, final ActorRef sender) {
+ askProtocolEncountered(batched.getTransactionId());
+
try {
commitCoordinator.handleBatchedModifications(batched, sender, this);
} catch (Exception e) {
boolean isLeaderActive = isLeaderActive();
if (isLeader() && isLeaderActive) {
+ askProtocolEncountered(forwardedReady.getTransactionId());
commitCoordinator.handleForwardedReadyTransaction(forwardedReady, getSender(), this);
} else {
ActorSelection leader = getLeader();
}
private void handleAbortTransaction(final AbortTransaction abort) {
- doAbortTransaction(abort.getTransactionId(), getSender());
+ final TransactionIdentifier transactionId = abort.getTransactionId();
+ askProtocolEncountered(transactionId);
+ doAbortTransaction(transactionId, getSender());
}
void doAbortTransaction(final Identifier transactionID, final ActorRef sender) {
private void closeTransactionChain(final CloseTransactionChain closeTransactionChain) {
if (isLeader()) {
final LocalHistoryIdentifier id = closeTransactionChain.getIdentifier();
+ askProtocolEncountered(id.getClientId());
+
// FIXME: CONTROLLER-1628: stage purge once no transactions are present
store.closeTransactionChain(id, null);
store.purgeTransactionChain(id, null);
@SuppressWarnings("checkstyle:IllegalCatch")
private void createTransaction(final CreateTransaction createTransaction) {
+ askProtocolEncountered(createTransaction.getTransactionId());
+
try {
if (TransactionType.fromInt(createTransaction.getTransactionType()) != TransactionType.READ_ONLY
&& failIfIsolatedLeader(getSender())) {
transactionId);
}
+ // Called on leader only
+ private void askProtocolEncountered(final TransactionIdentifier transactionId) {
+ askProtocolEncountered(transactionId.getHistoryId().getClientId());
+ }
+
+ // Called on leader only
+ private void askProtocolEncountered(final ClientIdentifier clientId) {
+ final LeaderFrontendState state = knownFrontends.get(clientId.getFrontendId());
+ if (state instanceof LeaderFrontendState.Enabled) {
+ LOG.debug("{}: encountered ask-based client {}, disabling transaction tracking", persistenceId(), clientId);
+ persistPayload(clientId, DisableTrackingPayload.create(clientId,
+ datastoreContext.getInitialPayloadSerializedBufferCapacity()), false);
+ }
+ }
+
private void updateSchemaContext(final UpdateSchemaContext message) {
updateSchemaContext(message.getSchemaContext());
}
if (txCommitTimeoutCheckSchedule == null) {
// Schedule a message to be periodically sent to check if the current in-progress
// transaction should be expired and aborted.
- FiniteDuration period = Duration.create(transactionCommitTimeout / 3, TimeUnit.MILLISECONDS);
+ FiniteDuration period = FiniteDuration.create(transactionCommitTimeout / 3, TimeUnit.MILLISECONDS);
txCommitTimeoutCheckSchedule = getContext().system().scheduler().schedule(
period, period, getSelf(),
TX_COMMIT_TIMEOUT_CHECK_MESSAGE, getContext().dispatcher(), ActorRef.noSender());
@Override
protected void applyState(final ActorRef clientActor, final Identifier identifier, final Object data) {
if (data instanceof Payload) {
+ if (data instanceof DisableTrackingPayload) {
+ disableTracking((DisableTrackingPayload) data);
+ return;
+ }
+
try {
store.applyReplicatedPayload(identifier, (Payload)data);
} catch (DataValidationFailedException | IOException e) {