9 Replies Latest reply on Jan 15, 2015 12:28 PM by tomjenkinson

    Modifying LocalXAResourceImpl to return RMFAIL out of XAResource::commit() if it does not know whether the database committed or not

    tomjenkinson

      For background, a scenario was recently reported when using the CMR functionality of JBoss EAP which can result in unreported data integrity issues. The issue is reported here: Bug 1181132 – Data inconsistency for CMR when connection is broken after database resource commits. For those unfamiliar with the CMR algorithm, the outcome of a 1PC resource is used to dictate the outcome of the following XA resources. If the 1PC returns rollback, the other resources are rolled back, otherwise they are committed.

       

      > Can LocalXAResource assume something about the XAException error code based on the exception caught

      We have discovered that LocalXAResourceImpl (ironjacamar/LocalXAResourceImpl.java at ironjacamar-1.0.30.Final · ironjacamar/ironjacamar · GitHub) treats any failure from Connection::commit as if the connection is guaranteeing that the resource manager has rolled back. There are some scenarios where this assertion does not hold true. These scenarios are discussed in the SQL specification and covered by SQL states 8006-7 in http://pubs.opengroup.org/onlinepubs/9695959099/toc.pdf:

      ’08006’ — Connection failure

      ’08007’ — Transaction resolution unknown


      > Could the JDBC resource adapter be improved to provide additional hints to the case

      Consider the following:

      driver.commit()

      --> invoke RPC to commit remote resource manager

          --> remote resource manager commits

               --> connection breaks to driver before response can be returned

      I am not familiar with JCA but in those scenarios it is a violation of the XA specification to return RBROLLBACK as RBROLLBACK is not ambiguous and asserts that the resource has rolled back. The correct code to return in that scenario would be RMFAIL. I have a very basic prototype that checks the SQLException from the ResourceException within the jbossts LocalXAResourceImpl:

      https://github.com/tomjenkinson/ironjacamar/compare/ironjacamar:1.0...tomjenkinson:1181132?expand=1

      You will see from my diff I have looked at the linked SQLException and checked if it is one of the known connection failures (after a remote call has started) from the SQL spec. You will also see that the change is localized solely in the jbossts package. That being said - I haven't actually tested it but I wanted to communicate what I think we need here for your feedback on this.

       

       

      EDIT: Including the stack trace:

       

      14:37:09,538 WARN  [com.arjuna.ats.jta] (EJB default - 5) ARJUNA016036: commit on < formatId=131077, gtrid_length=29, bqual_length=36, tx_uid=0:ffff0a280468:35b4979e:54b3cdf0:2b, node_name=1, branch_uid=0:ffff0a280468:35b4979e:54b3cdf0:30, subordinatenodename=null, eis_name=java:jboss/xa-datasources/CrashRecoveryDS > (LocalXAResourceImpl@485b0678[connectionListener=134bf9b1 connectionManager=5005d564 warned=false currentXid=null productName=PostgreSQL productVersion=9.3.5 jndiName=java:jboss/xa-datasources/CrashRecoveryDS]) failed with exception $XAException.XA_RBROLLBACK: org.jboss.jca.core.spi.transaction.local.LocalXAException: IJ001156: Could not commit local transaction

          at org.jboss.jca.core.tx.jbossts.LocalXAResourceImpl.commit(LocalXAResourceImpl.java:180)

          at com.arjuna.ats.internal.jta.resources.arjunacore.CommitMarkableResourceRecord.commit(CommitMarkableResourceRecord.java:495) [jbossjts-jacorb-4.17.29.Final-redhat-1.jar:4.17.29.Final-redhat-1]

          at com.arjuna.ats.internal.jta.resources.arjunacore.CommitMarkableResourceRecord.topLevelCommit(CommitMarkableResourceRecord.java:476) [jbossjts-jacorb-4.17.29.Final-redhat-1.jar:4.17.29.Final-redhat-1]

          at com.arjuna.ats.arjuna.coordinator.BasicAction.doCommit(BasicAction.java:2754) [jbossjts-jacorb-4.17.29.Final-redhat-1.jar:4.17.29.Final-redhat-1]

          at com.arjuna.ats.arjuna.coordinator.BasicAction.doCommit(BasicAction.java:2670) [jbossjts-jacorb-4.17.29.Final-redhat-1.jar:4.17.29.Final-redhat-1]

          at com.arjuna.ats.arjuna.coordinator.BasicAction.phase2Commit(BasicAction.java:1828) [jbossjts-jacorb-4.17.29.Final-redhat-1.jar:4.17.29.Final-redhat-1]

          at com.arjuna.ats.arjuna.coordinator.BasicAction.End(BasicAction.java:1508) [jbossjts-jacorb-4.17.29.Final-redhat-1.jar:4.17.29.Final-redhat-1]

          at com.arjuna.ats.arjuna.coordinator.TwoPhaseCoordinator.end(TwoPhaseCoordinator.java:98) [jbossjts-jacorb-4.17.29.Final-redhat-1.jar:4.17.29.Final-redhat-1]

          at com.arjuna.ats.arjuna.AtomicAction.commit(AtomicAction.java:162) [jbossjts-jacorb-4.17.29.Final-redhat-1.jar:4.17.29.Final-redhat-1]

          at com.arjuna.ats.internal.jta.transaction.arjunacore.TransactionImple.commitAndDisassociate(TransactionImple.java:1189) [jbossjts-jacorb-4.17.29.Final-redhat-1.jar:4.17.29.Final-redhat-1]

          at com.arjuna.ats.internal.jta.transaction.arjunacore.BaseTransaction.commit(BaseTransaction.java:126) [jbossjts-jacorb-4.17.29.Final-redhat-1.jar:4.17.29.Final-redhat-1]

          at com.arjuna.ats.jbossatx.BaseTransactionManagerDelegate.commit(BaseTransactionManagerDelegate.java:75)

          at org.jboss.as.ejb3.tx.CMTTxInterceptor.endTransaction(CMTTxInterceptor.java:92) [jboss-as-ejb3-7.5.0.Final-redhat-17.jar:7.5.0.Final-redhat-17]

          at org.jboss.as.ejb3.tx.CMTTxInterceptor.invokeInOurTx(CMTTxInterceptor.java:284) [jboss-as-ejb3-7.5.0.Final-redhat-17.jar:7.5.0.Final-redhat-17]

          at org.jboss.as.ejb3.tx.CMTTxInterceptor.required(CMTTxInterceptor.java:345) [jboss-as-ejb3-7.5.0.Final-redhat-17.jar:7.5.0.Final-redhat-17]

          at org.jboss.as.ejb3.tx.CMTTxInterceptor.processInvocation(CMTTxInterceptor.java:243) [jboss-as-ejb3-7.5.0.Final-redhat-17.jar:7.5.0.Final-redhat-17]

          at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:288) [jboss-invocation-1.1.2.Final-redhat-1.jar:1.1.2.Final-redhat-1]

          at org.jboss.as.ejb3.remote.EJBRemoteTransactionPropagatingInterceptor.processInvocation(EJBRemoteTransactionPropagatingInterceptor.java:79) [jboss-as-ejb3-7.5.0.Final-redhat-17.jar:7.5.0.Final-redhat-17]

          at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:288) [jboss-invocation-1.1.2.Final-redhat-1.jar:1.1.2.Final-redhat-1]

          at org.jboss.as.ejb3.component.interceptors.CurrentInvocationContextInterceptor.processInvocation(CurrentInvocationContextInterceptor.java:41) [jboss-as-ejb3-7.5.0.Final-redhat-17.jar:7.5.0.Final-redhat-17]

          at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:288) [jboss-invocation-1.1.2.Final-redhat-1.jar:1.1.2.Final-redhat-1]

          at org.jboss.as.ejb3.component.invocationmetrics.WaitTimeInterceptor.processInvocation(WaitTimeInterceptor.java:43) [jboss-as-ejb3-7.5.0.Final-redhat-17.jar:7.5.0.Final-redhat-17]

          at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:288) [jboss-invocation-1.1.2.Final-redhat-1.jar:1.1.2.Final-redhat-1]

          at org.jboss.as.ejb3.component.interceptors.ShutDownInterceptorFactory$1.processInvocation(ShutDownInterceptorFactory.java:64) [jboss-as-ejb3-7.5.0.Final-redhat-17.jar:7.5.0.Final-redhat-17]

          at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:288) [jboss-invocation-1.1.2.Final-redhat-1.jar:1.1.2.Final-redhat-1]

          at org.jboss.as.ejb3.component.interceptors.LoggingInterceptor.processInvocation(LoggingInterceptor.java:59) [jboss-as-ejb3-7.5.0.Final-redhat-17.jar:7.5.0.Final-redhat-17]

          at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:288) [jboss-invocation-1.1.2.Final-redhat-1.jar:1.1.2.Final-redhat-1]

          at org.jboss.as.ejb3.component.interceptors.EjbExceptionTransformingInterceptorFactories$1.processInvocation(EjbExceptionTransformingInterceptorFactories.java:75) [jboss-as-ejb3-7.5.0.Final-redhat-17.jar:7.5.0.Final-redhat-17]

          at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:288) [jboss-invocation-1.1.2.Final-redhat-1.jar:1.1.2.Final-redhat-1]

          at org.jboss.as.ee.component.NamespaceContextInterceptor.processInvocation(NamespaceContextInterceptor.java:50) [jboss-as-ee-7.5.0.Final-redhat-17.jar:7.5.0.Final-redhat-17]

          at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:288) [jboss-invocation-1.1.2.Final-redhat-1.jar:1.1.2.Final-redhat-1]

          at org.jboss.as.ejb3.component.interceptors.AdditionalSetupInterceptor.processInvocation(AdditionalSetupInterceptor.java:55) [jboss-as-ejb3-7.5.0.Final-redhat-17.jar:7.5.0.Final-redhat-17]

          at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:288) [jboss-invocation-1.1.2.Final-redhat-1.jar:1.1.2.Final-redhat-1]

          at org.jboss.as.ee.component.TCCLInterceptor.processInvocation(TCCLInterceptor.java:45) [jboss-as-ee-7.5.0.Final-redhat-17.jar:7.5.0.Final-redhat-17]

          at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:288) [jboss-invocation-1.1.2.Final-redhat-1.jar:1.1.2.Final-redhat-1]

          at org.jboss.invocation.ChainedInterceptor.processInvocation(ChainedInterceptor.java:61) [jboss-invocation-1.1.2.Final-redhat-1.jar:1.1.2.Final-redhat-1]

          at org.jboss.as.ee.component.ViewService$View.invoke(ViewService.java:185) [jboss-as-ee-7.5.0.Final-redhat-17.jar:7.5.0.Final-redhat-17]

          at org.jboss.as.ejb3.remote.protocol.versionone.MethodInvocationMessageHandler.invokeMethod(MethodInvocationMessageHandler.java:332) [jboss-as-ejb3-7.5.0.Final-redhat-17.jar:7.5.0.Final-redhat-17]

          at org.jboss.as.ejb3.remote.protocol.versionone.MethodInvocationMessageHandler.access$100(MethodInvocationMessageHandler.java:69) [jboss-as-ejb3-7.5.0.Final-redhat-17.jar:7.5.0.Final-redhat-17]

          at org.jboss.as.ejb3.remote.protocol.versionone.MethodInvocationMessageHandler$1.run(MethodInvocationMessageHandler.java:202) [jboss-as-ejb3-7.5.0.Final-redhat-17.jar:7.5.0.Final-redhat-17]

          at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:471) [rt.jar:1.7.0_71]

          at java.util.concurrent.FutureTask.run(FutureTask.java:262) [rt.jar:1.7.0_71]

          at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145) [rt.jar:1.7.0_71]

          at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615) [rt.jar:1.7.0_71]

          at java.lang.Thread.run(Thread.java:745) [rt.jar:1.7.0_71]

          at org.jboss.threads.JBossThread.run(JBossThread.java:122)

      Caused by: javax.resource.ResourceException: SQLException

          at org.jboss.jca.adapters.jdbc.BaseWrapperManagedConnection.checkException(BaseWrapperManagedConnection.java:1202) [ironjacamar-jdbc-1.0.30.Final-redhat-1.jar:1.0.30.Final-redhat-1]

          at org.jboss.jca.adapters.jdbc.local.LocalManagedConnection.commit(LocalManagedConnection.java:99) [ironjacamar-jdbc-1.0.30.Final-redhat-1.jar:1.0.30.Final-redhat-1]

          at org.jboss.jca.core.tx.jbossts.LocalXAResourceImpl.commit(LocalXAResourceImpl.java:175)

          ... 45 more

      Caused by: org.postgresql.util.PSQLException: An I/O error occurred while sending to the backend.

          at org.postgresql.core.v3.QueryExecutorImpl.execute(QueryExecutorImpl.java:281)

          at org.postgresql.jdbc2.AbstractJdbc2Connection.executeTransactionCommand(AbstractJdbc2Connection.java:814)

          at org.postgresql.jdbc2.AbstractJdbc2Connection.commit(AbstractJdbc2Connection.java:838)

          at org.jboss.jca.adapters.jdbc.local.LocalManagedConnection.commit(LocalManagedConnection.java:95) [ironjacamar-jdbc-1.0.30.Final-redhat-1.jar:1.0.30.Final-redhat-1]

          ... 46 more

      Caused by: java.io.EOFException

          at org.postgresql.core.PGStream.ReceiveChar(PGStream.java:284)

          at org.postgresql.core.v3.QueryExecutorImpl.processResults(QueryExecutorImpl.java:1741)

          at org.postgresql.core.v3.QueryExecutorImpl.execute(QueryExecutorImpl.java:255)

          ... 49 more

       

      Message was edited by: Tom Jenkinson

        • 1. Re: Modifying LocalXAResourceImpl to return RMFAIL out of XAResource::commit() if it does not know whether the database committed or not
          jesper.pedersen

          First of all, this isn't specific to your CMR case, as it involves the general contract between the JCA and TM specifications.

          Can LocalXAResource assume something about the XAException error code based on the exception caught

          Could the JDBC resource adapter be improved to provide additional hints to the case

           

          The XAException.XA_RBROLLBACK error code is returned due to JCA 1.7 section 7.6.2.2 and 22.2.1.


          LocalTransactionException doesn't have a way to provide a hint of which XAException error code that should be used. And in this precise case neither does the JDBC API - just a generic SQLException. I don't think you can assume that the 8006 / 8007 is always on the way "back"; it depends on what the vendors interpret the statements as.


          Comparing ironjacamar:1.0...tomjenkinson:1181132 · tomjenkinson/ironjacamar · GitHub

           

          You can't change the LocalTransaction bridge to include JDBC exception information.

           

          The correct solution would be to explore if the JDBC resource adapter can pass back an exception (likely LocalTransactionException or ResourceException) with enough generic information to set the resulting error code to XAER_RMFAIL. The JMS API has a case for this, but none of the JMS resource adapters make use of this to my knowledge. And hence the default error code has to be XA_RBROLLBACK.

           

          However, if you are saying that Narayana will always try to do a rollback when LocalTransaction.commit() fails with any error code (like XAER_RMFAIL), then it should be "safe" to change the default error code. Otherwise it would require extensive testing with all LocalTransaction capable resource adapters.

          • 2. Re: Modifying LocalXAResourceImpl to return RMFAIL out of XAResource::commit() if it does not know whether the database committed or not
            tomjenkinson

            Jesper Pedersen wrote:

             

            First of all, this isn't specific to your CMR case, as it involves the general contract between the JCA and TM specifications.

             

            Agreed. To show at a high level why the current implementation is not correct:

            conn.insert(foo)

            res.commit() -> RBROLLBACK

            assertTrue(conn2.query(foo not exist))

            In the current implementation that assert would fail as the commit did succeed in the RM.

             

             

            Jesper Pedersen wrote:

             

             

            The XAException.XA_RBROLLBACK error code is returned due to JCA 1.7 section 7.6.2.2 and 22.2.1.

             

            LocalTransactionException doesn't have a way to provide a hint of which XAException error code that should be used. And in this precise case neither does the JDBC API - just a generic SQLException. I don't think you can assume that the 8006 / 8007 is always on the way "back"; it depends on what the vendors interpret the statements as.

             

            From my reading of http://docs.oracle.com/javaee/6/api/javax/resource/spi/LocalTransactionException.html it should be possible to return an error code obtained from the underlying SQLException as the second parameter of the constructor http://docs.oracle.com/javaee/6/api/javax/resource/spi/LocalTransactionException.html#LocalTransactionException(java.lang.String, java.lang.String) . And insofar as "I don't think you can assume that the 8006 / 8007 is always on the way "back"; it depends on what the vendors interpret the statements as" is concerned that is fine - that is the point of RMFAIL - its to be returned when you don't know the conclusion of the transaction, unlike RBROLLBACK which is when you do know the outcome which isn't the case here. If it the database rolled back in this case you would have had to return RMFAIL as you just didn't know.

             

            Jesper Pedersen wrote:


            Comparing ironjacamar:1.0...tomjenkinson:1181132 · tomjenkinson/ironjacamar · GitHub

             

            You can't change the LocalTransaction bridge to include JDBC exception information.

             

            The correct solution would be to explore if the JDBC resource adapter can pass back an exception (likely LocalTransactionException or ResourceException) with enough generic information to set the resulting error code to XAER_RMFAIL. The JMS API has a case for this, but none of the JMS resource adapters make use of this to my knowledge. And hence the default error code has to be XA_RBROLLBACK.

             

            However, if you are saying that Narayana will always try to do a rollback when LocalTransaction.commit() fails with any error code (like XAER_RMFAIL), then it should be "safe" to change the default error code. Otherwise it would require extensive testing with all LocalTransaction capable resource adapters.

             

            Ah, right I see what you mean about the LocalTransaction bridge. For LRCO this is less of an issue because users know that it is unsafe. CMR is meant to be safe so that is why I am trying to solve this right now. I have updated my branch to make the modifications at the JDBC layer and utilize a LocalTransactionException which as mentioned above caters for this specific scenario as it can used used for: "Any resource adapter or resource manager specific error conditions related to local transaction management. Examples are ... communication failure during transaction completion".

             

            My branch update is a new commit on the last one but the diff shows the current state:

            Comparing ironjacamar:1.0...tomjenkinson:1181132 · tomjenkinson/ironjacamar · GitHub

            • 3. Re: Modifying LocalXAResourceImpl to return RMFAIL out of XAResource::commit() if it does not know whether the database committed or not
              tomjenkinson

              Jesper Pedersen wrote:

               

              However, if you are saying that Narayana will always try to do a rollback when LocalTransaction.commit() fails with any error code (like XAER_RMFAIL), then it should be "safe" to change the default error code. Otherwise it would require extensive testing with all LocalTransaction capable resource adapters.

               

              If we get RMFAIL we will commit the rest of the XAR. If we get RBROLLBACK (and its the first resource) we will roll back the XAR to get an atomic outcome.

               

              EDIT:

              To be clear, that information actually applies to XA (and CMR), in terms of LRCO if it is changed to return RMFAIL then as the commit of a LRCO happens last during the prepare phase RMFAIL at this point means that the transaction rolls back the XAR the same as RBROLLBACK.

               

              To summarise:

              If you changed LocalXAResourceImple to return RMFAIL for all exceptions out of commit; in LRCO it would have very little impact except the stack trace initial wording but in CMR it causes legitimate rollback of a CMR to cause data integrity issues.

              If you changed LocalXAResourceImple to return RMFAIL for inconclusive outcomes out of the SQL::commit and RBROLLBACK for conclusive outcomes; it would not affect backwards compatibility in LRCO and maintain data integrity for CMR in this use case.

               

              The reassuring thing should be that whether you return RMFAIL or RBROLLBACK it doesn't have an effect on existing LRCO behavior. I have tested this locally with a dummy LRCO (Test various outcomes from a LRCO · fa74b2d · tomjenkinson/narayana · GitHub):

               

              Returning RBROLLBACK results in a RollbackException out of commit:

              WARN: ARJUNA016039: onePhaseCommit on < formatId=131077, gtrid_length=29, bqual_length=36, tx_uid=0:ffff0a037014:cb69:54b7a62d:2, node_name=1, branch_uid=0:ffff0a037014:cb69:54b7a62d:3, subordinatenodename=null, eis_name=0 > (com.hp.mwtests.ts.jta.xa.JTATest$1@69a0bc8a) failed with exception XAException.XA_RBROLLBACK

               

              Returning RMFAIL results in the same exception but a slight (expected) difference in the wording of the WARN as it is XAER_RMFAIL instead of XA_RBROLLBACK:

              WARN: ARJUNA016039: onePhaseCommit on < formatId=131077, gtrid_length=29, bqual_length=36, tx_uid=0:ffff0a037014:cb78:54b7a683:2, node_name=1, branch_uid=0:ffff0a037014:cb78:54b7a683:3, subordinatenodename=null, eis_name=0 > (com.hp.mwtests.ts.jta.xa.JTATest$1@6cedb374) failed with exception XAException.XAER_RMFAIL

              • 4. Re: Modifying LocalXAResourceImpl to return RMFAIL out of XAResource::commit() if it does not know whether the database committed or not
                mmusgrov

                If we get RMFAIL we will commit the rest of the XAR. If we get RBROLLBACK (and its the first resource) we will roll back the XAR to get an atomic outcome.

                Also a side note is that with CMR if we get RMFAIL and the resource actually rolled back we have a data inconsistency but we are able to detect this and report it giving the user the possibility of patching things up. On the other hand if it returns RBROLLBACK instead (but the resource in reality committed) then we cannot detect the heuristic and the user cannot initiate his own manual recovery procedures.


                Also as Tom said LRCO is known to be unsafe but returning RBROLLBACK instead of RMFAIL guarantees unreported data inconsistency whereas returning RMFAIL means that we can at least report the possibility that the last resource committed but the remaining participants were rolled back.

                • 5. Re: Modifying LocalXAResourceImpl to return RMFAIL out of XAResource::commit() if it does not know whether the database committed or not
                  tomjenkinson

                  Jesper Pedersen wrote:

                   

                  The XAException.XA_RBROLLBACK error code is returned due to JCA 1.7 section 7.6.2.2 and 22.2.1.

                   

                  What I am saying about returning RMFAIL is still consistent with JCA 1.7 7.6.2.2.

                   

                  7.6.2.2 One-phase Commit

                      ■ If the RM fails to commit a transaction during a 1PC commit, then the RM should

                      throw one of the XA_RB* exceptions. In the exception case, an RM should roll

                      back the transaction branch’s work and release all held RM resources

                   

                  In the scenario we are discussing the RM did commit the transaction. The error is that the driver has failed to receive a response. Therefore the XA spec says it should be RMFAIL. As mentioned in my reply earlier today, this should have no material effect on existing LRCO use cases.

                  • 6. Re: Re: Modifying LocalXAResourceImpl to return RMFAIL out of XAResource::commit() if it does not know whether the database committed or not
                    jesper.pedersen

                    conn.insert(foo)

                    res.commit() -> RBROLLBACK

                     

                     

                    Yeah, but what happens if the COMMIT never reaches the EIS ?

                     

                    The solution needs to cover both cases, and for all LocalTransaction capable resource adapters - JDBC is just an example.

                    I have updated my branch to make the modifications at the JDBC layer and utilize a LocalTransactionException

                     

                    Maybe, but the String parameter you used is vendor specific, and you can't assume it will contain the error code you expect - there is no contract in JCA specification about this.

                     

                    We would need a new constructor in LocalTransactionException that explicit mandates that the value is a XA error code - ala LocalTransactionException(String msg, int xaErrorCode, Throwable t)

                     

                    If we get RMFAIL we will commit the rest of the XAR.

                    Which is incorrect if the communication error happened before the EIS has reached.

                     

                    7.6.2.2 One-phase Commit

                        ■ If the RM fails to commit a transaction during a 1PC commit, then the RM should

                        throw one of the XA_RB* exceptions. In the exception case, an RM should roll

                        back the transaction branch’s work and release all held RM resources

                     

                    Yes, the last sentence is the key question - what happens in the case where the RM has committed, but can't notify the client about this... The JMS API is better than the JDBC on this point.

                     

                    As mentioned in my reply earlier today, this should have no material effect on existing LRCO use cases.

                    Let me stress again that this has nothing to do with LRCO, CMR, JDBC, ... However, I do agree that XAER_RMFAIL would be a correct error code in certain cases.

                    • 7. Re: Re: Modifying LocalXAResourceImpl to return RMFAIL out of XAResource::commit() if it does not know whether the database committed or not
                      mmusgrov

                       

                      7.6.2.2 One-phase Commit

                          ■ If the RM fails to commit a transaction during a 1PC commit, then the RM should

                          throw one of the XA_RB* exceptions. In the exception case, an RM should roll

                          back the transaction branch’s work and release all held RM resources

                       

                      This part of the specification does not justify returning one of the XA_RB* exceptions since it also says the "an RM should roll back the transaction branch’s work" which is not happening in this scenario. I would argue that if you cannot guarantee the roll back then section 7.6.2.2 does not apply.

                      • 8. Re: Re: Modifying LocalXAResourceImpl to return RMFAIL out of XAResource::commit() if it does not know whether the database committed or not
                        jesper.pedersen

                        Which is why I said, "However, I do agree that XAER_RMFAIL would be a correct error code in certain cases.".

                         

                        We need to come up with a solution that covers all cases, not a specific hack to a single case.

                        • 9. Re: Re: Modifying LocalXAResourceImpl to return RMFAIL out of XAResource::commit() if it does not know whether the database committed or not
                          tomjenkinson

                          Hi, just to update the forum that after agreement from Jesper I have raised the JBJCA that describes at a high level why the LocalXAResourceImpl contravenes the XA specification. [JBJCA-1244] LocalXAResourceImpl returns RBROLLBACK in certain scenarios which violate the XA specification - JBoss Issu…

                           

                          As I am not familiar with all the constraints that the implementation may have to adhere to it just records the agreed XA violation for now.