[jboss-user] [JCA/JBoss] - Re: Force Oracle to Rollback _after_ prepare phase?

ypsilon do-not-reply at jboss.com
Wed May 9 06:16:57 EDT 2007


Hi Weston.


"weston.price at jboss.com" wrote : This is a heuristic. 
  | 
  | Technically once a resource agrees in the prepare phase, the commit must occur. Is the offensive resource throwing an Exception in your case? This should force the rollback of the other participant. When you say 'does not respond to the commit request' what do you mean? 

The problem is that the resource seems to be no longer available. The TCP-Socket times out. This of course means that the commit request might have reached it's destination and thereby caused the commit to be executed, but from my experiences so far this did not happen.
Since all communication is done via HTTP and the ResourceManager itself is not java an Exception is not really possible. In case of a timeout the XAResource at the moment throws a XAException (RMERR).

If I however set up a test case and throw whatever exception in the XAResource the other participant is not being rolled back. Here is some sample code:


  | The Method which does the work looks like this (called remotely):
  | 
  |   /**
  |    * @throws CreateException
  |    * @ejb.interface-method
  |    * @ejb.transaction type="Required"
  |    */
  |    public void jtaTest() throws RemoteException, CreateException {
  | 
  | ctx.lookup("java:/TransactionManager");
  |        try {
  |            TransactionManager transactionManager = (TransactionManager)new InitialContext().lookup("java:/TransactionManager");
  |            log.info(transactionManager.getClass());
  |            transactionManager.getTransaction().enlistResource(new MyXAResource());
  |            AddressValue addy2 = new AddressValue();
  |            addy2.setCity("einestadt");
  |            addy2.setId(new Long(System.currentTimeMillis()));
  |            addy2.setName("ich");
  |            addy2.setStreet("am kamp 12");
  |            AddressUtil.getLocalHome().create(addy2) ;
  |            
  |        } catch (Exception e) {
  |            e.printStackTrace();
  |            ctx.setRollbackOnly();
  |        }
  |   }
  | 
  | 
  | And this is the enlisted XAResource:
  | 
  |     private static class MyXAResource implements XAResource {
  |         Xid managedXid = null;
  | 
  |         public void commit(Xid xid, boolean b) throws XAException {
  |             log.info("Nummer 1:commiting " + xid);
  |             int testFlag=0;
  |             switch (testFlag) { 
  |                 case 0:
  |             
  |                 log.info("Nummer 1:Error during commit");
  |                 throw new XAException(XAException.XA_HEURRB);
  |                 case 1:
  |             
  |                 log.info("Nummer 1:Error during commit");
  |                 throw new RuntimeException("blabla");
  |                 case 2:
  |             
  |                 log.info("Nummer 1:Error during commit");
  |                 throw new XAException(XAException.XAER_RMERR);
  |                 
  |             }
  | 
  |             log.info("Nummer 1:done commiting");
  |         }
  | 
  |         public void end(Xid xid, int i) throws XAException {
  |             log.info("Nummer 1:end transcation " + xid);
  |         }
  | 
  |         public void forget(Xid xid) throws XAException {
  |             log.info("Nummer 1:forget transcation " + xid);
  |         }
  | 
  |         public int getTransactionTimeout() throws XAException {
  |             return 5000;  //To change body of implemented methods use File | Settings | File Templates.
  |         }
  | 
  |         public boolean isSameRM(XAResource xaResource) throws XAException {
  |             log.info("Nummer 1:isSameRM called");
  |             return xaResource == this;
  |         }
  | 
  |         public int prepare(Xid xid) throws XAException {
  |             boolean flag = false;
  |             log.info("Nummer 1: prepare called.");
  |             if (flag) {
  |                 throw new XAException(XAException.XA_RBCOMMFAIL );
  |             }
  | 
  |             return XA_OK;  //To change body of implemented methods use File | Settings | File Templates.
  |         }
  | 
  |         public Xid[] recover(int i) throws XAException {
  |             log.info("Nummer 1:recover called");
  |             return new Xid[0];  //To change body of implemented methods use File | Settings | File Templates.
  |         }
  | 
  |         public void rollback(Xid xid) throws XAException {
  |             boolean flag = false;
  |             if (flag) {
  |                 throw new XAException(XAException.XAER_RMERR );
  |             }
  |         }
  | 
  |         public boolean setTransactionTimeout(int i) throws XAException {
  |             return false;  //To change body of implemented methods use File | Settings | File Templates.
  |         }
  | 
  |         public void start(Xid xid, int flags) throws XAException {
  |             if (xid == null) throw new XAException(XAException.XAER_INVAL);
  |             if (managedXid != null) {
  |              throw new XAException(XAException.XAER_INVAL);
  |             } else {
  |                 managedXid = xid;
  |             }
  |             log.info("Nummer 1:start called " + xid + " i " +flags);
  |         }
  |     }
  | 
  | 

as you can see in commit there is always an XAException being thrown.

here is some logging


  | 11:40:15,195 INFO  [CMRTestFacadeBean] Nummer 1:Error during commit
  | 11:40:15,196 WARN  [TransactionImpl] XAException: tx=TransactionImpl:XidImpl[FormatId=257, GlobalId=toaster/15, BranchQual=, localId=15] errorCode=XA_HEURRB
  | javax.transaction.xa.XAException
  | at eval.cmr.CMRTestFacadeBean$MyXAResource.commit(CMRTestFacadeBean.java:313)action.xa.XAException
  | at org.jboss.tm.TransactionImpl$Resource.commit(TransactionImpl.java:2253)
  |         at org.jboss.tm.TransactionImpl.commitResources(TransactionImpl.java:1784)
  |         at org.jboss.tm.TransactionImpl.commit(TransactionImpl.java:358)
  | ...
  | "weston.price at jboss.com" wrote : This is a heuristic. 
  |   | 
  |   | Technically once a resource agrees in the prepare phase, the commit must occur. Is the offensive resource throwing an Exception in your case? This should force the rollback of the other participant. When you say 'does not respond to the commit request' what do you mean? 
  | 
  | The problem is that the resource seems to be no longer available. The TCP-Socket times out. This of course means that the commit request might have reached it's destination and thereby caused the commit to be executed, but from my experiences so far this did not happen.
  | Since all communication is done via HTTP and the ResourceManager itself is not java an Exception is not really possible.
  | 
  | If I however set up a test case and throw whatever exception in the XAResource the other participant is not being rolled back. Here is some sample code:
  | 
  | 
  |   | The Method which does the work looks like this (called remotely):
  |   | 
  |   |   /**
  |   |    * @throws CreateException
  |   |    * @ejb.interface-method
  |   |    * @ejb.transaction type="Required"
  |   |    */
  |   |    public void jtaTest() throws RemoteException, CreateException {
  |   | 
  |   | ctx.lookup("java:/TransactionManager");
  |   |        try {
  |   |            TransactionManager transactionManager = (TransactionManager)new InitialContext().lookup("java:/TransactionManager");
  |   |            log.info(transactionManager.getClass());
  |   |            transactionManager.getTransaction().enlistResource(new MyXAResource());
  |   |            AddressValue addy2 = new AddressValue();
  |   |            addy2.setCity("einestadt");
  |   |            addy2.setId(new Long(System.currentTimeMillis()));
  |   |            addy2.setName("ich");
  |   |            addy2.setStreet("am kamp 12");
  |   | 	// save the address to the DB		
  |   |            AddressUtil.getLocalHome().create(addy2) ;
  |   |            
  |   |        } catch (Exception e) {
  |   |            e.printStackTrace();
  |   |            ctx.setRollbackOnly();
  |   |        }
  |   |   }
  |   | 
  |   | 
  |   | And this is the enlisted XAResource:
  |   | 
  |   |     private static class MyXAResource implements XAResource {
  |   |         Xid managedXid = null;
  |   | 
  |   |         public void commit(Xid xid, boolean b) throws XAException {
  |   |             log.info("Nummer 1:commiting " + xid);
  |   |             int testFlag=0;
  |   |             switch (testFlag) { 
  |   |                 case 0:
  |   |             
  |   |                 log.info("Nummer 1:Error during commit");
  |   |                 throw new XAException(XAException.XA_HEURRB);
  |   |                 case 1:
  |   |             
  |   |                 log.info("Nummer 1:Error during commit");
  |   |                 throw new RuntimeException("blabla");
  |   |                 case 2:
  |   |             
  |   |                 log.info("Nummer 1:Error during commit");
  |   |                 throw new XAException(XAException.XAER_RMERR);
  |   |                 
  |   |             }
  |   | 
  |   |             log.info("Nummer 1:done commiting");
  |   |         }
  |   | 
  |   |         public void end(Xid xid, int i) throws XAException {
  |   |             log.info("Nummer 1:end transcation " + xid);
  |   |         }
  |   | 
  |   |         public void forget(Xid xid) throws XAException {
  |   |             log.info("Nummer 1:forget transcation " + xid);
  |   |         }
  |   | 
  |   |         public int getTransactionTimeout() throws XAException {
  |   |             return 5000;  //To change body of implemented methods use File | Settings | File Templates.
  |   |         }
  |   | 
  |   |         public boolean isSameRM(XAResource xaResource) throws XAException {
  |   |             log.info("Nummer 1:isSameRM called");
  |   |             return xaResource == this;
  |   |         }
  |   | 
  |   |         public int prepare(Xid xid) throws XAException {
  |   |             boolean flag = false;
  |   |             log.info("Nummer 1: prepare called.");
  |   |             if (flag) {
  |   |                 throw new XAException(XAException.XA_RBCOMMFAIL );
  |   |             }
  |   | 
  |   |             return XA_OK;  //To change body of implemented methods use File | Settings | File Templates.
  |   |         }
  |   | 
  |   |         public Xid[] recover(int i) throws XAException {
  |   |             log.info("Nummer 1:recover called");
  |   |             return new Xid[0];  //To change body of implemented methods use File | Settings | File Templates.
  |   |         }
  |   | 
  |   |         public void rollback(Xid xid) throws XAException {
  |   |             boolean flag = false;
  |   |             if (flag) {
  |   |                 throw new XAException(XAException.XAER_RMERR );
  |   |             }
  |   |         }
  |   | 
  |   |         public boolean setTransactionTimeout(int i) throws XAException {
  |   |             return false;  //To change body of implemented methods use File | Settings | File Templates.
  |   |         }
  |   | 
  |   |         public void start(Xid xid, int flags) throws XAException {
  |   |             if (xid == null) throw new XAException(XAException.XAER_INVAL);
  |   |             if (managedXid != null) {
  |   |              throw new XAException(XAException.XAER_INVAL);
  |   |             } else {
  |   |                 managedXid = xid;
  |   |             }
  |   |             log.info("Nummer 1:start called " + xid + " i " +flags);
  |   |         }
  |   |     }
  |   | 
  |   | 
  | 
  | as you can see in commit there is always an XAException being thrown.
  | 
  | here is some logging
  | 
  | 
  |   | 11:40:15,195 INFO  [CMRTestFacadeBean] Nummer 1:Error during commit
  |   | 11:40:15,196 WARN  [TransactionImpl] XAException: tx=TransactionImpl:XidImpl[FormatId=257, GlobalId=toaster/15, BranchQual=, localId=15] errorCode=XA_HEURRB
  |   | javax.transaction.xa.XAException
  |   | at eval.cmr.CMRTestFacadeBean$MyXAResource.commit(CMRTestFacadeBean.java:313)action.xa.XAException
  |   | at org.jboss.tm.TransactionImpl$Resource.commit(TransactionImpl.java:2253)
  |   |         at org.jboss.tm.TransactionImpl.commitResources(TransactionImpl.java:1784)
  |   |         at org.jboss.tm.TransactionImpl.commit(TransactionImpl.java:358)
  |   | ...
  |   | 11:40:15,209 INFO  [CMRTestFacadeBean] Nummer 1:forget transcation XidImpl[FormatId=257, GlobalId=toaster/15, BranchQual=1, localId=15]
  |   | 11:40:15,242 ERROR [LogInterceptor] TransactionRolledbackException in method: public abstract void eval.cmr.CMRTestFacade.jtaTest() throws javax.ejb.CreateException,java.rmi.RemoteException, causedBy:
  |   | javax.transaction.HeuristicRollbackException
  |   |         at org.jboss.tm.TransactionImpl.checkHeuristics(TransactionImpl.java:1610)
  |   |         at org.jboss.tm.TransactionImpl.commit(TransactionImpl.java:378)
  |   |         at org.jboss.ejb.plugins.TxInterceptorCMT.endTransaction(TxInterceptorCMT.java:501)
  |   |         at org.jboss.ejb.plugins.TxInterceptorCMT.runWithTransactions(TxInterceptorCMT.java:361)
  |   |         at org.jboss.ejb.plugins.TxInterceptorCMT.invoke(TxInterceptorCMT.java:181)
  |   |         at org.jboss.ejb.plugins.SecurityInterceptor.invoke(SecurityInterceptor.java:168)
  |   | 
  |   | 
  |   | 
  | 
  | The address which is created is however being written to the Database.
  | 
  | Is that normal?
  | 
  | Thanks in advance 
  | Greetings
  | PeeR
  | 

View the original post : http://www.jboss.com/index.html?module=bb&op=viewtopic&p=4044224#4044224

Reply to the post : http://www.jboss.com/index.html?module=bb&op=posting&mode=reply&p=4044224



More information about the jboss-user mailing list