Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Connection pooling and Thread.interrupt()

I am using c3p0 to handle database connection pooling in a multithreaded environment. The question might pertain to other pooling libs, but this is what I have.

Recently I've needed to implement interruption handling on such threads using directly or indirectly c3p0, and have noticed that if interrupt() is called right when c3p0Datasource.getConnection() is trying to fetch me a Connection from the pool, it throws an InterruptedException.

Obviously, this happens because of the wait()

at java.lang.Object.wait(Native Method)
at com.mchange.v2.resourcepool.BasicResourcePool.awaitAvailable(BasicResourcePool.java:1414)

Cool. The question is how do you handle this properly - both is case a) you want to continue with the transaction before your thread terminates, and b) you want to abort.

I've tried a solution that seems to be working fine (posted as answer) - actually, I think this subject is closed. Feel free to chip in otherwise, thanks!

like image 478
Robert Verdes Avatar asked Dec 08 '25 10:12

Robert Verdes


1 Answers

I did a simple test by firing a lot of Connection requests within 1 second, executing a SELECT each time tim make sure the pool bottlenecks, and then calling interrupt().

What I found was that the connection object is fine and dandy after the InterruptedException being caught, even though the stacktrace shows me c3p0 meltdown at awaitAvailable(..). At this very second I'm checking out their sources, and surely, they handle the InterruptedException. They even throw a proper warning:

WARNING: com.mchange.v2.resourcepool.BasicResourcePool@5bcf4b61 -- an attempt to checkout a resource was interrupted, and the pool is still live: some other thread must have either interrupted the Thread attempting checkout!

telling us it's still live, albeit inbetween a lot of word fuzz. Solved.

Here's the test anyway.

ComboPooledDataSource ds = new ComboPooledDataSource();

// testing with various pool sizes - same effect
ds.setMinPoolSize(1);
ds.setMaxPoolSize(5);
ds.setInitialPoolSize(2);

Thread connectingThread = new Thread() {

    public void run() {
        Connection cnxn = null;
        while (true) {
            try {
                cnxn = ds.getConnection();
                System.out.println("Got connection.");
                executeQuery(cnxn);
            } catch (SQLException e) {
                System.out.println("Got exception.");
                e.printStackTrace();

                // SOLUTION:
                Throwable cause = e.getCause();
                if (cause instanceof InterruptedException) {
                    System.out.println("Caught InterruptedException! Cnxn is " + cnxn);

                    // note that cnxn is a com.mchange.v2.c3p0.impl.NewProxyConnection
                    // also note that it's perfectly healthy.
                    //
                    // You may either want to:
                    // a) use the cnxn to submit your the query

                    executeQuery(cnxn);
                    cnxn.close()

                    // b) handle a proper shutdown

                    cnxn.close();

                }
                break;
            }
        }
    };
};

connectingThread.start();
    
try {
    Thread.sleep(1000);
} catch (InterruptedException e) {          e.printStackTrace();        }
    
connectingThread.interrupt();
    
like image 55
Robert Verdes Avatar answered Dec 09 '25 23:12

Robert Verdes



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!