/*
* JBoss, Home of Professional Open Source
* Copyright 2009 Red Hat Inc. and/or its affiliates and other
* contributors as indicated by the @author tags. All rights reserved.
* See the copyright.txt in the distribution for a full listing of
* individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.infinispan.interceptors.base;
import org.infinispan.commands.control.LockControlCommand;
import org.infinispan.commands.tx.RollbackCommand;
import org.infinispan.context.Flag;
import org.infinispan.context.InvocationContext;
import org.infinispan.context.impl.LocalTxInvocationContext;
import org.infinispan.context.impl.TxInvocationContext;
import org.infinispan.factories.annotations.Inject;
import org.infinispan.factories.annotations.Start;
import org.infinispan.remoting.rpc.RpcManager;
import org.infinispan.transaction.LockingMode;
import org.infinispan.transaction.xa.CacheTransaction;
/**
* Acts as a base for all RPC calls
*
* @author <a href="mailto:manik@jboss.org">Manik Surtani (manik@jboss.org)</a>
* @author Mircea.Markus@jboss.com
* @since 4.0
*/
public abstract class BaseRpcInterceptor extends CommandInterceptor {
protected RpcManager rpcManager;
@Inject
public void init(RpcManager rpcManager) {
this.rpcManager = rpcManager;
}
protected boolean defaultSynchronous;
protected long timeout;
@Start
public void init() {
defaultSynchronous = configuration.getCacheMode().isSynchronous();
timeout = configuration.getSyncReplTimeout();
}
@Override
public Object visitLockControlCommand(TxInvocationContext ctx, LockControlCommand command) throws Throwable {
Object retVal = invokeNextInterceptor(ctx, command);
if (ctx.isOriginLocal()) {
//unlock will happen async as it is a best effort
boolean sync = !command.isUnlock();
command.setFlags(ctx.getFlags());
((LocalTxInvocationContext) ctx).remoteLocksAcquired(rpcManager.getTransport().getMembers());
rpcManager.broadcastRpcCommand(command, sync, false, false);
}
return retVal;
}
protected final boolean isSynchronous(InvocationContext ctx) {
if (ctx.hasFlag(Flag.FORCE_SYNCHRONOUS))
return true;
else if (ctx.hasFlag(Flag.FORCE_ASYNCHRONOUS))
return false;
return defaultSynchronous;
}
protected final boolean isLocalModeForced(InvocationContext ctx) {
if (ctx.hasFlag(Flag.CACHE_MODE_LOCAL)) {
if (getLog().isTraceEnabled()) getLog().trace("LOCAL mode forced on invocation. Suppressing clustered events.");
return true;
}
return false;
}
protected static boolean shouldInvokeRemoteTxCommand(TxInvocationContext ctx) {
// just testing for empty modifications isn't enough - the Lock API may acquire locks on keys but won't
// register a Modification. See ISPN-711.
return ctx.isOriginLocal() && (ctx.hasModifications() ||
!((LocalTxInvocationContext) ctx).getRemoteLocksAcquired().isEmpty());
}
/**
* check if the rollback command should be sent remotely or not.
*
* Rules:
* 1) if prepare was sent, then the rollback should be sent
* 2) if prepare was not sent then we have two cases:
* a) in total order, no locks are acquired during execution, so we can avoid the invoke remotely
* b) in pessimist locking, lock *can* be acquired and then the command should be sent
*
* @param ctx the invocation context
* @param command the rollback command
* @return true if it should be invoked, false otherwise
*/
protected final boolean shouldInvokeRemoteRollbackCommand(TxInvocationContext ctx, RollbackCommand command) {
CacheTransaction cacheTransaction = ctx.getCacheTransaction();
command.setPrepareSent(cacheTransaction.wasPrepareSent());
boolean totalOrder = command.getGlobalTransaction().getReconfigurableProtocol().useTotalOrder();
return cacheTransaction.wasPrepareSent() ||
(!totalOrder && configuration.getTransactionLockingMode() == LockingMode.PESSIMISTIC);
}
}