You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tapestry.apache.org by hl...@apache.org on 2011/09/14 19:29:27 UTC

svn commit: r1170723 - in /tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/internal/plastic: PlasticClassLoader.java PlasticClassPool.java

Author: hlship
Date: Wed Sep 14 17:29:27 2011
New Revision: 1170723

URL: http://svn.apache.org/viewvc?rev=1170723&view=rev
Log:
TAP5-1650: On a cold start with a large number of incoming requests, Tapestry can deadlock inside PlasticClassLoader/PlasticClassPool

Modified:
    tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/internal/plastic/PlasticClassLoader.java
    tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/internal/plastic/PlasticClassPool.java

Modified: tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/internal/plastic/PlasticClassLoader.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/internal/plastic/PlasticClassLoader.java?rev=1170723&r1=1170722&r2=1170723&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/internal/plastic/PlasticClassLoader.java (original)
+++ tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/internal/plastic/PlasticClassLoader.java Wed Sep 14 17:29:27 2011
@@ -14,8 +14,13 @@
 
 package org.apache.tapestry5.internal.plastic;
 
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
+
 public class PlasticClassLoader extends ClassLoader
 {
+    final Lock classloaderLock = new ReentrantLock();
+
     private final ClassLoaderDelegate delegate;
 
     public PlasticClassLoader(ClassLoader parent, ClassLoaderDelegate delegate)
@@ -26,25 +31,32 @@ public class PlasticClassLoader extends 
     }
 
     @Override
-    protected synchronized Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException
+    protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException
     {
-        Class<?> loadedClass = findLoadedClass(name);
+        classloaderLock.lock();
 
-        if (loadedClass != null)
-            return loadedClass;
-
-        if (delegate.shouldInterceptClassLoading(name))
+        try
         {
-            Class<?> c = delegate.loadAndTransformClass(name);
+            Class<?> loadedClass = findLoadedClass(name);
 
-            if (resolve)
-                resolveClass(c);
+            if (loadedClass != null)
+                return loadedClass;
 
-            return c;
-        }
-        else
+            if (delegate.shouldInterceptClassLoading(name))
+            {
+                Class<?> c = delegate.loadAndTransformClass(name);
+
+                if (resolve)
+                    resolveClass(c);
+
+                return c;
+            } else
+            {
+                return super.loadClass(name, resolve);
+            }
+        } finally
         {
-            return super.loadClass(name, resolve);
+            classloaderLock.unlock();
         }
     }
 

Modified: tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/internal/plastic/PlasticClassPool.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/internal/plastic/PlasticClassPool.java?rev=1170723&r1=1170722&r2=1170723&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/internal/plastic/PlasticClassPool.java (original)
+++ tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/internal/plastic/PlasticClassPool.java Wed Sep 14 17:29:27 2011
@@ -14,30 +14,17 @@
 
 package org.apache.tapestry5.internal.plastic;
 
-import java.lang.annotation.Annotation;
-import java.lang.reflect.Modifier;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.CopyOnWriteArrayList;
-
 import org.apache.tapestry5.internal.plastic.asm.ClassReader;
 import org.apache.tapestry5.internal.plastic.asm.ClassWriter;
 import org.apache.tapestry5.internal.plastic.asm.Opcodes;
 import org.apache.tapestry5.internal.plastic.asm.tree.AnnotationNode;
 import org.apache.tapestry5.internal.plastic.asm.tree.ClassNode;
-import org.apache.tapestry5.plastic.AnnotationAccess;
-import org.apache.tapestry5.plastic.ClassInstantiator;
-import org.apache.tapestry5.plastic.ClassType;
-import org.apache.tapestry5.plastic.PlasticClassEvent;
-import org.apache.tapestry5.plastic.PlasticClassListener;
-import org.apache.tapestry5.plastic.PlasticClassListenerHub;
-import org.apache.tapestry5.plastic.PlasticClassTransformation;
-import org.apache.tapestry5.plastic.PlasticManagerDelegate;
-import org.apache.tapestry5.plastic.TransformationOption;
+import org.apache.tapestry5.plastic.*;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Modifier;
+import java.util.*;
+import java.util.concurrent.CopyOnWriteArrayList;
 
 /**
  * Responsible for managing a class loader that allows ASM {@link ClassNode}s
@@ -84,7 +71,9 @@ public class PlasticClassPool implements
         }
     }
 
-    /** Map from FQCN to BaseClassDef. */
+    /**
+     * Map from FQCN to BaseClassDef.
+     */
     private final Map<String, BaseClassDef> baseClassDefs = new HashMap<String, PlasticClassPool.BaseClassDef>();
 
     private final Set<TransformationOption> options;
@@ -92,18 +81,14 @@ public class PlasticClassPool implements
     /**
      * Creates the pool with a set of controlled packages; all classes in the controlled packages are loaded by the
      * pool's class loader, and all top-level classes in the controlled packages are transformed via the delegate.
-     * 
-     * @param parentLoader
-     *            typically, the Thread's context class loader
-     * @param delegate
-     *            responsible for end stages of transforming top-level classes
-     * @param controlledPackages
-     *            set of package names (note: retained, not copied)
-     * @param options
-     *            used when transforming classes
+     *
+     * @param parentLoader       typically, the Thread's context class loader
+     * @param delegate           responsible for end stages of transforming top-level classes
+     * @param controlledPackages set of package names (note: retained, not copied)
+     * @param options            used when transforming classes
      */
     public PlasticClassPool(ClassLoader parentLoader, PlasticManagerDelegate delegate, Set<String> controlledPackages,
-            Set<TransformationOption> options)
+                            Set<TransformationOption> options)
     {
         loader = new PlasticClassLoader(parentLoader, this);
         this.delegate = delegate;
@@ -117,7 +102,7 @@ public class PlasticClassPool implements
     }
 
     public synchronized Class realizeTransformedClass(ClassNode classNode, InheritanceData inheritanceData,
-            StaticContext staticContext)
+                                                      StaticContext staticContext)
     {
         Class result = realize(PlasticInternalUtils.toClassName(classNode.name), ClassType.PRIMARY, classNode);
 
@@ -141,7 +126,7 @@ public class PlasticClassPool implements
     }
 
     private PlasticClassEvent toEvent(final String primaryClassName, final ClassType classType,
-            final ClassNode classNode)
+                                      final ClassNode classNode)
     {
         return new PlasticClassEvent()
         {
@@ -204,8 +189,7 @@ public class PlasticClassPool implements
                     return annotationType.cast(searchClass.getAnnotation(annotationType));
                 }
             };
-        }
-        catch (Exception ex)
+        } catch (Exception ex)
         {
             throw new RuntimeException(ex);
         }
@@ -266,8 +250,7 @@ public class PlasticClassPool implements
         try
         {
             return loader.loadClass(className);
-        }
-        catch (Exception ex)
+        } catch (Exception ex)
         {
             throw new RuntimeException(String.format("Unable to load class %s: %s", className,
                     PlasticInternalUtils.toMessage(ex)), ex);
@@ -337,7 +320,7 @@ public class PlasticClassPool implements
     /**
      * For a fully-qualified class name of an <em>existing</em> class, loads the bytes for the class
      * and returns a PlasticClass instance.
-     * 
+     *
      * @throws ClassNotFoundException
      */
     public InternalPlasticClassTransformation getPlasticClassTransformation(String className)
@@ -374,9 +357,8 @@ public class PlasticClassPool implements
     /**
      * Constructs a class node by reading the raw bytecode for a class and instantiating a ClassNode
      * (via {@link ClassReader#accept(org.apache.tapestry5.internal.plastic.asm.ClassVisitor, int)}).
-     * 
-     * @param className
-     *            fully qualified class name
+     *
+     * @param className fully qualified class name
      * @return corresponding ClassNode
      */
     public ClassNode constructClassNode(String className)
@@ -406,8 +388,7 @@ public class PlasticClassPool implements
                     PlasticInternalUtils.toInternalName(baseClassName), null);
 
             return createTransformation(baseClassName, newClassNode);
-        }
-        catch (ClassNotFoundException ex)
+        } catch (ClassNotFoundException ex)
         {
             throw new RuntimeException(String.format("Unable to create class %s as sub-class of %s: %s", newClassName,
                     baseClassName, PlasticInternalUtils.toMessage(ex)), ex);
@@ -416,48 +397,57 @@ public class PlasticClassPool implements
 
     public synchronized ClassInstantiator getClassInstantiator(String className)
     {
-        if (!instantiators.containsKey(className))
+        ClassInstantiator result;
+
+        loader.classloaderLock.lock();
+
+        try
         {
-            try
+            if (!instantiators.containsKey(className))
             {
-                loader.loadClass(className);
-            }
-            catch (ClassNotFoundException ex)
-            {
-                throw new RuntimeException(ex);
+                try
+                {
+                    loader.loadClass(className);
+                } catch (ClassNotFoundException ex)
+                {
+                    throw new RuntimeException(ex);
+                }
             }
-        }
 
-        ClassInstantiator result = instantiators.get(className);
-
-        if (result == null)
+            result = instantiators.get(className);
+        } finally
         {
-            // TODO: Verify that the problem is incorrect package, and not any other failure.
+            loader.classloaderLock.unlock();
+        }
 
-            StringBuilder b = new StringBuilder();
-            b.append("Class '")
-                    .append(className)
-                    .append("' is not a transformed class. Transformed classes should be in one of the following packages: ");
+        if (result != null)
+        {
+            return result;
+        }
 
-            String sep = "";
+        // TODO: Verify that the problem is incorrect package, and not any other failure.
 
-            List<String> names = new ArrayList<String>(controlledPackages);
-            Collections.sort(names);
+        StringBuilder b = new StringBuilder();
+        b.append("Class '")
+                .append(className)
+                .append("' is not a transformed class. Transformed classes should be in one of the following packages: ");
 
-            for (String name : names)
-            {
-                b.append(sep);
-                b.append(name);
+        String sep = "";
 
-                sep = ", ";
-            }
+        List<String> names = new ArrayList<String>(controlledPackages);
+        Collections.sort(names);
 
-            String message = b.append(".").toString();
+        for (String name : names)
+        {
+            b.append(sep);
+            b.append(name);
 
-            throw new IllegalArgumentException(message);
+            sep = ", ";
         }
 
-        return result;
+        String message = b.append(".").toString();
+
+        throw new IllegalArgumentException(message);
     }
 
     TypeCategory getTypeCategory(String typeName)