5 Replies Latest reply on Nov 3, 2009 1:25 PM by Jacques-Olivier Goussard

    Connection.close() creates an XAConnection

    Jacques-Olivier Goussard Newbie

      Hi
      I've the following code (excerp - can post the full source):

      com.arjuna.ats.jta.UserTransaction.userTransaction().begin();

      TransactionalDriver arjunaJDBC2Driver = new TransactionalDriver();

      Connection conn1 = arjunaJDBC2Driver.connect("jdbc:arjuna:jdbc/foo", dbProps);

      Connection conn2 = arjunaJDBC2Driver.connect("jdbc:arjuna:jdbc/foo", dbProps);

      Statement stmt = conn2.createStatement();
      stmt.execute("SELECT 1 FROM DUAL");
      stmt.close();

      conn2.close();

      conn1.close();

      com.arjuna.ats.jta.UserTransaction.userTransaction().commit();

      As you can see, nothing is done with conn1 - however, the conn1.close() will trigger a getXAConnection() on the DataSource:
      at org.jboss.JDBCCloseTest$LoggedDataSource.getXAConnection(JDBCCloseTest.java:35)
      at com.arjuna.ats.internal.jdbc.IndirectRecoverableConnection.createConnection(IndirectRecoverableConnection.java:429)
      at com.arjuna.ats.internal.jdbc.IndirectRecoverableConnection.getConnection(IndirectRecoverableConnection.java:298)
      at com.arjuna.ats.internal.jdbc.IndirectRecoverableConnection.getResource(IndirectRecoverableConnection.java:206)
      at com.arjuna.ats.internal.jdbc.ConnectionImple.close(ConnectionImple.java:349)
      at org.jboss.JDBCCloseTest.main(JDBCCloseTest.java:114)

      How come? It's like of the close on conn2 had released the underlying XAConnection and the close on conn1 tries to re-acquire one (to close it!). It looks like a lazyness issue in JBossTS, where conn1 fails to detect that nothing was done on it. This creates connection leaks in my code.
      Any ideas ??
      /jog

        • 1. Re: Connection.close() creates an XAConnection
          Jonathan Halliday Master

          I agree the driver is doing an unnecessary connection init, but only because your app code is doing likewise - why does your app get a conn you have no intention of using? I also don't follow where the connection leak occurs - it open a connection then closes it right away.

          • 2. Re: Connection.close() creates an XAConnection
            Jacques-Olivier Goussard Newbie

            Looking into the JBossTS code it seems the issue is the following: because at the point where I create conn2 I didn't do yet anything with conn1, the two connections are not associated to the same transaction. The transaction association for ConnectionImple is done in the createStatement() call (via registerDatabase), so the driver returns me 2 different instances (conn1 != conn2) which is not what the doc says. The doc says that inside a single transaction the driver should do pooling - and I expect this to be true whatever order I chose for my JDBC calls.
            So with this code, even if I create a statement on conn1 AFTER I do so on conn2, the two connections will create two XAConnection instead of one - this is my leak problem.
            The only way of making this work is:
            com.arjuna.ats.jta.UserTransaction.userTransaction().begin();
            Connection conn1 = arjunaJDBC2Driver.connect("jdbc:arjuna:jdbc/foo", dbProps);
            // Associate conn1 with transaction
            conn1.createStatement();
            Connection conn2 = arjunaJDBC2Driver.connect("jdbc:arjuna:jdbc/foo", dbProps);
            // Now conn1 == conn2 - without the createStatement(), that won<t be true

            Looks like a bug to me - transaction association should be done as soon as the connection is created in connect(). Do you agree?
            /jog

            • 3. Re: Connection.close() creates an XAConnection
              Jonathan Halliday Master

              Absolutely not. The docs do need fixing though :-) Logical pooling won't help you - you ask for two connections, you get two connections. The second call can't give you the same connection as the first - it's checked out from the pool by the first call. Pooling will accelerate the

              getConn()
              closeConn()
              getConn()

              sequence though.

              We don't match to the transaction at creation time because its also feasible to do

              getConnection();
              begin();
              use_connection();
              commit();

              and don't get me started on suspending and resuming transactions on the thread whilst holding an open connection handle... This kind of headache is why most sane people use an app server with a proper JCA.

              • 4. Re: Connection.close() creates an XAConnection
                Jacques-Olivier Goussard Newbie

                Hum - but how do you explain that if I do
                tm.begin()
                Connection conn1 = driver.connect();
                Conenction conn2 = driver.connect();
                then
                conn1 != conn2
                but doing
                tm.begin()
                Connection conn1 = driver.connect();
                conn1.createStatement();
                Conenction conn2 = driver.connect();
                then
                conn1 == conn2
                ?
                In both cases I asked for 2 connections, but I didn't get two in the second case (the == above is the real == java operator).

                • 5. Re: Connection.close() creates an XAConnection
                  Jacques-Olivier Goussard Newbie

                  Ah - and I forgot to add that
                  tm.begin();
                  Connection conn1 = driver.connect();
                  Connection conn2 = driver.connect();
                  Statement stmt = conn2.createStatement();
                  stmt.execute("SELEC...");
                  stmt.close();
                  conn2.close();
                  conn1.close();

                  will generate, in the conn1.close() call:

                  Exception in thread "main" java.sql.SQLException: [com.arjuna.ats.internal.jdbc.delisterror] Delist of resource failed.
                  at com.arjuna.ats.internal.jdbc.ConnectionImple.close(ConnectionImple.java:352)
                  at org.jboss.JDBCCloseTest.main(JDBCCloseTest.java:121)
                  Exception in thread "main" java.sql.SQLException: [com.arjuna.ats.internal.jdbc.delisterror] Delist of resource failed.
                  at com.arjuna.ats.internal.jdbc.ConnectionImple.close(ConnectionImple.java:352)
                  at org.jboss.JDBCCloseTest.main(JDBCCloseTest.java:121)

                  2009-11-03 13:22:14,023 [main] WARN com.arjuna.ats.jta.logging.loggerI18N - [com.arjuna.ats.internal.jta.transaction.arjunacore.unknownresource] [com.arjuna.ats.internal.jta.transaction.arjunacore.unknownresource] TransactionImple.delistResource - unknown resource

                  So again - conn1 is not enlisted in the transaction but close tries to delist it it seems.