diff --git a/openjpa-kernel/src/main/java/org/apache/openjpa/conf/BrokerValue.java b/openjpa-kernel/src/main/java/org/apache/openjpa/conf/BrokerValue.java new file mode 100644 index 000000000..2cd4dbbe7 --- /dev/null +++ b/openjpa-kernel/src/main/java/org/apache/openjpa/conf/BrokerValue.java @@ -0,0 +1,49 @@ +package org.apache.openjpa.conf; + +import org.apache.openjpa.lib.conf.PluginValue; +import org.apache.openjpa.lib.conf.Configuration; +import org.apache.openjpa.kernel.BrokerImpl; +import org.apache.openjpa.kernel.FinalizingBrokerImpl; +import org.apache.openjpa.util.InternalException; + +/** + * Custom {@link PluginValue} that can efficiently create {@link BrokerImpl} + * instances. + * + * @since 0.9.7 + */ +public class BrokerValue + extends PluginValue { + + private BrokerImpl _templateBroker; + + public BrokerValue(String prop) { + super(prop, false); + String[] aliases = new String[] { + "default", FinalizingBrokerImpl.class.getName(), + "non-finalizing", BrokerImpl.class.getName(), + }; + setAliases(aliases); + setDefault(aliases[0]); + setString(aliases[0]); + } + + public Object newInstance(String clsName, Class type, Configuration conf, + boolean fatal) { + if (BrokerImpl.class.getName().equals(clsName)) { + // This is not synchronized. If there are concurrent invocations + // while _templateBroker is null, we'll just end up with extra + // template brokers, which will get safely garbage collected. + if (_templateBroker == null) + _templateBroker = (BrokerImpl) super.newInstance( + clsName, type, conf, fatal); + try { + return _templateBroker.clone(); + } catch (CloneNotSupportedException e) { + throw new InternalException(e); + } + } else { + return super.newInstance(clsName, type, conf, fatal); + } + } +} diff --git a/openjpa-kernel/src/main/java/org/apache/openjpa/conf/OpenJPAConfigurationImpl.java b/openjpa-kernel/src/main/java/org/apache/openjpa/conf/OpenJPAConfigurationImpl.java index 3c9515cac..d981a67a1 100644 --- a/openjpa-kernel/src/main/java/org/apache/openjpa/conf/OpenJPAConfigurationImpl.java +++ b/openjpa-kernel/src/main/java/org/apache/openjpa/conf/OpenJPAConfigurationImpl.java @@ -71,7 +71,7 @@ public class OpenJPAConfigurationImpl // openjpa properties public ObjectValue classResolverPlugin; - public ObjectValue brokerPlugin; + public BrokerValue brokerPlugin; public ObjectValue dataCachePlugin; public ObjectValue dataCacheManagerPlugin; public IntValue dataCacheTimeout; @@ -178,11 +178,8 @@ public class OpenJPAConfigurationImpl brokerFactoryPlugin = new BrokerFactoryValue(); addValue(brokerFactoryPlugin); - brokerPlugin = addPlugin("BrokerImpl", false); - aliases = new String[] { "default", BrokerImpl.class.getName() }; - brokerPlugin.setAliases(aliases); - brokerPlugin.setDefault(aliases[0]); - brokerPlugin.setString(aliases[0]); + brokerPlugin = new BrokerValue("BrokerImpl"); + addValue(brokerPlugin); dataCacheManagerPlugin = addPlugin("DataCacheManager", true); aliases = diff --git a/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/BrokerImpl.java b/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/BrokerImpl.java index 8122267ce..ed73a1749 100644 --- a/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/BrokerImpl.java +++ b/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/BrokerImpl.java @@ -96,7 +96,7 @@ import org.apache.openjpa.util.UserException; * @author Abe White */ public class BrokerImpl - implements Broker, FindCallbacks { + implements Broker, FindCallbacks, Cloneable { /** * Incremental flush. @@ -155,14 +155,13 @@ public class BrokerImpl private ManagedRuntime _runtime = null; private LockManager _lm = null; private InverseManager _im = null; - private final JCAHelper _jca = new JCAHelper(); + private JCAHelper _jca = null; private ReentrantLock _lock = null; private OpCallbacks _call = null; private RuntimeExceptionTranslator _extrans = null; // cache class loader associated with the broker - private ClassLoader _loader = Thread.currentThread(). - getContextClassLoader(); + private ClassLoader _loader = null; // user state private Synchronization _sync = null; @@ -225,6 +224,8 @@ public class BrokerImpl private LifecycleEventManager _lifeEventManager = null; private int _lifeCallbackMode = 0; + private boolean _initializeWasInvoked = false; + /** * Set the persistence manager's authentication. This is the first * method called after construction. @@ -251,6 +252,9 @@ public class BrokerImpl */ public void initialize(AbstractBrokerFactory factory, DelegatingStoreManager sm, boolean managed, int connMode) { + _initializeWasInvoked = true; + _loader = Thread.currentThread().getContextClassLoader(); + _jca = new JCAHelper(); _conf = factory.getConfiguration(); _compat = _conf.getCompatibilityInstance(); _factory = factory; @@ -295,14 +299,13 @@ public class BrokerImpl beginInternal(); } - /** - * Close on finalize. - */ - protected void finalize() - throws Throwable { - super.finalize(); - if (!isClosed()) - free(); + public Object clone() + throws CloneNotSupportedException { + if (_initializeWasInvoked) + throw new CloneNotSupportedException(); + else { + return super.clone(); + } } /** diff --git a/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/FinalizingBrokerImpl.java b/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/FinalizingBrokerImpl.java new file mode 100644 index 000000000..af27ba701 --- /dev/null +++ b/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/FinalizingBrokerImpl.java @@ -0,0 +1,23 @@ +package org.apache.openjpa.kernel; + +/** + * Subtype of {@link BrokerImpl} that automatically closes itself during + * finalization. This implementation guards against potential resource leaks, + * but also incurs a scalability bottleneck as instances are enlisted in the + * finalization queue and subsequently cleaned up. + * + * @since 0.9.7 + */ +public class FinalizingBrokerImpl + extends BrokerImpl { + + /** + * Close on finalize. + */ + protected void finalize() + throws Throwable { + super.finalize(); + if (!isClosed()) + free(); + } +} diff --git a/openjpa-project/src/doc/manual/ref_guide_conf.xml b/openjpa-project/src/doc/manual/ref_guide_conf.xml index 93b774f9b..d0bf25168 100644 --- a/openjpa-project/src/doc/manual/ref_guide_conf.xml +++ b/openjpa-project/src/doc/manual/ref_guide_conf.xml @@ -585,7 +585,7 @@ BrokerImpl ) describing the org.apache.openjpa.kernel.Broker type to use at runtime. See - on for details. + on for details.
diff --git a/openjpa-project/src/doc/manual/ref_guide_optimization.xml b/openjpa-project/src/doc/manual/ref_guide_optimization.xml index 69ede3ea8..745ef0b7e 100644 --- a/openjpa-project/src/doc/manual/ref_guide_optimization.xml +++ b/openjpa-project/src/doc/manual/ref_guide_optimization.xml @@ -564,6 +564,25 @@ loading subclass data or traversing relations for each instance in a large collection of results can speed up data loading by orders of magnitude. + + + + Disable BrokerImpl finalization + + +performance, scalability + + + +By default, OpenJPA's EntityManagers use finalizers to ensure that resources +get cleaned up. If you are properly managing your resources, this finalization +is not necessary, and will introduce unneeded synchronization, leading to +scalability problems. You can disable this protective behavior by setting the +openjpa.BrokerImpl property to +non-finalizing. See for details. + + diff --git a/openjpa-project/src/doc/manual/ref_guide_runtime.xml b/openjpa-project/src/doc/manual/ref_guide_runtime.xml index 029c296b4..872131d62 100644 --- a/openjpa-project/src/doc/manual/ref_guide_runtime.xml +++ b/openjpa-project/src/doc/manual/ref_guide_runtime.xml @@ -103,11 +103,37 @@ allows you to convert between EntityManagerFactories and BrokerFactories, EntityManagers and Brokers. -
+
- Broker Customization + Broker Finalization - + + + EntityManager + + + finalizing + + + clean-up + + + +The default OpenJPAEntityManager implementation automatically closes itself +during instance finalization. This guards against accidental resource leaks +that may occur if a developer fails to explicitly close EntityManagers when +finished with them, but it also incurs a scalability bottleneck, since the +JVM must perform synchronization during instance creation, and since the +finalizer thread will have more instances to monitor. To avoid this overhead, +set the openjpa.BrokerImpl + configuration property to non-finalizing. + +
+
+ + Broker Customization and Finalization + + OpenJPAEntityManager @@ -116,17 +142,8 @@ and Brokers. -Some advanced users may want to add capabilities to OpenJPA's internal - -org.apache.openjpa.kernel.BrokerImpl. You can configure -OpenJPA to use a custom subclass of BrokerImpl through -the openjpa.BrokerImpl - configuration property. Set this property to the full class name of your -custom subclass. - - -As a plugin string, you can also -use this property to configure the BrokerImpl with the +As a plugin string, this property +can be used to configure the BrokerImpl with the following properties: @@ -147,6 +164,22 @@ Defaults to false. <property name="openjpa.BrokerImpl" value="EvictFromDataCache=true"/> + +Additionally, some advanced users may want to add capabilities to OpenJPA's +internal +org.apache.openjpa.kernel.BrokerImpl. You can +configure OpenJPA to use a custom subclass of BrokerImpl +with the openjpa.BrokerImpl + configuration property. Set this property to the full class +name of your custom subclass. When implementing your subclass, consider the +finalization issues mentioned in +. It may be appropriate +to create a subtype of both + +org.apache.openjpa.kernel.BrokerImpl and + +org.apache.openjpa.kernel.FinalizingBrokerImpl. +