]
Tomas Hofman commented on JBJCA-1396:
-------------------------------------
PR:
dataSource.getConnection() returns broken connection after
XAResource#commit() failed in the same thread
--------------------------------------------------------------------------------------------------------
Key: JBJCA-1396
URL:
https://issues.jboss.org/browse/JBJCA-1396
Project: IronJacamar
Issue Type: Bug
Components: JDBC
Affects Versions: WildFly/IronJacamar 1.4.2.Final
Reporter: Tomas Hofman
Assignee: Tomas Hofman
Priority: Major
Attachments: log_and_config.zip, reproducer.zip
When retrying Usertransaction on same thread after XAResource#commit() failed,
DataSource#getConnection() returns closed connection in new Usertransaction. [1]
[1]
{code}
// 1st attempt.
UserTransaction.begin();
Connection conn = dataSource.getConnection();
Statemnt stmt = conn.createStatement();
stmt.executeUpdate("...");
UserTransaction.commit(); // XAResource#commit() failure with ARJUNA016039.
// retry transaction.
UserTransaction.begin();
Connection conn = dataSource.getConnection(); // returned same physical connection of the
previous transaction.
Statemnt stmt = conn.createStatement(); // SQLException thrown by the connection is
already closed.
{code}
The stacktrace [2] is as follows.
[2]
{code}
// 1st attempt
WARN [com.arjuna.ats.jta] (default task-1) ARJUNA016039: onePhaseCommit on <
formatId=131077, gtrid_length=29, bqual_length=36,
tx_uid=0:ffff7f000001:21fea082:5dc8ed99:f, node_name=1,
branch_uid=0:ffff7f000001:21fea082:5dc8ed99:14, subordinatenodename=null,
eis_name=java:jboss/datasources/ExampleDS >
(LocalXAResourceImpl@6cb4daa9[connectionListener=6a0eecdd connectionManager=36f87501
warned=false currentXid=null productName=H2 productVersion=@PROJECT_VERSION@ (2016-10-31)
jndiName=java:jboss/datasources/ExampleDS]) 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:182)
at
com.arjuna.ats.internal.jta.resources.arjunacore.XAOnePhaseResource.commit(XAOnePhaseResource.java:120)
at
com.arjuna.ats.internal.arjuna.abstractrecords.LastResourceRecord.topLevelOnePhaseCommit(LastResourceRecord.java:172)
at com.arjuna.ats.arjuna.coordinator.BasicAction.onePhaseCommit(BasicAction.java:2386)
at com.arjuna.ats.arjuna.coordinator.BasicAction.End(BasicAction.java:1497)
at
com.arjuna.ats.arjuna.coordinator.TwoPhaseCoordinator.end(TwoPhaseCoordinator.java:96)
at com.arjuna.ats.arjuna.AtomicAction.commit(AtomicAction.java:162)
at
com.arjuna.ats.internal.jta.transaction.arjunacore.TransactionImple.commitAndDisassociate(TransactionImple.java:1287)
at
com.arjuna.ats.internal.jta.transaction.arjunacore.BaseTransaction.commit(BaseTransaction.java:126)
at
com.arjuna.ats.jbossatx.BaseTransactionManagerDelegate.commit(BaseTransactionManagerDelegate.java:94)
at
org.wildfly.transaction.client.LocalTransaction.commitAndDissociate(LocalTransaction.java:75)
at
org.wildfly.transaction.client.ContextTransactionManager.commit(ContextTransactionManager.java:71)
at
org.wildfly.transaction.client.LocalUserTransaction.commit(LocalUserTransaction.java:53)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.jboss.weld.util.reflection.Reflections.invokeAndUnwrap(Reflections.java:410)
at
org.jboss.weld.bean.builtin.CallableMethodHandler.invoke(CallableMethodHandler.java:42)
at
org.jboss.weld.bean.proxy.EnterpriseTargetBeanInstance.invoke(EnterpriseTargetBeanInstance.java:56)
at org.jboss.weld.bean.proxy.ProxyMethodHandler.invoke(ProxyMethodHandler.java:106)
at org.jboss.weldx.transaction.UserTransaction$$Proxy$_$$_Weld$Proxy$.commit(Unknown
Source)
at com.example.HelloServlet.doGet(HelloServlet.java:65)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:686)
...
// 2nd attempt
ERROR [stderr] (default task-1) org.h2.jdbc.JdbcSQLException: The object is already
closed [90007-193]
ERROR [stderr] (default task-1) at
org.h2.message.DbException.getJdbcSQLException(DbException.java:345)
ERROR [stderr] (default task-1) at org.h2.message.DbException.get(DbException.java:179)
ERROR [stderr] (default task-1) at org.h2.message.DbException.get(DbException.java:155)
ERROR [stderr] (default task-1) at org.h2.message.DbException.get(DbException.java:144)
ERROR [stderr] (default task-1) at
org.h2.jdbc.JdbcConnection.checkClosed(JdbcConnection.java:1480)
ERROR [stderr] (default task-1) at
org.h2.jdbc.JdbcConnection.checkClosed(JdbcConnection.java:1458)
ERROR [stderr] (default task-1) at
org.h2.jdbc.JdbcConnection.createStatement(JdbcConnection.java:202)
ERROR [stderr] (default task-1) at
org.jboss.jca.adapters.jdbc.WrappedConnection$1.produce(WrappedConnection.java:357)
ERROR [stderr] (default task-1) at
org.jboss.jca.adapters.jdbc.WrappedConnection$1.produce(WrappedConnection.java:355)
ERROR [stderr] (default task-1) at
org.jboss.jca.adapters.jdbc.SecurityActions.executeInTccl(SecurityActions.java:97)
ERROR [stderr] (default task-1) at
org.jboss.jca.adapters.jdbc.WrappedConnection.createStatement(WrappedConnection.java:355)
ERROR [stderr] (default task-1) at com.example.HelloServlet.doGet(HelloServlet.java:59)
...
{code}
The following document [3] indicates the XAResource#commit() with onePhase=true has
possibility to close the connection when the commit fails. So the connection closing seems
to be correct.
[3]
{code}
"If the resource manager did not commit the transaction and the paramether
onePhase is set to true, the resource manager may throw one of the XA_RB* exceptions.
Upon return, the resource manager has rolled back the branch's work and has
released all held resources."
https://docs.oracle.com/javase/8/docs/api/javax/transaction/xa/XAResource...
{code}
And if java.sql.Connection#close() is called before Usertransaction#commit() on 1st
attempt, DataSource returns a valid/useful connection on 2nd Usertransaction. [4]
But it seems to be difficult to know for user why getConnection() returns closed
connection when the above issue occurred.
[4]
{code}
// 1st attempt.
UserTransaction.begin();
Connection conn = dataSource.getConnection();
Statemnt stmt = conn.createStatement();
stmt.executeUpdate("...");
conn.close(); // connection close is called before commit.
UserTransaction.commit(); // XAResource#commit() failure with ARJUNA016039.
// retry transaction.
UserTransaction.begin();
Connection conn = dataSource.getConnection(); // valid connection will be returned.
{code}