On Wed, 2005-09-14 at 08:51 +0200, Andreas Fredriksson wrote:

> I think the only fix is to rewrite the class definition code in Derby to
> avoid taking a lock on the helper objects, but I don't know the source
> code well enough to write a proper fix.

Maybe I should spend more time tweaking before sending email in the
future.. :-)

The attached patch fixes the problem for me. I'm sure there's more than
this to it, but please feel free to use this a reference. We'll use it
locally and see if anything else creeps up.

Regards,
Andreas


diff -r -u db-derby-10.1.1.0-src-orig/java/engine/org/apache/derby/impl/services/reflect/ReflectClassesJava2.java db-derby-10.1.1.0-src/java/engine/org/apache/derby/impl/services/reflect/ReflectClassesJava2.java
--- db-derby-10.1.1.0-src-orig/java/engine/org/apache/derby/impl/services/reflect/ReflectClassesJava2.java	2005-07-29 19:37:53.000000000 +0200
+++ db-derby-10.1.1.0-src/java/engine/org/apache/derby/impl/services/reflect/ReflectClassesJava2.java	2005-09-14 11:42:00.000000000 +0200
@@ -19,8 +19,13 @@
  */
 
 package org.apache.derby.impl.services.reflect;
+
 import org.apache.derby.iapi.util.ByteArray;
 
+import java.util.Collections;
+import java.util.Map;
+import java.util.HashMap;
+
 /**
 	Relfect loader with Privileged block for Java 2 security. 
 */
@@ -29,35 +34,44 @@
 	implements java.security.PrivilegedAction
 {
 
-	private java.util.HashMap preCompiled;
+	private final Map preCompiled = Collections.synchronizedMap(new HashMap());
 
 	private int action;
 
-	protected synchronized LoadedGeneratedClass loadGeneratedClassFromData(String fullyQualifiedName, ByteArray classDump) {
+	protected LoadedGeneratedClass loadGeneratedClassFromData(String fullyQualifiedName, ByteArray classDump) {
 
 		if (classDump == null || classDump.getArray() == null) {
 
-			if (preCompiled == null)
-				preCompiled = new java.util.HashMap();
-			else
-			{
-				ReflectGeneratedClass gc = (ReflectGeneratedClass) preCompiled.get(fullyQualifiedName);
-				if (gc != null)
-					return gc;
-			}
+			ReflectGeneratedClass gc = (ReflectGeneratedClass)
+				preCompiled.get(fullyQualifiedName);
+			if (gc != null)
+				return gc;
 
-			// not a generated class, just load the class directly.
+			// Not a generated class, just load the class directly.
+			//
+			// There's a slight chance of a race condition here--if two
+			// threads decide to generate the same class at once there will be
+			// a redundant instance of ReflectGeneratedClass created. This
+			// will only cause trouble if two callers decide to generate the
+			// same class with different contents which is a bug in itself.
+			//
+			// By not locking we allow ClassLoader objects to use the database
+			// in their findClass() methods to resolve bytecode; had we locked
+			// this object there would have been a deadlock when multiple
+			// threads issue queries and/or load classes.
 			try {
 				Class jvmClass = Class.forName(fullyQualifiedName);
-				ReflectGeneratedClass gc = new ReflectGeneratedClass(this, jvmClass, null);
-				preCompiled.put(fullyQualifiedName, gc);
-				return gc;
+				ReflectGeneratedClass newgc = new ReflectGeneratedClass(this, jvmClass, null);
+				preCompiled.put(fullyQualifiedName, newgc);
+				return newgc;
 			} catch (ClassNotFoundException cnfe) {
 				throw new NoClassDefFoundError(cnfe.toString());
 			}
 		}
 
-		action = 1;
+		synchronized (this) {
+			action = 1;
+		}
 		return ((ReflectLoaderJava2) java.security.AccessController.doPrivileged(this)).loadGeneratedClass(fullyQualifiedName, classDump);
 	}
 
@@ -73,10 +87,12 @@
 		}
 	}
 
-	protected synchronized Class loadClassNotInDatabaseJar(String name) throws ClassNotFoundException {
+	protected Class loadClassNotInDatabaseJar(String name) throws ClassNotFoundException {
 		
 		Class foundClass = null;
-		action = 2;
+		synchronized (this) {
+			action = 2;
+		}
 	    // We may have two problems with calling  getContextClassLoader()
 	    // when trying to find our own classes for aggregates.
 	    // 1) If using the URLClassLoader a ClassNotFoundException may be 

Reply via email to