[JBoss JIRA] Created: (ISPN-887) XAResource implementation improvements (TransactionalXAResource)
by Mircea Markus (JIRA)
XAResource implementation improvements (TransactionalXAResource)
----------------------------------------------------------------
Key: ISPN-887
URL: https://issues.jboss.org/browse/ISPN-887
Project: Infinispan
Issue Type: Feature Request
Components: Transactions
Affects Versions: 4.2.0.Final
Reporter: Mircea Markus
Assignee: Manik Surtani
Fix For: 5.0.0.Final
Reviewing the code with Jonathan Halliday has brought the following aspects (see TODOs below):
package org.infinispan.transaction.xa;
import org.infinispan.commands.CommandsFactory;
import org.infinispan.commands.tx.CommitCommand;
import org.infinispan.commands.tx.PrepareCommand;
import org.infinispan.commands.tx.RollbackCommand;
import org.infinispan.config.Configuration;
import org.infinispan.context.InvocationContextContainer;
import org.infinispan.context.impl.LocalTxInvocationContext;
import org.infinispan.interceptors.InterceptorChain;
import org.infinispan.util.logging.Log;
import org.infinispan.util.logging.LogFactory;
import javax.transaction.xa.XAException;
import javax.transaction.xa.XAResource;
import javax.transaction.xa.Xid;
/**
* This acts both as an local {@link org.infinispan.transaction.xa.CacheTransaction} and implementor of an {@link
* javax.transaction.xa.XAResource} that will be called by tx manager on various tx stages.
*
* @author Mircea.Markus(a)jboss.com
* @since 4.0
*/
public class TransactionXaAdapter implements XAResource {
private static final Log log = LogFactory.getLog(TransactionXaAdapter.class);
private static boolean trace = log.isTraceEnabled();
//todo - comment why timeout is not used
// - it is useful only if TM and client are in separate processes and TM might fail. this is because a client might tm.begin and then the TM (running separate process) crashes
// - in this scenario the TM won't ever call XAResource.rollback, so these resources would be held there forever
// - not affecting us as in all scenarios TM&XAResource are collocated
private int txTimeout;
private final InvocationContextContainer icc;
private final InterceptorChain invoker;
private final CommandsFactory commandsFactory;
private final Configuration configuration;
private final TransactionTable txTable;
/**
* XAResource is associated with a transaction between enlistment (XAResource.start()) XAResource.end(). It's only the
* boundary methods (prepare, commit, rollback) that need to be "stateless".
* Reefer to section 3.4.4 from JTA spec v.1.1
*/
private final LocalTransaction localTransaction;
public TransactionXaAdapter(LocalTransaction localTransaction, TransactionTable txTable, CommandsFactory commandsFactory,
Configuration configuration, InterceptorChain invoker, InvocationContextContainer icc) {
this.localTransaction = localTransaction;
this.txTable = txTable;
this.commandsFactory = commandsFactory;
this.configuration = configuration;
this.invoker = invoker;
this.icc = icc;
}
/**
* This can be call for any transaction object. See Section 3.4.6 (Resource Sharing) from JTA spec v1.1.
*/
public int prepare(Xid xid) throws XAException {
//todo if I throw an exception here then I should also cleanup resources as .rollback might never be called!!
LocalTransaction localTransaction = getLocalTransactionAndValidate(xid);
//todo - same as last comment
validateNotMarkedForRollback(localTransaction);
if (configuration.isOnePhaseCommit()) {
if (trace) log.trace("Received prepare for tx: {0}. Skipping call as 1PC will be used.", xid);
return XA_OK;
}
PrepareCommand prepareCommand = commandsFactory.buildPrepareCommand(localTransaction.getGlobalTransaction(), localTransaction.getModifications(), configuration.isOnePhaseCommit());
if (trace) log.trace("Sending prepare command through the chain: " + prepareCommand);
LocalTxInvocationContext ctx = icc.createTxInvocationContext();
ctx.setLocalTransaction(localTransaction);
try {
invoker.invoke(ctx, prepareCommand);
if (localTransaction.isReadOnly()) {
if (trace) log.trace("Readonly transaction: " + localTransaction.getGlobalTransaction());
// force a cleanup to release any objects held. Some TMs don't call commit if it is a READ ONLY tx. See ISPN-845
commit(xid, false);
return XA_RDONLY;
} else {
return XA_OK;
}
} catch (Throwable e) {
// todo if I throw this exception make sure that all locks are 100% cleaned up, as TM won't do any rollback call on it.
// todo - handle this! -> if only a node fails to ack tx prepare, and that node is still part of the cluster, it needs to be sync with tx state.
// one way of doing this is by pushing the tx state to that node until one of two happens: a) node ack or b) node is shunned from the cluster
log.error("Error while processing PrepareCommand", e);
throw new XAException(XAException.XAER_RMERR);
}
}
/**
* Same comment as for {@link #prepare(javax.transaction.xa.Xid)} applies for commit.
*/
public void commit(Xid xid, boolean isOnePhase) throws XAException {
LocalTransaction localTransaction = getLocalTransactionAndValidate(xid);
if (trace) log.trace("committing transaction {0}", localTransaction.getGlobalTransaction());
try {
LocalTxInvocationContext ctx = icc.createTxInvocationContext();
ctx.setLocalTransaction(localTransaction);
// todo this needs to be split in two:
// - configuration.isOnePhaseCommit() this is not "as important", as the user ack that it doesn't "really" need consistency
// - on the other case ("isOnePhase"==true) make sure that this method either commits successfully or it fails and cleans up logs eventually
if (configuration.isOnePhaseCommit() || isOnePhase) {
validateNotMarkedForRollback(localTransaction);
if (trace) log.trace("Doing an 1PC prepare call on the interceptor chain");
PrepareCommand command = commandsFactory.buildPrepareCommand(localTransaction.getGlobalTransaction(), localTransaction.getModifications(), true);
try {
invoker.invoke(ctx, command);
} catch (Throwable e) {
log.error("Error while processing 1PC PrepareCommand", e);
throw new XAException(XAException.XAER_RMERR);
}
} else {
CommitCommand commitCommand = commandsFactory.buildCommitCommand(localTransaction.getGlobalTransaction());
try {
invoker.invoke(ctx, commitCommand);
} catch (Throwable e) {
log.error("Error while processing 1PC PrepareCommand", e);
throw new XAException(XAException.XAER_RMERR);
}
}
} finally {
cleanup(localTransaction);
}
}
/**
* Same comment as for {@link #prepare(javax.transaction.xa.Xid)} applies for commit.
*/
public void rollback(Xid xid) throws XAException {
rollbackImpl(xid, commandsFactory, icc, invoker, txTable);
}
public static void rollbackImpl(Xid xid, CommandsFactory commandsFactory, InvocationContextContainer icc, InterceptorChain invoker, TransactionTable txTable) throws XAException {
LocalTransaction localTransaction = txTable.getLocalTransaction(xid);
if (localTransaction == null) {
if (trace) log.trace("no tx found for {0}", xid);
throw new XAException(XAException.XAER_NOTA);
}
if (trace) log.trace("rollback transaction {0} ", localTransaction.getGlobalTransaction());
RollbackCommand rollbackCommand = commandsFactory.buildRollbackCommand(localTransaction.getGlobalTransaction());
LocalTxInvocationContext ctx = icc.createTxInvocationContext();
ctx.setLocalTransaction(localTransaction);
try {
invoker.invoke(ctx, rollbackCommand);
} catch (Throwable e) {
log.error("Exception while rollback", e);
throw new XAException(XAException.XA_HEURHAZ);
} finally {
cleanupImpl(localTransaction, txTable, icc);
}
}
private LocalTransaction getLocalTransactionAndValidate(Xid xid) throws XAException {
LocalTransaction localTransaction1 = txTable.getLocalTransaction(xid);
if (localTransaction1 == null) {
log.error("This should not happen when XAResource and TM are in the same process! No tx found for {0}", xid);
throw new XAException(XAException.XAER_NOTA);
}
return localTransaction1;
}
public void start(Xid xid, int i) throws XAException {
localTransaction.setXid(xid);
txTable.addLocalTransactionMapping(localTransaction);
if (trace) log.trace("start called on tx " + this.localTransaction.getGlobalTransaction());
}
public void end(Xid xid, int i) throws XAException {
if (trace) log.trace("end called on tx " + this.localTransaction.getGlobalTransaction());
}
public void forget(Xid xid) throws XAException {
if (trace) log.trace("forget called");
}
public int getTransactionTimeout() throws XAException {
if (trace) log.trace("start called");
return txTimeout;
}
public boolean isSameRM(XAResource xaResource) throws XAException {
if (!(xaResource instanceof TransactionXaAdapter)) {
return false;
}
TransactionXaAdapter other = (TransactionXaAdapter) xaResource;
return other.equals(this);
}
public Xid[] recover(int i) throws XAException {
if (trace) log.trace("recover called: " + i);
return null;
}
public boolean setTransactionTimeout(int i) throws XAException {
this.txTimeout = i;
return true;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof TransactionXaAdapter)) return false;
TransactionXaAdapter that = (TransactionXaAdapter) o;
return this.localTransaction.equals(that.localTransaction);
}
@Override
public int hashCode() {
return localTransaction.getGlobalTransaction().hashCode();
}
@Override
public String toString() {
return "TransactionXaAdapter{" +
"localTransaction=" + localTransaction +
'}';
}
private void validateNotMarkedForRollback(LocalTransaction localTransaction) throws XAException {
if (localTransaction.isMarkedForRollback()) {
if (trace) log.trace("Transaction already marked for rollback: {0}", localTransaction);
throw new XAException(XAException.XA_RBROLLBACK);
}
}
private void cleanup(LocalTransaction localTransaction) {
TransactionXaAdapter.cleanupImpl(localTransaction, txTable, icc);
}
private static void cleanupImpl(LocalTransaction localTransaction, TransactionTable txTable, InvocationContextContainer icc) {
txTable.removeLocalTransaction(localTransaction);
icc.suspend();
}
}
--
This message is automatically generated by JIRA.
-
For more information on JIRA, see: http://www.atlassian.com/software/jira
13 years, 7 months
[JBoss JIRA] Created: (ISPN-1063) Validation in TransactionFactory.init should be moved to ConfigurationValidatingVisitor
by Galder Zamarreño (JIRA)
Validation in TransactionFactory.init should be moved to ConfigurationValidatingVisitor
---------------------------------------------------------------------------------------
Key: ISPN-1063
URL: https://issues.jboss.org/browse/ISPN-1063
Project: Infinispan
Issue Type: Enhancement
Components: Configuration, Transactions
Reporter: Galder Zamarreño
Assignee: Mircea Markus
Fix For: 5.0.0.CR1
2:25:00 PM galderz: mmarkus: hi
2:25:26 PM mmarkus: hi galderz
2:26:11 PM galderz: hey mmarkus, i was wondering if the validation in TransactionFactory.init would be better suited for ConfigurationValidatingVisitor ?
2:26:30 PM galderz: i mean, the validation about the incompatible configuration options
2:28:49 PM mmarkus: galderz: which validation exactly? there's no validation in TransactionFactory.init ..
2:33:51 PM galderz: if (txFactoryEnum == null) { ....
2:34:01 PM galderz: Unsupported combination (dldEnabled, recoveryEnabled, xa) = (%s, %s, %s)
2:34:14 PM galderz: that's validation of the configuration afact
2:34:28 PM galderz: boolean dldEnabled = configuration.isEnableDeadlockDetection();
boolean recoveryEnabled = configuration.isTransactionRecoveryEnabled();
boolean xa = !configuration.isUseSynchronizationForTransactions();
2:37:58 PM mmarkus: galderz: yes, good point it should move to ConfigurationValidatingVisitor
--
This message is automatically generated by JIRA.
For more information on JIRA, see: http://www.atlassian.com/software/jira
13 years, 7 months
[JBoss JIRA] Created: (ISPN-1091) HotRod clients should failover if encountering a SuspectException
by Galder Zamarreño (JIRA)
HotRod clients should failover if encountering a SuspectException
-----------------------------------------------------------------
Key: ISPN-1091
URL: https://issues.jboss.org/browse/ISPN-1091
Project: Infinispan
Issue Type: Bug
Components: Cache Server
Affects Versions: 4.2.1.FINAL
Reporter: Galder Zamarreño
Assignee: Galder Zamarreño
Fix For: 4.2.2.BETA1, 4.2.2.FINAL, 5.0.0.CR2
As Michal rightly indicated in JBPAPP-6473, Hot Rod clients need to be able to deal with SuspectException errors and failover rather than bubbling up. In the future the server will make sure the right error code is returned, but in the absence of that, the error message can be inspected.
--
This message is automatically generated by JIRA.
For more information on JIRA, see: http://www.atlassian.com/software/jira
13 years, 7 months
[JBoss JIRA] Created: (ISPN-1099) Old message ID sent back when failure reading magic byte
by Galder Zamarreño (JIRA)
Old message ID sent back when failure reading magic byte
--------------------------------------------------------
Key: ISPN-1099
URL: https://issues.jboss.org/browse/ISPN-1099
Project: Infinispan
Issue Type: Bug
Components: Cache Server
Affects Versions: 5.0.0.CR1, 4.2.1.FINAL
Reporter: Galder Zamarreño
Assignee: Galder Zamarreño
Fix For: 4.2.2.BETA1, 4.2.2.FINAL, 5.0.0.CR2, 5.0.0.FINAL
If the server fails to read anything before the message id, for example when reading the magic byte:
[JBoss] 00:32:02,733 TRACE [HotRodEncoder$] Encode msg Response{messageId=2421, operation=PutResponse, status=Success, cacheName=}
...
[JBoss] org.infinispan.server.hotrod.HotRodException: org.infinispan.server.hotrod.InvalidMagicIdException: Error reading magic byte or message id: 255
The error response sent back will contain the previous message ID and the client won't like it:
2011/04/29 00:32:02:733 EDT [WARN ][Runner - 0] HOST perf01.mw.lab.eng.bos.redhat.com:rootProcess:E - Error sampling data: <org.infinispan.client.hotrod.exceptions.InvalidResponseException:: Invalid message id. Expected 2476 and received 2421>
I don't know however the root of the InvalidMagicIdException but in such situation where the server did not get to read the message id, it will return 0 as message id and the client needs to be able to deal w/ it accordingly.
--
This message is automatically generated by JIRA.
For more information on JIRA, see: http://www.atlassian.com/software/jira
13 years, 7 months
[JBoss JIRA] Created: (ISPN-1085) TopologyAwareConsistentHash can run in an endless loop when rehashing
by Jürgen Kellerer (JIRA)
TopologyAwareConsistentHash can run in an endless loop when rehashing
---------------------------------------------------------------------
Key: ISPN-1085
URL: https://issues.jboss.org/browse/ISPN-1085
Project: Infinispan
Issue Type: Bug
Components: Distributed Cache
Affects Versions: 4.2.1.FINAL
Environment: Infinispan 4.2.1 using distributed caches and 3 cluster nodes with siteId and machineId (siteId is the same on all nodes, machineId is different)
Reporter: Jürgen Kellerer
Assignee: Mircea Markus
I'm not exactly sure how to reproduce it and why it happened but at least the problem is a quality / error handling issue.
TopologyAwareConsistentHash can run in an endless loop when rehashing runs and 'numOwners' is greater than the available addresses in 'processSequence'.
The endless loop is in the method _getOwners()_ and the reason for it is shown in the simplified snippet below. It would really be helpful if the method either throws an exception with an exact definition what went wrong (e.g. including the address list and numOwners count) or handle the case if it's normal that this can happen when the cluster is just about to be built up.
{code:java}
private List<Address> getOwners(Address address, int numOwners) {
...
ArrayList<Address> processSequence = ...
...
List<Address> result = new ArrayList<Address>();
while (result.size() < numOwners) {
Iterator<Address> addrIt = processSequence.iterator();
while (addrIt.hasNext()) {
result.add(addrIt.next());
addrIt.remove();
}
}
return result;
}
{code}
--
This message is automatically generated by JIRA.
For more information on JIRA, see: http://www.atlassian.com/software/jira
13 years, 7 months
[JBoss JIRA] Created: (ISPN-1105) infinispan-tools fails to build with JDK 7 early access
by Trustin Lee (JIRA)
infinispan-tools fails to build with JDK 7 early access
-------------------------------------------------------
Key: ISPN-1105
URL: https://issues.jboss.org/browse/ISPN-1105
Project: Infinispan
Issue Type: Bug
Reporter: Trustin Lee
Assignee: Manik Surtani
Priority: Minor
{{infinispan-tools}} depends on {{com.sun.tools}} to compile Javadoc doclets. The dependency is only activated for Sun JDK currently. Since JDK 7, Oracle changed the vendor string from {{Sun Microsystems, Inc.}} to {{Oracle Corporation}}. Because of this change, the {{tools.jar}} is dropped from the build class path when Maven was invoked by JDK 7, resulting in the build failure.
--
This message is automatically generated by JIRA.
For more information on JIRA, see: http://www.atlassian.com/software/jira
13 years, 7 months