Bug #46925 XAConnection Map never updated in class SuspendableXAConnection
Description:
In the class com.mysql.jdbc.jdbc2.optional.SuspendableXAConnection (used when pinGlobalTxToPhysicalConnection=true). There's a static Map (XIDS_TO_PHYSICAL_CONNECTIONS) that tracks the Xid with the XAConnection, however this map is never populated.
The effect is that the SuspendableXAConnection is never pinned to the real XA connection.
Instead its creating new connections at each start/end/resume/prepare/... calls.
Affect versions (tested) 5.0.6, 5.0.8, 5.1.8
How to repeat:
Test case that will fail with an unpatched version of the driver :
import javax.sql.XAConnection;
import javax.transaction.xa.XAResource;
import javax.transaction.xa.Xid;
import com.mysql.jdbc.jdbc2.optional.MysqlXADataSource;
import com.mysql.jdbc.jdbc2.optional.SuspendableXAConnection;
import junit.framework.TestCase;
/**
*
* @author Tony Bussieres
*
*/
public class TestPinnedXAConnection extends TestCase {
public void testXAPinnedConnection() throws Exception {
MysqlXADataSource xads1 = new MysqlXADataSource();
MysqlXADataSource xads2 = new MysqlXADataSource();
xads1.setPinGlobalTxToPhysicalConnection(true);
xads1.setUrl("jdbc:mysql://172.16.13.74:4040/TestDB");
xads1.setUser("testuser");
xads1.setPassword("testpass");
xads1.setLogXaCommands(true);
xads2.setPinGlobalTxToPhysicalConnection(true);
xads2.setUrl("jdbc:mysql://172.16.13.74:4040/TestDB2");
xads2.setUser("testuser");
xads2.setPassword("testpass");
xads2.setLogXaCommands(true);
Xid txid = new MyXid(new byte[] { 0x1 }, new byte[] {0xF}); // fake Xid
XAConnection c1 = xads1.getXAConnection();
assertTrue(c1 instanceof SuspendableXAConnection);
// start a transaction on one connection
c1.getXAResource().start(txid, XAResource.TMNOFLAGS);
c1.getXAResource().end(txid, XAResource.TMSUCCESS);
XAConnection c2 = xads2.getXAConnection();
assertTrue(c2 instanceof SuspendableXAConnection);
// prepare on another one. Since we are using a "pinned" connection we should have the same "currentXAConnection" for both SuspendableXAConnection
c2.getXAResource().prepare(txid); // this will fail without the patch.
c2.getXAResource().commit(txid,false);
/* stack trace generated without the patch :
*
com.mysql.jdbc.jdbc2.optional.MysqlXAException: XAER_RMFAIL: The command cannot be executed when global transaction is in the NON-EXISTING state
at com.mysql.jdbc.jdbc2.optional.MysqlXAConnection.mapXAExceptionFromSQLException(MysqlXAConnection.java:600)
at com.mysql.jdbc.jdbc2.optional.MysqlXAConnection.dispatchCommand(MysqlXAConnection.java:583)
at com.mysql.jdbc.jdbc2.optional.MysqlXAConnection.prepare(MysqlXAConnection.java:385)
at com.mysql.jdbc.jdbc2.optional.SuspendableXAConnection.prepare(SuspendableXAConnection.java:136)
at TestXA.testXAPinnedConnection(TestXA.java:40)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at junit.framework.TestCase.runTest(TestCase.java:154)
at junit.framework.TestCase.runBare(TestCase.java:127)
at junit.framework.TestResult$1.protect(TestResult.java:106)
at junit.framework.TestResult.runProtected(TestResult.java:124)
at junit.framework.TestResult.run(TestResult.java:109)
at junit.framework.TestCase.run(TestCase.java:118)
at junit.framework.TestSuite.runTest(TestSuite.java:208)
at junit.framework.TestSuite.run(TestSuite.java:203)
at org.eclipse.jdt.internal.junit.runner.junit3.JUnit3TestReference.run(JUnit3TestReference.java:130)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:460)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:673)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:386)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:196)
*/
}
class MyXid implements Xid {
byte[] gtxid;
byte[] brid;
public MyXid(byte[] gtxid, byte[] brid) {
this.gtxid = gtxid;
this.brid = brid;
}
public byte[] getBranchQualifier() {
return brid;
}
public int getFormatId() {
return 0;
}
public byte[] getGlobalTransactionId() {
return gtxid;
}
}
}
Suggested fix:
patch (for 5.1.8)
--- mysql-connector-java-5.1.8/src/com/mysql/jdbc/jdbc2/optional/SuspendableXAConnection.java 2009-07-14 13:12:13.000000000 -0400
+++ /work/download/mysql-connector-java-5.1.8/src/com/mysql/jdbc/jdbc2/optional/SuspendableXAConnection.java 2009-08-25 13:29:30.000000000 -0400
@@ -75,6 +75,7 @@
if (conn == null) {
conn = new MysqlXAConnection(connectionToWrap,
connectionToWrap.getLogXaCommands());
+ addXAConnectionMapping(xid,conn);
}
return conn;
@@ -83,6 +84,10 @@
private static synchronized void removeXAConnectionMapping(Xid xid) {
XIDS_TO_PHYSICAL_CONNECTIONS.remove(xid);
}
+
+ private static synchronized void addXAConnectionMapping(Xid xid,XAConnection conn) {
+ XIDS_TO_PHYSICAL_CONNECTIONS.put(xid,conn);
+ }
private synchronized void switchToXid(Xid xid) throws XAException {
if (xid == null) {
Portions of this website are copyright © 2001, 2002 The PHP Group
Page generated in 0.058 sec. using MySQL 8.4.7-u6-cloud
Timestamp references displayed by the system are UTC.
Content reproduced on this site is the property of the
respective copyright holders.
It is not reviewed in advance
by Oracle and does not necessarily represent the opinion of
Oracle or any other party.
Description: In the class com.mysql.jdbc.jdbc2.optional.SuspendableXAConnection (used when pinGlobalTxToPhysicalConnection=true). There's a static Map (XIDS_TO_PHYSICAL_CONNECTIONS) that tracks the Xid with the XAConnection, however this map is never populated. The effect is that the SuspendableXAConnection is never pinned to the real XA connection. Instead its creating new connections at each start/end/resume/prepare/... calls. Affect versions (tested) 5.0.6, 5.0.8, 5.1.8 How to repeat: Test case that will fail with an unpatched version of the driver : import javax.sql.XAConnection; import javax.transaction.xa.XAResource; import javax.transaction.xa.Xid; import com.mysql.jdbc.jdbc2.optional.MysqlXADataSource; import com.mysql.jdbc.jdbc2.optional.SuspendableXAConnection; import junit.framework.TestCase; /** * * @author Tony Bussieres * */ public class TestPinnedXAConnection extends TestCase { public void testXAPinnedConnection() throws Exception { MysqlXADataSource xads1 = new MysqlXADataSource(); MysqlXADataSource xads2 = new MysqlXADataSource(); xads1.setPinGlobalTxToPhysicalConnection(true); xads1.setUrl("jdbc:mysql://172.16.13.74:4040/TestDB"); xads1.setUser("testuser"); xads1.setPassword("testpass"); xads1.setLogXaCommands(true); xads2.setPinGlobalTxToPhysicalConnection(true); xads2.setUrl("jdbc:mysql://172.16.13.74:4040/TestDB2"); xads2.setUser("testuser"); xads2.setPassword("testpass"); xads2.setLogXaCommands(true); Xid txid = new MyXid(new byte[] { 0x1 }, new byte[] {0xF}); // fake Xid XAConnection c1 = xads1.getXAConnection(); assertTrue(c1 instanceof SuspendableXAConnection); // start a transaction on one connection c1.getXAResource().start(txid, XAResource.TMNOFLAGS); c1.getXAResource().end(txid, XAResource.TMSUCCESS); XAConnection c2 = xads2.getXAConnection(); assertTrue(c2 instanceof SuspendableXAConnection); // prepare on another one. Since we are using a "pinned" connection we should have the same "currentXAConnection" for both SuspendableXAConnection c2.getXAResource().prepare(txid); // this will fail without the patch. c2.getXAResource().commit(txid,false); /* stack trace generated without the patch : * com.mysql.jdbc.jdbc2.optional.MysqlXAException: XAER_RMFAIL: The command cannot be executed when global transaction is in the NON-EXISTING state at com.mysql.jdbc.jdbc2.optional.MysqlXAConnection.mapXAExceptionFromSQLException(MysqlXAConnection.java:600) at com.mysql.jdbc.jdbc2.optional.MysqlXAConnection.dispatchCommand(MysqlXAConnection.java:583) at com.mysql.jdbc.jdbc2.optional.MysqlXAConnection.prepare(MysqlXAConnection.java:385) at com.mysql.jdbc.jdbc2.optional.SuspendableXAConnection.prepare(SuspendableXAConnection.java:136) at TestXA.testXAPinnedConnection(TestXA.java:40) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) at java.lang.reflect.Method.invoke(Method.java:597) at junit.framework.TestCase.runTest(TestCase.java:154) at junit.framework.TestCase.runBare(TestCase.java:127) at junit.framework.TestResult$1.protect(TestResult.java:106) at junit.framework.TestResult.runProtected(TestResult.java:124) at junit.framework.TestResult.run(TestResult.java:109) at junit.framework.TestCase.run(TestCase.java:118) at junit.framework.TestSuite.runTest(TestSuite.java:208) at junit.framework.TestSuite.run(TestSuite.java:203) at org.eclipse.jdt.internal.junit.runner.junit3.JUnit3TestReference.run(JUnit3TestReference.java:130) at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:460) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:673) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:386) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:196) */ } class MyXid implements Xid { byte[] gtxid; byte[] brid; public MyXid(byte[] gtxid, byte[] brid) { this.gtxid = gtxid; this.brid = brid; } public byte[] getBranchQualifier() { return brid; } public int getFormatId() { return 0; } public byte[] getGlobalTransactionId() { return gtxid; } } } Suggested fix: patch (for 5.1.8) --- mysql-connector-java-5.1.8/src/com/mysql/jdbc/jdbc2/optional/SuspendableXAConnection.java 2009-07-14 13:12:13.000000000 -0400 +++ /work/download/mysql-connector-java-5.1.8/src/com/mysql/jdbc/jdbc2/optional/SuspendableXAConnection.java 2009-08-25 13:29:30.000000000 -0400 @@ -75,6 +75,7 @@ if (conn == null) { conn = new MysqlXAConnection(connectionToWrap, connectionToWrap.getLogXaCommands()); + addXAConnectionMapping(xid,conn); } return conn; @@ -83,6 +84,10 @@ private static synchronized void removeXAConnectionMapping(Xid xid) { XIDS_TO_PHYSICAL_CONNECTIONS.remove(xid); } + + private static synchronized void addXAConnectionMapping(Xid xid,XAConnection conn) { + XIDS_TO_PHYSICAL_CONNECTIONS.put(xid,conn); + } private synchronized void switchToXid(Xid xid) throws XAException { if (xid == null) {