From Bugzilla Helper: User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.5) Gecko/20030925 Description of problem: When not all results are retrieved from a DataQuery with next(), and close() is not called, com.redhat.persistence.engine.rdbms.ResultCycle.finalize() can close the database Connection when it is invoked. This results in a "java.sql.SQLException: Connection has been closed" when another thread is currently using this connection. See the attached log for an example where a thread gets a Connection object, the finalizer thread closes that Connection object, and the first thread dies with an exception trying to use the Connection it just got. Version-Release number of selected component (if applicable): How reproducible: Sometimes Steps to Reproduce: This is hard to reproduce because garbage collection is unpredictable. But on a customer's development system, the error could be reproduced by clicking around in the UI for some time. 1. Call DataQuery.next() for a result set with more than one row 2. Don't call close(), but make sure that the JVM can garbage collect the DataQuery object (by using a local variable). 3. Do some more work, including database accesses. Expected Results: Either the ResultCycle finalizer should not close the Connection, or it should make sure that the connection is not used before closing it, or we should update the DataQuery documentation and tell people that close() *has* to be called when not all rows are retrieved. The latter is what I have done for now. Additional info: This happens with the 6.0 code from Perforce. It did not happen with the release version of 6.0. (Although one cannot be sure with an error which depends on a certain object being garbage collected at a certain time.)
Created attachment 95714 [details] Server log Example of how the finalizer thread closes the connection used by another thread.
Created attachment 95759 [details] JSP to reproduce the bug Actually, the bug is easy to reproduce, thanks to System.gc() and runFinalization(). See the attached JSP. Note that the "Connection has been closed" exception you will get comes from the BaseServlet class. That's because it tries to abort the transaction after catching the exception thrown in the JSP, and while doing so, throws an exception itself. If you comment the "transaction.abort()" in BaseServlet.internalService(), you will get the original exception from stmt2.execute. Another interesting thing about the JSP is the behaviour when you add a call to users.close() or remove the if block altogether. In this case, you will get a null pointer exception in the finalize method of _test_22dfinalize__jsp. Not sure why that happens.
carsten: is this project-critical? we're aggressively triaging for QU, so target for 6.0.2 unless you say otherwise.
No, it is not project-critical. We have added close() calls for all DataQuery objects where we don't retrieve all rows.
Unfortunately, fixing this by adding close() calls did not work as well as expected. We still encounter the error sporadically, and have enabled debug logging for ResultCycle to track down the places where DataQueries are not closed. But that's a slow process. It would really be helpful if this bug were fixed in the persistence layer.
In theory, this shouldn't be happening. In practice, it is. Retarget based on Carsten's comments for 6.0.1, but need to investigate and determine what the root cause is before deciding whether or not a fix can be done for 6.0.1.
Changes which add close() calls to core and cms code: 37948, 37950
This bug was caused by faulty integration from dev to 6.0.x. Change 36462 on 6.0.x added result set closing functionality that interacted poorly with the com.arsdigita.db.* jdbc wrappers that did the same thing . Change 38190 reverts 36462. The test jsp works now.