On Tue, 10 Nov 2009, Mauro Molinari wrote:

Bug reference:      5177
PostgreSQL version: 8.3.8
Description:        Concurrency problem in AbstractJdbc23PooledConnection
Details:

Hello, we're using PostgreSQL JDBC3 driver 8.3-605 to connect to a 8.3.8
Postgres instance. Our application has a JTA-XA transaction infrastructure
managed by Spring and using JBoss Transactions as a JTA implementation.
We're using a connection pool of our own to pool XA connections on top of
which there's JBoss Transactions transactional driver that is managing
connections. Our connection pool infrastructure creates a PGXADataSource
from which it gets new XA connections.

In this scenario, sometimes happens that the PostgreSQL driver fails with
the following exception:

java.lang.NullPointerException
 at
org.postgresql.ds.jdbc23.AbstractJdbc23PooledConnection$ConnectionHandler.in
voke(AbstractJdbc23PooledConnection.java:319)
 at $Proxy5.close(Unknown Source)
 at
com.arjuna.ats.internal.jdbc.ConnectionImple.close(ConnectionImple.java:369)

Looking at the JDBC driver source code, it seems a concurrency problem,
because at row 304-305 the variable con is checked against null.

What is actually happening here is that our code is closing a connection
used to read some data from the DB. This read operation is executed outside
any transaction, so JBoss Transactions is honouring the connection close
request by first calling calling close on the XA connection (and this is
causing the XA connection to be given back to our pool); after that, because
of the actual JDBC connection reports false on isClosed(), JBoss
Transactions is also calling close() on it too... and this generates the
NullPointerException given above.

Looking at the AbstractJdbc23PooledConnection it seems there's no
synchronization at all between isClosed() and close(). My suspect is that in
the previous scenario something like this happens:
1. thread 1: close() is invoked
2. thread 2: isClosed() returns false
3. thread 2: close() is invoked

At operation 2., isClose returns false, while it should return true because
a close request has already been made on thread 1. Anyway, there should be
no problem at all to call close repeatedly on the same connection (as the
JDBC contract states), so the NullPointerException should not happen in any
case.


Attached is a test case which reproduces this problem easily.


Thanks in advance and please let me know how I can monitor this bug report
(is there any bug tracking system for PostgreSQL?).


There is no bug tracker for postgresql in general. The JDBC driver does have a bug tracker, but the mailing list is where most of the action happens.

http://pgfoundry.org/tracker/?group_id=1000224

Kris Jurka
import java.sql.*;
import javax.sql.XAConnection;

import org.postgresql.xa.PGXADataSource;

public class XaCloseTest {

        public static void main(String args[]) throws Exception {
                PGXADataSource ds = new PGXADataSource();
                ds.setServerName("localhost");
                ds.setUser("kjurka");
                ds.setPassword("");
                ds.setDatabaseName("kjurka");
                ds.setPortNumber(5850);

                XAConnection xaconn = ds.getXAConnection();

                Handle h = new Handle();
                h.conn = xaconn.getConnection();

                for (int i=0; i<5; i++) {
                        Closer c = new Closer(h);
                        c.start();
                }

                Opener o = new Opener(xaconn, h);
                o.start();
        }

        private static class Handle {
                public Connection conn;
        }

        private static class Closer extends Thread {
                private final Handle _h;

                public Closer(Handle h) {
                        _h = h;
                }

                public void run() {
                        while (true) {
                                try {
                                        _h.conn.close();
                                } catch (SQLException sqle) {
                                        sqle.printStackTrace();
                                }
                        }
                }
        }

        private static class Opener extends Thread {
                private final XAConnection _xaconn;
                private final Handle _h;

                public Opener(XAConnection xaconn, Handle h) {
                        _xaconn = xaconn;
                        _h = h;
                }

                public void run() {
                        while (true) {
                                try {
                                        _h.conn = _xaconn.getConnection();
                                } catch (SQLException sqle) {
                                        sqle.printStackTrace();
                                }
                        }
                }

        }

}
-- 
Sent via pgsql-bugs mailing list (pgsql-bugs@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-bugs

Reply via email to