https://issues.apache.org/bugzilla/show_bug.cgi?id=48971

--- Comment #5 from Konstantin Kolinko <knst.koli...@gmail.com> 2010-03-28 
21:30:07 UTC ---
Created an attachment (id=25203)
 --> (https://issues.apache.org/bugzilla/attachment.cgi?id=25203)
bug48971_DBCP_reproducer.zip - IllegalStateException caused by stopped timer

Any DBCP pool that has timeBetweenEvictionRunsMillis attribute set to a
positive value will suffer from this issue.

The class that creates the timer is org.apache.commons.pool.impl.EvictionTimer
and is (after being renamed) in tomcat-dbcp.jar, which is in the Common class
loader.

It looks that the TimerThread created by the Timer will belong to the first web
application that happens to access the pool. Forcibly stopping the timer
creates an invalid state in the DBCP and the next web applications may fail to
start.

I am attaching configuration that reproduces this issue.

To reproduce:
1. Unpack the zip archive, and place the provided files on top of the default
configuration of Tomcat 6.0.26.

It contains:
1) /data - Two sample HSQLDB databases (http://hsqldb.org/), "database" and
"database2". These are identical and contain a single table with two rows of
data - see the *.script files.
2) /lib - HSQLDB 1.8.1.2 jar.
3) /conf - server.xml that defines a database pool in GlobalResources.
         - tomcat-users.xml that contains a username and password for the
manager application
4) /webapps - Two web applications, test1 and test2. These are nearly
identical, with the following only difference between them (see
META-INF/context.xml):
- test1 uses connection pool defined in server.xml
- test2 uses its own connection pool
5) /logs - Logs from my test run.

2. Copy jstl.jar and standard.jar from /webapps/examples/WEB-INF/lib/ of Tomcat
into the /lib folder of Tomcat.

3. Start Tomcat
4. Go to http://localhost:8080/test1/  A test page should load and print two
database rows.
5. Go to http://localhost:8080/manager/html/ and stop the test1 application.
Note, that Tomcat stops TimerThread created by DBCP.

6. Go to http://localhost:8080/test2/
Expected result: The same output as for test1 before.
Actual result:  The page fails to load, displaying
DataSource invalid: "java.lang.IllegalStateException: Timer already cancelled."


It is not seen from the stack trace, but my understanding here is that that
occurs because in Commons Pools, when a new pool is initialized, the
GenericObjectPool#startEvictor(..) method creates a new Evictor and calls
Timer.schedule(..) to schedule it, but the timer is already canceled.

Other issues:
1) I suspect that when the pool defined in server.xml is initialized, the TCCL
occurs to be equal to the classloader of the web application. I have not yet
confirmed that, but that will be a separate bug (causing its own leaks) if it
is the case.
2) HSQLDB creates its own "HSQLDB Timer" thread. That is not important, because
DBCP issue I am talking about is independent of what database is used. If
anyone is curious: that thread is created by the org.hsqldb.lib.HsqlTimer
class.


Regarding the feature of stopping TimerThreads:
1) I agree with Sylvain that it looks like that it would be better to have it
disabled by default, but I would like to have a separate option to control
enabling this feature.
2) I think that another strategy is possible here: to call
Thread.setContextClassLoader(null) on the affected threads. That can have its
consequences, but might be better than stopping the threads.

Workaround:  Do not set "timeBetweenEvictionRunsMillis" attribute on a pool.

-- 
Configure bugmail: https://issues.apache.org/bugzilla/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
You are the assignee for the bug.

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org
For additional commands, e-mail: dev-h...@tomcat.apache.org

Reply via email to