OPENJPA-138. Some updates to help with performance of OpenJPA in an application server environment. Details can be found in the OPENJPA-138 Issue.

git-svn-id: https://svn.apache.org/repos/asf/incubator/openjpa/trunk@506230 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Kevin W. Sutter 2007-02-12 02:33:05 +00:00
parent 7d0839f9ff
commit e14378f7f3
7 changed files with 167 additions and 38 deletions

View File

@ -29,6 +29,7 @@ public class JNDIManagedRuntime
implements ManagedRuntime { implements ManagedRuntime {
private String _tmLoc = "java:/TransactionManager"; private String _tmLoc = "java:/TransactionManager";
private static TransactionManager _tm;
/** /**
* Return the location of the {@link TransactionManager} in JNDI. * Return the location of the {@link TransactionManager} in JNDI.
@ -44,13 +45,18 @@ public class JNDIManagedRuntime
_tmLoc = name; _tmLoc = name;
} }
public TransactionManager getTransactionManager() /**
throws Exception { * Return the cached TransactionManager instance.
Context ctx = new InitialContext(); */
try { public TransactionManager getTransactionManager() throws Exception {
return (TransactionManager) ctx.lookup(_tmLoc); if (_tm == null) {
} finally { Context ctx = new InitialContext();
ctx.close(); try {
_tm = (TransactionManager) ctx.lookup(_tmLoc);
} finally {
ctx.close();
}
} }
} return _tm;
}
} }

View File

@ -64,7 +64,8 @@ public abstract class AbstractBrokerFactory
// configuration // configuration
private final OpenJPAConfiguration _conf; private final OpenJPAConfiguration _conf;
private transient boolean _readOnly = false; private transient boolean _readOnly = false;
private transient RuntimeException _closed = null; private transient boolean _closed = false;
private transient RuntimeException _closedException = null;
private Map _userObjects = null; private Map _userObjects = null;
// internal lock: spec forbids synchronization on this object // internal lock: spec forbids synchronization on this object
@ -267,7 +268,7 @@ public abstract class AbstractBrokerFactory
* Returns true if this broker factory is closed. * Returns true if this broker factory is closed.
*/ */
public boolean isClosed() { public boolean isClosed() {
return _closed != null; return _closed;
} }
public void close() { public void close() {
@ -297,7 +298,10 @@ public abstract class AbstractBrokerFactory
(_conf.getMetaDataRepositoryInstance()); (_conf.getMetaDataRepositoryInstance());
_conf.close(); _conf.close();
_closed = new IllegalStateException(); _closed = true;
Log log = _conf.getLog(OpenJPAConfiguration.LOG_RUNTIME);
if (log.isTraceEnabled())
_closedException = new IllegalStateException();
} finally { } finally {
unlock(); unlock();
} }
@ -546,12 +550,18 @@ public abstract class AbstractBrokerFactory
} }
/** /**
* Throw an exception if the factory is closed. * Throw an exception if the factory is closed. The exact message and
* content of the exception varies whether TRACE is enabled or not.
*/ */
private void assertOpen() { private void assertOpen() {
if (_closed != null) if (_closed) {
throw new InvalidStateException(_loc.get("closed-factory")). if (_closedException == null) // TRACE not enabled
setCause(_closed); throw new InvalidStateException(_loc
.get("closed-factory-notrace"));
else
throw new InvalidStateException(_loc.get("closed-factory"))
.setCause(_closedException);
}
} }
//////////////////// ////////////////////

View File

@ -63,6 +63,7 @@ import org.apache.openjpa.lib.util.Localizer;
import org.apache.openjpa.lib.util.ReferenceHashMap; import org.apache.openjpa.lib.util.ReferenceHashMap;
import org.apache.openjpa.lib.util.ReferenceHashSet; import org.apache.openjpa.lib.util.ReferenceHashSet;
import org.apache.openjpa.lib.util.ReferenceMap; import org.apache.openjpa.lib.util.ReferenceMap;
import org.apache.openjpa.lib.util.concurrent.ConcurrentReferenceHashMap;
import org.apache.openjpa.lib.util.concurrent.ReentrantLock; import org.apache.openjpa.lib.util.concurrent.ReentrantLock;
import org.apache.openjpa.meta.ClassMetaData; import org.apache.openjpa.meta.ClassMetaData;
import org.apache.openjpa.meta.FieldMetaData; import org.apache.openjpa.meta.FieldMetaData;
@ -138,6 +139,9 @@ public class BrokerImpl
private static final Localizer _loc = private static final Localizer _loc =
Localizer.forPackage(BrokerImpl.class); Localizer.forPackage(BrokerImpl.class);
// Cache for from/to type assignments
private static ConcurrentReferenceHashMap _assignableTypes =
new ConcurrentReferenceHashMap(ReferenceMap.HARD, ReferenceMap.WEAK);
// the store manager in use; this may be a decorator such as a // the store manager in use; this may be a decorator such as a
// data cache store manager around the native store manager // data cache store manager around the native store manager
@ -215,7 +219,8 @@ public class BrokerImpl
// status // status
private int _flags = 0; private int _flags = 0;
private RuntimeException _closed = null; private boolean _closed = false;
private RuntimeException _closedException = null;
// event managers // event managers
private TransactionEventManager _transEventManager = null; private TransactionEventManager _transEventManager = null;
@ -1096,8 +1101,7 @@ public class BrokerImpl
cls)); cls));
return PCRegistry.newObjectId(cls, (String) val); return PCRegistry.newObjectId(cls, (String) val);
} }
if (isAssignable(meta.getObjectIdType(), val.getClass())) {
if (meta.getObjectIdType().isAssignableFrom(val.getClass())) {
if (!meta.isOpenJPAIdentity() && meta.isObjectIdTypeShared()) if (!meta.isOpenJPAIdentity() && meta.isObjectIdTypeShared())
return new ObjectId(cls, val); return new ObjectId(cls, val);
return val; return val;
@ -1118,6 +1122,37 @@ public class BrokerImpl
} }
} }
/**
* Cache from/to assignments to avoid Class.isAssignableFrom overhead
* @param from the target Class
* @param to the Class to test
* @return true if the "to" class could be assigned to "from" class
*/
private boolean isAssignable(Class from, Class to) {
boolean isAssignable;
ConcurrentReferenceHashMap assignableTo =
(ConcurrentReferenceHashMap) _assignableTypes.get(from);
if (assignableTo != null) { // "to" cache exists...
isAssignable = (assignableTo.get(to) != null);
if (!isAssignable) { // not in the map yet...
isAssignable = from.isAssignableFrom(to);
if (isAssignable) {
assignableTo.put(to, new Object());
}
}
} else { // no "to" cache yet...
isAssignable = from.isAssignableFrom(to);
if (isAssignable) {
assignableTo = new ConcurrentReferenceHashMap(
ReferenceMap.HARD, ReferenceMap.WEAK);
_assignableTypes.put(from, assignableTo);
assignableTo.put(to, new Object());
}
}
return isAssignable;
}
/** /**
* Create a new state manager for the given oid. * Create a new state manager for the given oid.
*/ */
@ -3969,11 +4004,11 @@ public class BrokerImpl
/////////// ///////////
public boolean isClosed() { public boolean isClosed() {
return _closed != null; return _closed;
} }
public boolean isCloseInvoked() { public boolean isCloseInvoked() {
return _closed != null || (_flags & FLAG_CLOSE_INVOKED) != 0; return _closed || (_flags & FLAG_CLOSE_INVOKED) != 0;
} }
public void close() { public void close() {
@ -4055,8 +4090,10 @@ public class BrokerImpl
_lm.close(); _lm.close();
_store.close(); _store.close();
_closed = new IllegalStateException();
_flags = 0; _flags = 0;
_closed = true;
if (_log.isTraceEnabled())
_closedException = new IllegalStateException();
if (err != null) if (err != null)
throw err; throw err;
@ -4246,11 +4283,19 @@ public class BrokerImpl
///////// /////////
// Utils // Utils
///////// /////////
/**
* Throw an exception if the context is closed. The exact message and
* content of the exception varies whether TRACE is enabled or not.
*/
public void assertOpen() { public void assertOpen() {
if (_closed != null) if (_closed) {
throw new InvalidStateException(_loc.get("closed"), _closed). if (_closedException == null) // TRACE not enabled
setFatal(true); throw new InvalidStateException(_loc.get("closed-notrace"))
.setFatal(true);
else
throw new InvalidStateException(_loc.get("closed"),
_closedException).setFatal(true);
}
} }
public void assertActiveTransaction() { public void assertActiveTransaction() {

View File

@ -36,6 +36,8 @@ import org.apache.openjpa.lib.rop.ResultObjectProvider;
import org.apache.openjpa.lib.rop.SimpleResultList; import org.apache.openjpa.lib.rop.SimpleResultList;
import org.apache.openjpa.lib.rop.WindowResultList; import org.apache.openjpa.lib.rop.WindowResultList;
import org.apache.openjpa.lib.util.Localizer; import org.apache.openjpa.lib.util.Localizer;
import org.apache.openjpa.lib.util.ReferenceMap;
import org.apache.openjpa.lib.util.concurrent.ConcurrentReferenceHashMap;
import org.apache.openjpa.meta.ClassMetaData; import org.apache.openjpa.meta.ClassMetaData;
import org.apache.openjpa.meta.FetchGroup; import org.apache.openjpa.meta.FetchGroup;
import org.apache.openjpa.meta.FieldMetaData; import org.apache.openjpa.meta.FieldMetaData;
@ -58,6 +60,10 @@ public class FetchConfigurationImpl
private static final Localizer _loc = Localizer.forPackage private static final Localizer _loc = Localizer.forPackage
(FetchConfigurationImpl.class); (FetchConfigurationImpl.class);
// Cache the from/to isAssignable invocations
private static ConcurrentReferenceHashMap _assignableTypes =
new ConcurrentReferenceHashMap(ReferenceMap.HARD, ReferenceMap.WEAK);
/** /**
* Configurable state shared throughout a traversal chain. * Configurable state shared throughout a traversal chain.
*/ */
@ -613,11 +619,37 @@ public class FetchConfigurationImpl
} }
/** /**
* Whether either of the two types is assignable from the other. * Whether either of the two types is assignable from the other. Optimize
* for the repeat calls with similar parameters by caching the from/to
* type parameters.
*/ */
private static boolean isAssignable(Class c1, Class c2) { private static boolean isAssignable(Class from, Class to) {
return c1 != null && c2 != null boolean isAssignable;
&& (c1.isAssignableFrom(c2) || c2.isAssignableFrom(c1));
if (from == null || to == null)
return false;
ConcurrentReferenceHashMap assignableTo =
(ConcurrentReferenceHashMap) _assignableTypes.get(from);
if (assignableTo != null) { // "to" cache exists...
isAssignable = (assignableTo.get(to) != null);
if (!isAssignable) { // not in the map yet...
isAssignable = from.isAssignableFrom(to);
if (isAssignable) {
assignableTo.put(to, new Object());
}
}
} else { // no "to" cache yet...
isAssignable = from.isAssignableFrom(to);
if (isAssignable) {
assignableTo = new ConcurrentReferenceHashMap(
ReferenceMap.HARD, ReferenceMap.WEAK);
_assignableTypes.put(from, assignableTo);
assignableTo.put(to, new Object());
}
}
return isAssignable;
} }
/** /**

View File

@ -17,6 +17,10 @@ package org.apache.openjpa.util;
import java.io.Serializable; import java.io.Serializable;
import org.apache.openjpa.lib.util.ReferenceHashSet;
import org.apache.openjpa.lib.util.ReferenceMap;
import org.apache.openjpa.lib.util.concurrent.ConcurrentReferenceHashMap;
/** /**
* Identity class extended by builtin OpenJPA identity objects. * Identity class extended by builtin OpenJPA identity objects.
* *
@ -31,6 +35,9 @@ public abstract class OpenJPAId
// type has his based on the least-derived non-object class so that // type has his based on the least-derived non-object class so that
// user-given ids with non-exact types match ids with exact types // user-given ids with non-exact types match ids with exact types
private transient int _typeHash = 0; private transient int _typeHash = 0;
// cache the types' generated hashcodes
private static ConcurrentReferenceHashMap _typeCache =
new ConcurrentReferenceHashMap(ReferenceMap.HARD, ReferenceMap.WEAK);
protected OpenJPAId() { protected OpenJPAId() {
} }
@ -82,13 +89,25 @@ public abstract class OpenJPAId
*/ */
protected abstract boolean idEquals(OpenJPAId other); protected abstract boolean idEquals(OpenJPAId other);
/**
* Generate the hashcode for this Id. Cache the type's generated hashcode
* so that it doesn't have to be generated each time.
*/
public int hashCode() { public int hashCode() {
if (_typeHash == 0) { if (_typeHash == 0) {
Class base = type; Integer typeHashInt = (Integer) _typeCache.get(type);
while (base.getSuperclass() != null if (typeHashInt == null) {
&& base.getSuperclass() != Object.class) Class base = type;
base = base.getSuperclass(); Class superclass = base.getSuperclass();
_typeHash = base.hashCode(); while (superclass != null && superclass != Object.class) {
base = base.getSuperclass();
superclass = base.getSuperclass();
}
_typeHash = base.hashCode();
_typeCache.put(type, new Integer(_typeHash));
} else {
_typeHash = typeHashInt.intValue();
}
} }
return _typeHash ^ idHash(); return _typeHash ^ idHash();
} }

View File

@ -94,8 +94,13 @@ trans-active: The "{0}" transaction property cannot be set during an \
active: This operation cannot be performed while a Transaction is active. active: This operation cannot be performed while a Transaction is active.
closed: The context has been closed. The stack trace at which the \ closed: The context has been closed. The stack trace at which the \
context was closed is held in the embedded exception. context was closed is held in the embedded exception.
closed-notrace: The context has been closed. The stack trace at which the \
context was closed is available if Runtime=TRACE logging is enabled.
closed-factory: The factory has been closed. The stack trace at \ closed-factory: The factory has been closed. The stack trace at \
which the factory was closed is held in the embedded exception. which the factory was closed is held in the embedded exception.
closed-factory-notrace: The factory has been closed. The stack trace at \
which the factory was closed is available if Runtime=TRACE logging is \
enabled.
non-trans-read: To perform reads on persistent data outside of a transaction, \ non-trans-read: To perform reads on persistent data outside of a transaction, \
the "NontransactionalRead" property must be set on the Transaction. the "NontransactionalRead" property must be set on the Transaction.
non-trans-write: To perform writes on persistent data outside of a \ non-trans-write: To perform writes on persistent data outside of a \

View File

@ -17,6 +17,8 @@ package org.apache.openjpa.lib.conf;
import org.apache.commons.lang.ObjectUtils; import org.apache.commons.lang.ObjectUtils;
import org.apache.openjpa.lib.util.Localizer; import org.apache.openjpa.lib.util.Localizer;
import org.apache.openjpa.lib.util.ReferenceMap;
import org.apache.openjpa.lib.util.concurrent.ConcurrentReferenceHashMap;
/** /**
* An object {@link Value}. * An object {@link Value}.
@ -28,6 +30,10 @@ public class ObjectValue extends Value {
private static final Localizer _loc = Localizer.forPackage private static final Localizer _loc = Localizer.forPackage
(ObjectValue.class); (ObjectValue.class);
// cache the types' classloader
private static ConcurrentReferenceHashMap _classloaderCache =
new ConcurrentReferenceHashMap(ReferenceMap.HARD, ReferenceMap.WEAK);
private Object _value = null; private Object _value = null;
public ObjectValue(String prop) { public ObjectValue(String prop) {
@ -81,10 +87,16 @@ public class ObjectValue extends Value {
* Allow subclasses to instantiate additional plugins. This method does * Allow subclasses to instantiate additional plugins. This method does
* not perform configuration. * not perform configuration.
*/ */
public Object newInstance(String clsName, Class type, public Object newInstance(String clsName, Class type, Configuration conf,
Configuration conf, boolean fatal) { boolean fatal) {
return Configurations.newInstance(clsName, this, conf, ClassLoader cl = (ClassLoader) _classloaderCache.get(type);
type.getClassLoader(), fatal); if (cl == null) {
cl = type.getClassLoader();
if (cl != null) { // System classloader is returned as null
_classloaderCache.put(type, cl);
}
}
return Configurations.newInstance(clsName, this, conf, cl, fatal);
} }
public Class getValueType() { public Class getValueType() {