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

svn commit: r1170760 - in /tapestry/tapestry5/trunk: plastic/src/main/java/org/apache/tapestry5/internal/plastic/ plastic/src/main/java/org/apache/tapestry5/plastic/ tapestry-core/src/main/java/org/apache/tapestry5/internal/services/

Author: hlship
Date: Wed Sep 14 18:33:50 2011
New Revision: 1170760

URL: http://svn.apache.org/viewvc?rev=1170760&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/PlasticClassPool.java
    tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/plastic/PlasticManager.java
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ComponentInstantiatorSourceImpl.java

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=1170760&r1=1170759&r2=1170760&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 18:33:50 2011
@@ -25,6 +25,7 @@ import java.lang.annotation.Annotation;
 import java.lang.reflect.Modifier;
 import java.util.*;
 import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.concurrent.locks.Lock;
 
 /**
  * Responsible for managing a class loader that allows ASM {@link ClassNode}s
@@ -58,6 +59,11 @@ public class PlasticClassPool implements
         }
     };
 
+    public Lock getClassLoaderLock()
+    {
+        return loader.classloaderLock;
+    }
+
     static class BaseClassDef
     {
         final InheritanceData inheritanceData;
@@ -395,7 +401,7 @@ public class PlasticClassPool implements
         }
     }
 
-    public synchronized ClassInstantiator getClassInstantiator(String className)
+    public ClassInstantiator getClassInstantiator(String className)
     {
         ClassInstantiator result;
 

Modified: tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/plastic/PlasticManager.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/plastic/PlasticManager.java?rev=1170760&r1=1170759&r2=1170760&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/plastic/PlasticManager.java (original)
+++ tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/plastic/PlasticManager.java Wed Sep 14 18:33:50 2011
@@ -14,15 +14,16 @@
 
 package org.apache.tapestry5.plastic;
 
-import java.util.Collection;
-import java.util.EnumSet;
-import java.util.Set;
-
 import org.apache.tapestry5.internal.plastic.Lockable;
 import org.apache.tapestry5.internal.plastic.NoopDelegate;
 import org.apache.tapestry5.internal.plastic.PlasticClassPool;
 import org.apache.tapestry5.internal.plastic.PlasticInternalUtils;
 
+import java.util.Collection;
+import java.util.EnumSet;
+import java.util.Set;
+import java.util.concurrent.locks.Lock;
+
 /**
  * Manages the internal class loaders and other logics necessary to load and transform existing classes,
  * or to create new classes dynamically at runtime. New instances are instantiates using
@@ -96,7 +97,7 @@ public class PlasticManager implements P
 
         /**
          * Creates the PlasticManager with the current set of options.
-         * 
+         *
          * @return the PlasticManager
          */
         public PlasticManager create()
@@ -115,7 +116,9 @@ public class PlasticManager implements P
         return withClassLoader(Thread.currentThread().getContextClassLoader());
     }
 
-    /** Creates a new builder using the specified class loader. */
+    /**
+     * Creates a new builder using the specified class loader.
+     */
     public static PlasticManagerBuilder withClassLoader(ClassLoader loader)
     {
         return new PlasticManagerBuilder(loader);
@@ -124,19 +127,15 @@ public class PlasticManager implements P
     /**
      * The standard constructor for PlasticManager, allowing a parent class loader to be specified (this is most often
      * the thread's contextClassLoader), as well as the delegate and the names of all controlled packages.
-     * 
-     * @param parentClassLoader
-     *            main source for (untransformed) classes
-     * @param delegate
-     *            performs transformations on top-level classes from controlled packages
-     * @param controlledPackageNames
-     *            defines the packages that are to be transformed; top-classes in these packages
-     *            (or sub-packages) will be passed to the delegate for transformation
-     * @param options
-     *            used when transforming classes
+     *
+     * @param parentClassLoader      main source for (untransformed) classes
+     * @param delegate               performs transformations on top-level classes from controlled packages
+     * @param controlledPackageNames defines the packages that are to be transformed; top-classes in these packages
+     *                               (or sub-packages) will be passed to the delegate for transformation
+     * @param options                used when transforming classes
      */
     private PlasticManager(ClassLoader parentClassLoader, PlasticManagerDelegate delegate,
-            Set<String> controlledPackageNames, Set<TransformationOption> options)
+                           Set<String> controlledPackageNames, Set<TransformationOption> options)
     {
         assert parentClassLoader != null;
         assert delegate != null;
@@ -149,7 +148,7 @@ public class PlasticManager implements P
      * Returns the ClassLoader that is used to instantiate transformed classes. The parent class loader
      * of the returned class loader is the context class loader, or the class loader specified by
      * {@link #withClassLoader(ClassLoader)}.
-     * 
+     *
      * @return class loader used to load classes in controlled packages
      */
     public ClassLoader getClassLoader()
@@ -163,7 +162,7 @@ public class PlasticManager implements P
      * PlasticClassTransformation.
      * TODO: This may make a kind of callback when we get to proxy creation, rather then pure transformation.
      * TODO: Clean up this mess!
-     * 
+     *
      * @throws ClassNotFoundException
      */
     <T> PlasticClassTransformation<T> getPlasticClass(String className) throws ClassNotFoundException
@@ -175,14 +174,12 @@ public class PlasticManager implements P
 
     /**
      * Gets the {@link ClassInstantiator} for the indicated class, which must be in a transformed package.
-     * 
-     * @param className
-     *            fully qualified class name
+     *
+     * @param className fully qualified class name
      * @return instantiator (configured via the
      *         {@linkplain PlasticManagerDelegate#configureInstantiator(String, ClassInstantiator) delegate} for the
      *         class
-     * @throws IllegalArgumentException
-     *             if the class is not a transformed class
+     * @throws IllegalArgumentException if the class is not a transformed class
      */
     public <T> ClassInstantiator<T> getClassInstantiator(String className)
     {
@@ -191,11 +188,9 @@ public class PlasticManager implements P
 
     /**
      * Creates an entirely new class, extending from the provided base class.
-     * 
-     * @param baseClass
-     *            class to extend from, which must be a class, not an interface
-     * @param callback
-     *            used to configure the new class
+     *
+     * @param baseClass class to extend from, which must be a class, not an interface
+     * @param callback  used to configure the new class
      * @return the instantiator, which allows instances of the new class to be created
      */
     public <T> ClassInstantiator<T> createClass(Class<T> baseClass, PlasticClassTransformer callback)
@@ -218,11 +213,9 @@ public class PlasticManager implements P
 
     /**
      * Creates an entirely new class. The class extends from Object and implements the provided interface.
-     * 
-     * @param interfaceType
-     *            class to extend from, which must be a class, not an interface
-     * @param callback
-     *            used to configure the new class
+     *
+     * @param interfaceType class to extend from, which must be a class, not an interface
+     * @param callback      used to configure the new class
      * @return the instantiator, which allows instances of the new class to be created
      * @see #createProxyTransformation(Class)
      */
@@ -241,9 +234,8 @@ public class PlasticManager implements P
      * Creates the underlying {@link PlasticClassTransformation} for an interface proxy. This should only be
      * used in the cases where encapsulating the PlasticClass construction into a {@linkplain PlasticClassTransformer
      * callback} is not feasible (which is the case for some of the older APIs inside Tapestry IoC).
-     * 
-     * @param interfaceType
-     *            class proxy will extend from
+     *
+     * @param interfaceType class proxy will extend from
      * @return transformation from which an instantiator may be created
      */
     public <T> PlasticClassTransformation<T> createProxyTransformation(Class interfaceType)
@@ -273,4 +265,13 @@ public class PlasticManager implements P
     {
         pool.removePlasticClassListener(listener);
     }
+
+    /**
+     * Returns a {@link Lock} that can be used to ensure synchronization with the manager's class loading and
+     * class transformation.
+     */
+    public Lock getClassloaderLock()
+    {
+        return pool.getClassLoaderLock();
+    }
 }

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ComponentInstantiatorSourceImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ComponentInstantiatorSourceImpl.java?rev=1170760&r1=1170759&r2=1170760&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ComponentInstantiatorSourceImpl.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ComponentInstantiatorSourceImpl.java Wed Sep 14 18:33:50 2011
@@ -53,6 +53,7 @@ import org.slf4j.Logger;
 
 import java.util.Map;
 import java.util.Set;
+import java.util.concurrent.locks.Lock;
 
 /**
  * A wrapper around a {@link PlasticManager} that allows certain classes to be modified as they are loaded.
@@ -225,8 +226,19 @@ public final class ComponentInstantiator
                         // Force the creation of the class (and the transformation of the class). This will first
                         // trigger transformations of any base classes.
 
-                        final ClassInstantiator<Component> plasticInstantiator = manager
-                                .getClassInstantiator(className);
+                        final ClassInstantiator<Component> plasticInstantiator;
+
+                        Lock lock = manager.getClassloaderLock();
+
+                        lock.lock();
+
+                        try
+                        {
+                            plasticInstantiator = manager.getClassInstantiator(className);
+                        } finally
+                        {
+                            lock.unlock();
+                        }
 
                         final ComponentModel model = classToModel.get(className);