Author: hlship
Date: Thu Sep 11 07:25:11 2008
New Revision: 694274

URL: http://svn.apache.org/viewvc?rev=694274&view=rev
Log:
TAPESTRY-2561: Rapidly refreshing a page, even the same page, can cause a 
deadlock related to class loading
                                

Modified:
    
tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/ModuleImpl.java

Modified: 
tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/ModuleImpl.java
URL: 
http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/ModuleImpl.java?rev=694274&r1=694273&r2=694274&view=diff
==============================================================================
--- 
tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/ModuleImpl.java
 (original)
+++ 
tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/ModuleImpl.java
 Thu Sep 11 07:25:11 2008
@@ -44,6 +44,9 @@
 
     private final Logger logger;
 
+    /**
+     * Lazily instantiated.  Access is guarded by BARRIER.
+     */
     private Object moduleBuilder;
 
     // Set to true when invoking the module constructor. Used to
@@ -52,11 +55,15 @@
     private boolean insideConstructor;
 
     /**
-     * Keyed on fully qualified service id; values are instantiated services 
(proxies).
+     * Keyed on fully qualified service id; values are instantiated services 
(proxies). Guarded by BARRIER.
      */
     private final Map<String, Object> services = 
CollectionFactory.newCaseInsensitiveMap();
 
-    private final ConcurrentBarrier barrier = new ConcurrentBarrier();
+    /**
+     * The barrier is shared by all modules, which means that creation of 
*any* service for any module is single
+     * threaded.
+     */
+    private final static ConcurrentBarrier BARRIER = new ConcurrentBarrier();
 
     public ModuleImpl(InternalRegistry registry, ServiceActivityTracker 
tracker, ModuleDef moduleDef,
                       ClassFactory classFactory, Logger logger)
@@ -148,9 +155,20 @@
         {
             public Object invoke()
             {
-                Object result = create(def, eagerLoadProxies);
+                // In a race condition, two threads may try to create the same 
service simulatenously.
+                // The second will block until after the first creates the 
service.
+
+                Object result = services.get(key);
 
-                services.put(key, result);
+                // Normally, result is null, unless some other thread slipped 
in and created the service
+                // proxy.
+
+                if (result == null)
+                {
+                    result = create(def, eagerLoadProxies);
+
+                    services.put(key, result);
+                }
 
                 return result;
             }
@@ -164,14 +182,14 @@
 
                 if (result == null)
                 {
-                    result = barrier.withWrite(create);
+                    result = BARRIER.withWrite(create);
                 }
 
                 return result;
             }
         };
 
-        return barrier.withRead(find);
+        return BARRIER.withRead(find);
     }
 
     public void collectEagerLoadServices(Collection<EagerLoadServiceProxy> 
proxies)
@@ -261,7 +279,7 @@
     {
         public Object invoke()
         {
-            if (moduleBuilder == null) 
barrier.withWrite(instantiateModuleBuilder);
+            if (moduleBuilder == null) 
BARRIER.withWrite(instantiateModuleBuilder);
 
             return moduleBuilder;
         }
@@ -269,7 +287,7 @@
 
     public Object getModuleBuilder()
     {
-        return barrier.withRead(provideModuleBuilder);
+        return BARRIER.withRead(provideModuleBuilder);
     }
 
     private Object constructModuleBuilder()


Reply via email to