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.
+