While stress testing my JPA based DAO layer (Running 500 simultanious updates at the same time each in a separate thread). I encountered following – system always stuck unable to make any progress.
The problem was, that there were no available connections at some point for any thread, so no running thread could make any progress.
I have investigated this for a while and the root was REQUIRES_NEW annotation on add method in one of my JPA DAO's.
So the scenario was:
- Test starts acquiring new
ConnectionfromConnectionPoolto start transaction. - After some initial phase, I call
addon myDAO, causing it to request anotherConnectionfromConnectionPoolwhich there are no, because all theConnectionsby that time, were taken by parallel running tests.
I tried to play with DataSource configurations
c3p0stucksDBCPstucksBoneCPstucksMySQLDataSourcefail some requests, with error – number of connections exceeded allowed.
Although I solved it by getting read of REQUIRES_NEW, with which all DataSources worked perfectly, still the best result seems to be of MySQLDataSource, since it did not stuck and just fail:)
So it seems you should not use REQUIRES_NEW at all, if you expect high throughput.
And my question:
Is there a configuration for either DataSources that could prevent this REQUIRES_NEW problem?
I played with checkout timeout in c3p0, and tests started to fail, as expected.
- 2 sec – 8 % passed
- 4 sec – 12 % passed
- 6 sec – 16 % passed
- 8 sec – 26 % passed
- 10 sec – 34 % passed
- 12 sec – 36 % passed
- 14/16/18 sec – 40 % passed
This is highly subjective ofcourse.
MySQLDataSource with plain configurations gave 20% of passed tests.
What about configuring a timeout for obtaining the connection? If the connection can’t be obtained in say 2 seconds, the pool will abort and throw an exception.
Also note that
REQUIRESis more typical. Often you’d want a call chain to share a transaction instead of starting a new transaction for each new call in a chain.