This is an automated email from the ASF dual-hosted git repository.

tabish pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/artemis.git


The following commit(s) were added to refs/heads/main by this push:
     new 39de83eb0c ARTEMIS-5806 don't rollback TX when throwing XAER_NOTA
39de83eb0c is described below

commit 39de83eb0ca0e7f1fa40488e1f032816441bdca3
Author: Justin Bertram <[email protected]>
AuthorDate: Tue Jan 6 16:45:32 2026 -0600

    ARTEMIS-5806 don't rollback TX when throwing XAER_NOTA
    
    Currently the broker will rollback the current transaction associated
    with a session when it is unable to find the XID passed when rolling
    back. This is a pseudo optimization for the case where the current
    transaction has timed out and the client may be holding on to messages.
    
    However, this is a mistake because the current transaction may still be
    valid. One such use-case involves XA transaction recovery in a Java EE
    server where a dedicated recovery process may attempt to rollback a
    transaction that no longer exists (e.g. due to timeout, broker restart,
    etc.) while a valid transaction is still active and associated with the
    Session.
---
 .../artemis/core/server/ActiveMQServerLogger.java  |  5 +-
 .../core/server/impl/ServerSessionImpl.java        | 10 ---
 .../artemis/tests/integration/xa/BasicXaTest.java  | 77 ++++++++++++++++++++++
 3 files changed, 78 insertions(+), 14 deletions(-)

diff --git 
a/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/ActiveMQServerLogger.java
 
b/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/ActiveMQServerLogger.java
index 8f78ac23c1..fa75e685d4 100644
--- 
a/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/ActiveMQServerLogger.java
+++ 
b/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/ActiveMQServerLogger.java
@@ -51,7 +51,7 @@ import 
org.apache.activemq.artemis.spi.core.remoting.Connection;
 /**
  * Logger Codes 220000 - 228999
  */
-@LogBundle(projectCode = "AMQ", regexID = "22[0-8][0-9]{3}", retiredIDs = 
{221026, 221052, 222003, 222012, 222015, 222020, 222021, 222022, 222024, 
222027, 222028, 222029, 222048, 222052, 222058, 222064, 222071, 222078, 222079, 
222083, 222084, 222088, 222090, 222102, 222105, 222110, 222128, 222134, 222135, 
222152, 222159, 222163, 222167, 222170, 222171, 222182, 222190, 222192, 222193, 
222204, 222252, 222255, 222257, 222259, 222260, 222276, 222277, 222288, 224001, 
224002, 224003, 224005, 2 [...]
+@LogBundle(projectCode = "AMQ", regexID = "22[0-8][0-9]{3}", retiredIDs = 
{221026, 221052, 222003, 222012, 222015, 222020, 222021, 222022, 222024, 
222027, 222028, 222029, 222048, 222052, 222058, 222064, 222071, 222078, 222079, 
222083, 222084, 222088, 222090, 222102, 222105, 222110, 222128, 222134, 222135, 
222152, 222159, 222163, 222167, 222170, 222171, 222182, 222190, 222192, 222193, 
222204, 222249, 222252, 222255, 222257, 222259, 222260, 222276, 222277, 222288, 
224001, 224002, 224003, 2 [...]
 public interface ActiveMQServerLogger {
 
    // Note: logger ID 224127 uses 
"org.apache.activemq.artemis.core.server.Queue" for its logger category, rather 
than ActiveMQServerLogger.class.getPackage().getName()
@@ -940,9 +940,6 @@ public interface ActiveMQServerLogger {
    @LogMessage(id = 222248, value = "Unable to remove consumer", level = 
LogMessage.Level.WARN)
    void unableToRemoveConsumer(Throwable e);
 
-   @LogMessage(id = 222249, value = "Unable to rollback on TX timed out", 
level = LogMessage.Level.WARN)
-   void unableToRollbackOnTxTimedOut(Exception e);
-
    @LogMessage(id = 222250, value = "Unable to delete heuristic completion 
from storage manager", level = LogMessage.Level.WARN)
    void unableToDeleteHeuristicCompletion(Exception e);
 
diff --git 
a/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/impl/ServerSessionImpl.java
 
b/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/impl/ServerSessionImpl.java
index 1b2877c12e..815b42057c 100644
--- 
a/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/impl/ServerSessionImpl.java
+++ 
b/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/impl/ServerSessionImpl.java
@@ -1619,16 +1619,6 @@ public class ServerSessionImpl extends 
CriticalComponentImpl implements ServerSe
                // checked heuristic rolled back transactions
                throw new ActiveMQXAException(XAException.XA_HEURRB, 
"transaction has ben heuristically rolled back: " + xid);
             } else {
-               logger.trace("xarollback into {}, xid={} forcing a rollback 
regular", theTx, xid);
-
-               try {
-                  // This could have happened because the TX timed out, at 
this point we would be better on rolling back
-                  // this session as a way to prevent consumers from holding 
their messages
-                  this.rollback(false);
-               } catch (Exception e) {
-                  ActiveMQServerLogger.LOGGER.unableToRollbackOnTxTimedOut(e);
-               }
-
                throw new ActiveMQXAException(XAException.XAER_NOTA, "Cannot 
find xid in resource manager: " + xid);
             }
          } else {
diff --git 
a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/xa/BasicXaTest.java
 
b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/xa/BasicXaTest.java
index 39655666b1..5b68934175 100644
--- 
a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/xa/BasicXaTest.java
+++ 
b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/xa/BasicXaTest.java
@@ -232,6 +232,83 @@ public class BasicXaTest extends ActiveMQTestBase {
       assertNotNull(message);
    }
 
+   @TestTemplate
+   public void testInterleavedXaTxRollbackSuccess() throws Exception {
+      Xid xid1 = newXID();
+      Xid xid2 = newXID();
+      ClientSession producerSession = sessionFactory.createSession();
+      ClientProducer producer = producerSession.createProducer(atestq);
+      ClientConsumer consumer = clientSession.createConsumer(atestq);
+      clientSession.start();
+      Queue testQueue = messagingService.locateQueue(atestq);
+
+      clientSession.start(xid1, XAResource.TMNOFLAGS);
+      ClientMessage message = consumer.receiveImmediate();
+      assertNull(message);
+      clientSession.end(xid1, XAResource.TMSUCCESS);
+
+      clientSession.start(xid2, XAResource.TMNOFLAGS);
+
+      clientSession.rollback(xid1);
+
+      // send message outside any tx
+      producer.send(createTextMessage(clientSession, "m1"));
+      Wait.assertEquals(1, () -> testQueue.getMessageCount());
+
+      message = consumer.receiveImmediate();
+      assertNotNull(message);
+      assertEquals(1, testQueue.getDeliveringCount());
+      message.acknowledge();
+
+      clientSession.end(xid2, XAResource.TMSUCCESS);
+      clientSession.prepare(xid2);
+      clientSession.commit(xid2, false);
+      assertEquals(1, testQueue.getMessagesAcknowledged());
+      assertEquals(0, testQueue.getDeliveringCount());
+      assertEquals(0, testQueue.getMessageCount());
+   }
+
+   @TestTemplate
+   public void testInterleavedXaTxRollbackFailed() throws Exception {
+      Xid xid1 = newXID();
+      Xid xid2 = newXID();
+      ClientSession producerSession = sessionFactory.createSession();
+      ClientProducer producer = producerSession.createProducer(atestq);
+      ClientConsumer consumer = clientSession.createConsumer(atestq);
+      clientSession.start();
+      clientSession.setTransactionTimeout(1);
+      Queue testQueue = messagingService.locateQueue(atestq);
+
+      clientSession.start(xid1, XAResource.TMNOFLAGS);
+      ClientMessage message = consumer.receive(2000);
+      // TX will time out here
+      assertNull(message);
+
+      clientSession.start(xid2, XAResource.TMNOFLAGS);
+
+      try {
+         clientSession.rollback(xid1);
+         fail("This rollback should have failed due to the time out");
+      } catch (XAException e) {
+         assertEquals(XAException.XAER_NOTA, e.errorCode);
+      }
+
+      // send message outside any tx
+      producer.send(createTextMessage(clientSession, "m1"));
+      Wait.assertEquals(1, () -> testQueue.getMessageCount());
+
+      message = consumer.receiveImmediate();
+      assertNotNull(message);
+      assertEquals(1, testQueue.getDeliveringCount());
+      message.acknowledge();
+
+      clientSession.end(xid2, XAResource.TMSUCCESS);
+      clientSession.rollback(xid2);
+      assertEquals(0, testQueue.getMessagesAcknowledged());
+      assertEquals(0, testQueue.getDeliveringCount());
+      assertEquals(1, testQueue.getMessageCount());
+   }
+
    @TestTemplate
    public void testRestartWithTXPrepareDeletedQueue() throws Exception {
 


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to