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]