| Summary: | EntityManager running out of connections in exclusive isolated client session mode | ||||||
|---|---|---|---|---|---|---|---|
| Product: | z_Archived | Reporter: | Patric Rufflar <patric> | ||||
| Component: | Eclipselink | Assignee: | Nobody - feel free to take it <nobody> | ||||
| Status: | CLOSED FIXED | QA Contact: | |||||
| Severity: | critical | ||||||
| Priority: | P3 | CC: | andrei.ilitchev, patric | ||||
| Version: | unspecified | ||||||
| Target Milestone: | --- | ||||||
| Hardware: | PC | ||||||
| OS: | Windows XP | ||||||
| Whiteboard: | |||||||
| Attachments: |
|
||||||
Here are the missing sources of the testcase: persistence.xml <persistence xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence persistence_1_0.xsd" version="1.0"> <persistence-unit name="customfeatures" transaction-type="RESOURCE_LOCAL"> <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider> <class>org.eclipse.persistence.testing.models.jpa.customfeatures.Employee</class> <properties> <property name="eclipselink.session.customizer" value="org.eclipse.persistence.testing.models.jpa.customfeatures.Customizer"/> <property name="eclipselink.jdbc.exclusive-connection.mode" value="Always"/> </properties> </persistence-unit> </persistence> public class Customizer implements SessionCustomizer { public void customize(Session session) throws SQLException { OracleDataSource ds = new OracleDataSource(); ds.setURL(session.getLogin().getConnectionString()); session.getLogin().setConnector(new JNDIConnector(ds)); session.getLogin().useExternalConnectionPooling(); } } The problem is caused by em.clear() - it doesn't release neither uow, nor its parent ClientSession that - in exclusive case - keeps holding the acquired connection forever. Workaround - don't call clear method outside of transaction if eclusive mode is Always. A simple fix would be to release both uow and its parent ClientSession when clear method is called outside of transaction. However that would release connection and that should be re-acquired again later. Keeping the uow is not an option - if detached value holders instantiated then these detached objects will appear on the old uow. Keeping the parent ClientSession is possible, however it will break the pattern when all the properties applied to the persistence contaxt after clean - if the ClientSessiojn is kept and some of connection properties has changed (for instance user/password or exclusive mod etc.) then the change will be ignored. It would be possible to cache the old session on EntityManagerImpl for the duration until the new persistence context is created (of course if the EM is closed before that the cached old session should be released). When the new session is created the old one passes to it its write accessor directly provided it makes sense for the new session to have it (for instance the old session was Exclusive, if the new session is Exclusive, too then it gets the cached accessor, otherwise the accessor is released). Note that the same could be done in case of rollback, which currently causes both the uow and the parent ClientSession to be released. Also note that this trick is not required in JTA case, when the write connection will be disconnected anyway. Created attachment 185575 [details]
suggested patch
The patch releases the uow and its parent on em.clear.
Fixed in trunk (2.2). The Eclipselink project has moved to Github: https://github.com/eclipse-ee4j/eclipselink |
Build Identifier: Eclipse 2.1.1 When using exclusive isolated client sessions (eclipselink.jdbc.exclusive-connection.mode = "Always") and eclipselink internal connection pooling has been disabled, Eclipselink will hang/block during client connection acquiring when using clear() "between" a transaction. The thread, which uses the EntityManager will hang forever. Connections (50 in the default configuraiton) are leaked and are most probably not reusable anymore. Reproducible: Always Steps to Reproduce: Junit test which reproduces the bug: public void testExclusiveSessionRunOutOfConnections() { EntityManager em = createEntityManager("customfeatures"); //because a change/(bug?) in EL 2.1, it's important to set the pool name to null //that EL will really disable internal connection pooling ((ClientSession) ((EntityManagerImpl) em).getUnitOfWork() .getParent()).getConnectionPolicy().setPoolName(null); boolean loop = true; while(loop) { em.clear(); // it's important that clear() is invoked "between" a transaction beginTransaction(em); // Employee emp = em.find(Employee.class, 1); // List<Employee> employees = em.createQuery("SELECT OBJECT(e) FROM Employee e").getResultList(); List names = em.createNativeQuery("SELECT NAME FROM CUSTOM_FEATURE_EMPLOYEE").getResultList(); commitTransaction(em); } }