|
Kevin opined: Within a Container-managed environment, the Container takes care of the lifecycle of the EntityManagers.
I believe that this applies only to injected EntityManagers, not to those created by the user explicitly via EMF.createEntityManager. So there is still some cleanup needed to guarantee proper resource deallocation when the EMF is closed. Patrick offered: implement a concurrent Collection class that uses weak references, and eliminate all locking I believe that this is an optimal solution. Concurrent Collections should have almost zero locking in most containers. Recall that we do have a 1.4-compatible concurrent collection at org.apache.openjpa.lib.util.concurrent.ConcurrentHashSet. However, to my knowledge, that impl uses hard references.
Thanks, Patrick and Craig. I did some looking in lib and found that we also have a ConcurrentReferenceHashSet. So, I have modified _brokers accordingly and am waiting for our test results. I have also removed the explicit lock/unlock invocations. As Patrick pointed out, the findBroker() is never called since findExisting is always false for OpenJPA, thus the other synch block shouldn't come into play. Hopefully, with the weak references in ConcurrentReferenceHashSet _brokers, this should help with the blocking and broker cleanup. Our original experimentation showed that even with the weak references in ReferenceHashSet, we still bogged down during the cleanup of the _brokers collection. But, maybe there's a problem with SunOne where they are not properly closing the EntityManagers. I'll post back when we get the test results.
> Our original experimentation showed that even with the weak references
> in ReferenceHashSet, we still bogged down during the cleanup of the > _brokers collection. But that should only be happening when the EMF is closed, right? Presumably, that corresponds to appserver shutdown / application undeploy. Is your test measuring that part of the application lifecycle? I'm going to go ahead with the proposed changes to remove the explicit lock/unlock invocations, and change the _brokers definition to use ConcurrentReferenceHashSet with weak references. The problem at shutdown was with the EMF.close processing. It is attempting to close any outstanding EM's that had not been closed. But, as it was iterating through this list, one of the EM instances became null and caused an NPE. Not sure if this is due to the weak references being GC'd or it indicates a possible problem with the underlying Collections MapBackedSet or something else, but a simple null check gets around this problem.
With these changes, the initial bottleneck with running OpenJPA in a server environment has been resolved. We are still pursuing other performance concerns, but we'll open new JIRA reports when we get something more concrete. Kevin The null problem is probably due to references being garbage collected -- this is a typical side-effect of weak reference collection types. The improved concurrency is typically worth the extra difficulty of checking for nulls, though.
Yes, null checking is an expected requirement when dealing with weak references. If you can get a strong reference in a cleanup routine then it's ok to use it, because the fact that you have a strong reference will prevent garbage collection.
If you get null from your weak reference, then the garbage collector has already done its job and by definition there can be nothing left for your routine to clean up. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||
The _brokers collection provides us with a means to ensure that when we close a BrokerFactory, all open Brokers are closed along with it. Additionally, we use a weak reference map here, so we don't need to maintain the _brokers collection during Broker.close().
So, we have a number of options:
1. move the locking logic to be just around the code that maintains the _brokers collection
2. implement a concurrent Collection class that uses weak references, and eliminate all locking
3. create a configuration option (openjpa.CloseBrokersOnBrokerFactoryClose or something) that controls whether or not OpenJPA tracks open brokers. This would allow default behavior to be pro-active about cleanup, but also allow containers (which are presumably doing a good job of resource clean-up) to bypass the overhead.