Some Eclipse Foundation services are deprecated, or will be soon. Please ensure you've read this important communication.

Bug 332464

Summary: EntityManager running out of connections in exclusive isolated client session mode
Product: z_Archived Reporter: Patric Rufflar <patric>
Component: EclipselinkAssignee: 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:
Description Flags
suggested patch none

Description Patric Rufflar CLA 2010-12-13 14:05:44 EST
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);
         }
     }
Comment 1 Patric Rufflar CLA 2010-12-13 15:12:09 EST
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();
}
}
Comment 2 Andrei Ilitchev CLA 2010-12-13 16:29:18 EST
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).
Comment 3 Andrei Ilitchev CLA 2010-12-13 16:35:46 EST
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.
Comment 4 Andrei Ilitchev CLA 2010-12-20 13:31:52 EST
Created attachment 185575 [details]
suggested patch

The patch releases the uow and its parent on em.clear.
Comment 5 Andrei Ilitchev CLA 2010-12-20 13:36:22 EST
Fixed in trunk (2.2).
Comment 6 Eclipse Webmaster CLA 2022-06-09 10:30:08 EDT
The Eclipselink project has moved to Github: https://github.com/eclipse-ee4j/eclipselink