You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tomcat.apache.org by ma...@apache.org on 2011/10/28 09:59:17 UTC

svn commit: r1190190 - in /tomcat/tc7.0.x/trunk: ./ java/org/apache/catalina/ java/org/apache/catalina/core/ java/org/apache/catalina/startup/ java/org/apache/coyote/ java/org/apache/tomcat/util/threads/ test/org/apache/tomcat/util/threads/ webapps/doc...

Author: markt
Date: Fri Oct 28 07:59:16 2011
New Revision: 1190190

URL: http://svn.apache.org/viewvc?rev=1190190&view=rev
Log:
Fix https://issues.apache.org/bugzilla/show_bug.cgi?id=46264
Implement threaded container start/stop

Removed:
    tomcat/tc7.0.x/trunk/java/org/apache/tomcat/util/threads/DedicatedThreadExecutor.java
    tomcat/tc7.0.x/trunk/test/org/apache/tomcat/util/threads/DedicatedThreadExecutorTest.java
Modified:
    tomcat/tc7.0.x/trunk/   (props changed)
    tomcat/tc7.0.x/trunk/java/org/apache/catalina/Container.java
    tomcat/tc7.0.x/trunk/java/org/apache/catalina/Host.java
    tomcat/tc7.0.x/trunk/java/org/apache/catalina/core/ContainerBase.java
    tomcat/tc7.0.x/trunk/java/org/apache/catalina/core/LocalStrings.properties
    tomcat/tc7.0.x/trunk/java/org/apache/catalina/core/StandardContext.java
    tomcat/tc7.0.x/trunk/java/org/apache/catalina/core/StandardHost.java
    tomcat/tc7.0.x/trunk/java/org/apache/catalina/core/mbeans-descriptors.xml
    tomcat/tc7.0.x/trunk/java/org/apache/catalina/startup/ContextConfig.java
    tomcat/tc7.0.x/trunk/java/org/apache/catalina/startup/HostConfig.java
    tomcat/tc7.0.x/trunk/java/org/apache/catalina/startup/LocalStrings.properties
    tomcat/tc7.0.x/trunk/java/org/apache/coyote/AbstractProtocol.java
    tomcat/tc7.0.x/trunk/webapps/docs/config/engine.xml
    tomcat/tc7.0.x/trunk/webapps/docs/config/host.xml

Propchange: tomcat/tc7.0.x/trunk/
------------------------------------------------------------------------------
--- svn:mergeinfo (original)
+++ svn:mergeinfo Fri Oct 28 07:59:16 2011
@@ -1 +1 @@
-/tomcat/trunk:1156115,1156171,1156276,1156304,1156519,1156530,1156602,1157015,1157018,1157151,1157198,1157204,1157810,1157832,1157834,1157847,1157908,1157939,1158155,1158160,1158176,1158195,1158198-1158199,1158227,1158331,1158334-1158335,1158426,1160347,1160592,1160611,1160619,1160626,1160639,1160652,1160720-1160721,1160772,1160774,1160776,1161303,1161310,1161322,1161339,1161486,1161540,1161549,1161584,1162082,1162149,1162169,1162721,1162769,1162836,1162932,1163630,1164419,1164438,1164469,1164480,1164567,1165234,1165247-1165248,1165253,1165273,1165282,1165309,1165331,1165338,1165347,1165360-1165361,1165367-1165368,1165602,1165608,1165677,1165693,1165721,1165723,1165728,1165730,1165738,1165746,1165765,1165777,1165918,1165921,1166077,1166150-1166151,1166290,1166366,1166620,1166686,1166693,1166752,1166757,1167368,1167394,1169447,1170647,1171692,1172233-1172234,1172236,1172269,1172278,1172282,1172556,1172610,1172664,1172689,1172711,1173020-1173021,1173082,1173088,1173090,1173096
 ,1173241,1173256,1173288,1173333,1173342,1173461,1173614,1173630,1173659,1173722,1174061,1174239,1174322,1174325,1174329-1174330,1174337-1174339,1174343,1174353,1174799,1174882,1174884,1174983,1175155,1175158,1175167,1175182,1175190,1175201,1175272,1175275,1175283,1175582,1175589-1175590,1175594,1175602,1175613,1175633,1175690,1175713,1175889,1175896,1175907,1176584,1176590,1176799,1177050,1177060,1177125,1177152,1177160,1177245,1177850,1177862,1177978,1178209,1178228,1178233,1178449,1178542,1178681,1178684,1178721,1179268,1179274,1180261,1180865,1180891,1180894,1180907,1181028,1181123,1181125,1181136,1181291,1181743,1182796,1183078,1183105,1183142,1183328,1183339-1183340,1183492-1183494,1183605,1184917,1184919,1185018,1185020,1185200,1185588,1185626,1185756,1185758,1186011,1186042-1186045,1186104,1186123,1186137,1186153,1186254,1186257,1186377-1186379,1186479-1186480,1186712,1186743,1186750,1186763,1186890-1186892,1186894,1186949,1187018,1187027-1187028,1187381,1187755,1187
 775,1187827,1188301,1188303-1188305,1188399,1188822,1188930-1188931,1189116,1189129,1189183,1189240,1189256,1189386,1189413-1189414,1189477,1189685,1189805,1189857,1189864,1189882,1190034
+/tomcat/trunk:1156115,1156171,1156276,1156304,1156519,1156530,1156602,1157015,1157018,1157151,1157198,1157204,1157810,1157832,1157834,1157847,1157908,1157939,1158155,1158160,1158176,1158195,1158198-1158199,1158227,1158331,1158334-1158335,1158426,1160347,1160592,1160611,1160619,1160626,1160639,1160652,1160720-1160721,1160772,1160774,1160776,1161303,1161310,1161322,1161339,1161486,1161540,1161549,1161584,1162082,1162149,1162169,1162721,1162769,1162836,1162932,1163630,1164419,1164438,1164469,1164480,1164567,1165234,1165247-1165248,1165253,1165273,1165282,1165309,1165331,1165338,1165347,1165360-1165361,1165367-1165368,1165602,1165608,1165677,1165693,1165721,1165723,1165728,1165730,1165738,1165746,1165765,1165777,1165918,1165921,1166077,1166150-1166151,1166290,1166366,1166620,1166686,1166693,1166752,1166757,1167368,1167394,1169447,1170647,1171692,1172233-1172234,1172236,1172269,1172278,1172282,1172556,1172610,1172664,1172689,1172711,1173020-1173021,1173082,1173088,1173090,1173096
 ,1173241,1173256,1173288,1173333,1173342,1173461,1173614,1173630,1173659,1173722,1174061,1174239,1174322,1174325,1174329-1174330,1174337-1174339,1174343,1174353,1174799,1174882,1174884,1174983,1175155,1175158,1175167,1175182,1175190,1175201,1175272,1175275,1175283,1175582,1175589-1175590,1175594,1175602,1175613,1175633,1175690,1175713,1175889,1175896,1175907,1176584,1176590,1176799,1177050,1177060,1177125,1177152,1177160,1177245,1177850,1177862,1177978,1178209,1178228,1178233,1178449,1178542,1178681,1178684,1178721,1179268,1179274,1180261,1180865,1180891,1180894,1180907,1181028,1181123,1181125,1181136,1181291,1181743,1182796,1183078,1183105,1183142,1183328,1183339-1183340,1183492-1183494,1183605,1184917,1184919,1185018,1185020,1185200,1185588,1185626,1185756,1185758,1186011,1186042-1186045,1186104,1186123,1186137,1186153,1186254,1186257,1186377-1186379,1186479-1186480,1186712,1186743,1186750,1186763,1186890-1186892,1186894,1186949,1187018,1187027-1187028,1187381,1187755,1187
 775,1187827,1188301,1188303-1188305,1188399,1188822,1188930-1188931,1189116,1189129,1189183,1189240,1189256,1189386,1189413-1189414,1189477,1189685,1189805,1189857,1189864,1189882,1190034,1190185

Modified: tomcat/tc7.0.x/trunk/java/org/apache/catalina/Container.java
URL: http://svn.apache.org/viewvc/tomcat/tc7.0.x/trunk/java/org/apache/catalina/Container.java?rev=1190190&r1=1190189&r2=1190190&view=diff
==============================================================================
--- tomcat/tc7.0.x/trunk/java/org/apache/catalina/Container.java (original)
+++ tomcat/tc7.0.x/trunk/java/org/apache/catalina/Container.java Fri Oct 28 07:59:16 2011
@@ -477,4 +477,21 @@ public interface Container extends Lifec
      * that the request/response still appears in the correct access logs.
      */
     public AccessLog getAccessLog();
+
+
+    /**
+     * Returns the number of threads available for starting and stopping any
+     * children associated with this container. This allows start/stop calls to
+     * children to be processed in parallel.
+     */
+    public int getStartStopThreads();
+
+
+    /**
+     * Sets the number of threads available for starting and stopping any
+     * children associated with this container. This allows start/stop calls to
+     * children to be processed in parallel.
+     * @param   startStopThreads    The new number of threads to be used
+     */
+    public void setStartStopThreads(int startStopThreads);
 }

Modified: tomcat/tc7.0.x/trunk/java/org/apache/catalina/Host.java
URL: http://svn.apache.org/viewvc/tomcat/tc7.0.x/trunk/java/org/apache/catalina/Host.java?rev=1190190&r1=1190189&r2=1190190&view=diff
==============================================================================
--- tomcat/tc7.0.x/trunk/java/org/apache/catalina/Host.java (original)
+++ tomcat/tc7.0.x/trunk/java/org/apache/catalina/Host.java Fri Oct 28 07:59:16 2011
@@ -16,6 +16,7 @@
  */
 package org.apache.catalina;
 
+import java.util.concurrent.ExecutorService;
 import java.util.regex.Pattern;
 
 
@@ -171,9 +172,16 @@ public interface Host extends Container 
     public void setDeployIgnore(String deployIgnore);
 
 
-    // --------------------------------------------------------- Public Methods
+    /**
+     * Return the executor that is used for starting and stopping contexts. This
+     * is primarily for use by components deploying contexts that want to do
+     * this in a multi-threaded manner.
+     */
+    public ExecutorService getStartStopExecutor();
 
 
+    // --------------------------------------------------------- Public Methods
+
     /**
      * Add an alias name that should be mapped to this same Host.
      *

Modified: tomcat/tc7.0.x/trunk/java/org/apache/catalina/core/ContainerBase.java
URL: http://svn.apache.org/viewvc/tomcat/tc7.0.x/trunk/java/org/apache/catalina/core/ContainerBase.java?rev=1190190&r1=1190189&r2=1190190&view=diff
==============================================================================
--- tomcat/tc7.0.x/trunk/java/org/apache/catalina/core/ContainerBase.java (original)
+++ tomcat/tc7.0.x/trunk/java/org/apache/catalina/core/ContainerBase.java Fri Oct 28 07:59:16 2011
@@ -26,6 +26,13 @@ import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.Hashtable;
 import java.util.Iterator;
+import java.util.List;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.Callable;
+import java.util.concurrent.Future;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.ThreadPoolExecutor;
+import java.util.concurrent.TimeUnit;
 
 import javax.management.ObjectName;
 import javax.naming.directory.DirContext;
@@ -274,8 +281,55 @@ public abstract class ContainerBase exte
     protected volatile AccessLog accessLog = null;
     private volatile boolean accessLogScanComplete = false;
 
+
+    /**
+     * The number of threads available to process start and stop events for any
+     * children associated with this container.
+     */
+    private int startStopThreads = 1;
+    protected ThreadPoolExecutor startStopExecutor;
+
     // ------------------------------------------------------------- Properties
 
+    @Override
+    public int getStartStopThreads() {
+        return startStopThreads;
+    }
+
+    /**
+     * Handles the special values.
+     */
+    private int getStartStopThreadsInternal() {
+        int result = getStartStopThreads();
+
+        // Positive values are unchanged
+        if (result > 0) {
+            return result;
+        }
+
+        // Zero == Runtime.getRuntime().availableProcessors()
+        // -ve  == Runtime.getRuntime().availableProcessors() + value
+        // These two are the same
+        result = Runtime.getRuntime().availableProcessors() + result;
+        if (result < 1) {
+            result = 1;
+        }
+        return result;
+    }
+
+    @Override
+    public void setStartStopThreads(int startStopThreads) {
+        this.startStopThreads = startStopThreads;
+
+        // Use local copies to ensure thread safety
+        ThreadPoolExecutor executor = startStopExecutor;
+        if (executor != null) {
+            int newThreads = getStartStopThreadsInternal();
+            executor.setMaximumPoolSize(newThreads);
+            executor.setCorePoolSize(newThreads);
+        }
+    }
+
 
     /**
      * Get the delay between the invocation of the backgroundProcess method on
@@ -1002,6 +1056,19 @@ public abstract class ContainerBase exte
     }
 
 
+    @Override
+    protected void initInternal() throws LifecycleException {
+        BlockingQueue<Runnable> startStopQueue =
+            new LinkedBlockingQueue<Runnable>();
+        startStopExecutor = new ThreadPoolExecutor(
+                getStartStopThreadsInternal(),
+                getStartStopThreadsInternal(), 10, TimeUnit.SECONDS,
+                startStopQueue);
+        startStopExecutor.allowCoreThreadTimeOut(true);
+        super.initInternal();
+    }
+
+
     /**
      * Start this component and implement the requirements
      * of {@link org.apache.catalina.util.LifecycleBase#startInternal()}.
@@ -1030,8 +1097,24 @@ public abstract class ContainerBase exte
 
         // Start our child containers, if any
         Container children[] = findChildren();
+        List<Future<Void>> results = new ArrayList<Future<Void>>();
         for (int i = 0; i < children.length; i++) {
-            children[i].start();
+            results.add(startStopExecutor.submit(new StartChild(children[i])));
+        }
+
+        boolean fail = false;
+        for (Future<Void> result : results) {
+            try {
+                result.get();
+            } catch (Exception e) {
+                log.error(sm.getString("containerBase.threadedStartFailed"), e);
+                fail = true;
+            }
+
+        }
+        if (fail) {
+            throw new LifecycleException(
+                    sm.getString("containerBase.threadedStartFailed"));
         }
 
         // Start the Valves in our pipeline (including the basic), if any
@@ -1070,8 +1153,23 @@ public abstract class ContainerBase exte
 
         // Stop our child containers, if any
         Container children[] = findChildren();
+        List<Future<Void>> results = new ArrayList<Future<Void>>();
         for (int i = 0; i < children.length; i++) {
-            children[i].stop();
+            results.add(startStopExecutor.submit(new StopChild(children[i])));
+        }
+
+        boolean fail = false;
+        for (Future<Void> result : results) {
+            try {
+                result.get();
+            } catch (Exception e) {
+                log.error(sm.getString("containerBase.threadedStopFailed"), e);
+                fail = true;
+            }
+        }
+        if (fail) {
+            throw new LifecycleException(
+                    sm.getString("containerBase.threadedStopFailed"));
         }
 
         // Stop our subordinate components, if any
@@ -1114,6 +1212,8 @@ public abstract class ContainerBase exte
             parent.removeChild(this);
         }
 
+        startStopExecutor.shutdownNow();
+
         super.destroyInternal();
     }
 
@@ -1413,4 +1513,37 @@ public abstract class ContainerBase exte
             }
         }
     }
+
+
+    // ----------------------------- Inner classes used with start/stop Executor
+
+    private static class StartChild implements Callable<Void> {
+
+        private Container child;
+
+        public StartChild(Container child) {
+            this.child = child;
+        }
+
+        @Override
+        public Void call() throws LifecycleException {
+            child.start();
+            return null;
+        }
+    }
+
+    private static class StopChild implements Callable<Void> {
+
+        private Container child;
+
+        public StopChild(Container child) {
+            this.child = child;
+        }
+
+        @Override
+        public Void call() throws LifecycleException {
+            child.stop();
+            return null;
+        }
+    }
 }

Modified: tomcat/tc7.0.x/trunk/java/org/apache/catalina/core/LocalStrings.properties
URL: http://svn.apache.org/viewvc/tomcat/tc7.0.x/trunk/java/org/apache/catalina/core/LocalStrings.properties?rev=1190190&r1=1190189&r2=1190190&view=diff
==============================================================================
--- tomcat/tc7.0.x/trunk/java/org/apache/catalina/core/LocalStrings.properties (original)
+++ tomcat/tc7.0.x/trunk/java/org/apache/catalina/core/LocalStrings.properties Fri Oct 28 07:59:16 2011
@@ -60,9 +60,8 @@ aprListener.sslInit=Failed to initialize
 aprListener.tcnValid=Loaded APR based Apache Tomcat Native library {0}.
 aprListener.flags=APR capabilities: IPv6 [{0}], sendfile [{1}], accept filters [{2}], random [{3}].
 asyncContextImpl.requestEnded=The request associated with the AsyncContext has already completed processing.
-containerBase.alreadyStarted=Container {0} has already been started
-containerBase.notConfigured=No basic Valve has been configured
-containerBase.notStarted=Container {0} has not been started
+containerBase.threadedStartFailed=A child container failed during start
+containerBase.threadedStopFailed=A child container failed during stop
 containerBase.backgroundProcess.cluster=Exception processing cluster {0} background process
 containerBase.backgroundProcess.loader=Exception processing loader {0} background process
 containerBase.backgroundProcess.manager=Exception processing manager {0} background process

Modified: tomcat/tc7.0.x/trunk/java/org/apache/catalina/core/StandardContext.java
URL: http://svn.apache.org/viewvc/tomcat/tc7.0.x/trunk/java/org/apache/catalina/core/StandardContext.java?rev=1190190&r1=1190189&r2=1190190&view=diff
==============================================================================
--- tomcat/tc7.0.x/trunk/java/org/apache/catalina/core/StandardContext.java (original)
+++ tomcat/tc7.0.x/trunk/java/org/apache/catalina/core/StandardContext.java Fri Oct 28 07:59:16 2011
@@ -37,7 +37,6 @@ import java.util.Map;
 import java.util.Set;
 import java.util.Stack;
 import java.util.TreeMap;
-import java.util.concurrent.Callable;
 import java.util.concurrent.atomic.AtomicLong;
 
 import javax.management.ListenerNotFoundException;
@@ -118,7 +117,6 @@ import org.apache.tomcat.JarScanner;
 import org.apache.tomcat.util.ExceptionUtils;
 import org.apache.tomcat.util.modeler.Registry;
 import org.apache.tomcat.util.scan.StandardJarScanner;
-import org.apache.tomcat.util.threads.DedicatedThreadExecutor;
 
 /**
  * Standard implementation of the <b>Context</b> interface.  Each
@@ -5208,9 +5206,7 @@ public class StandardContext extends Con
             }
         }
 
-        DedicatedThreadExecutor temporaryExecutor = new DedicatedThreadExecutor();
         try {
-            
             // Create context attributes that will be required
             if (ok) {
                 getServletContext().setAttribute(
@@ -5235,22 +5231,7 @@ public class StandardContext extends Con
 
             // Configure and call application event listeners
             if (ok) {
-                // we do it in a dedicated thread for memory leak protection, in
-                // case the Listeners registers some ThreadLocals that they
-                // forget to cleanup
-                Boolean listenerStarted =
-                    temporaryExecutor.execute(new Callable<Boolean>() {
-                        @Override
-                        public Boolean call() throws Exception {
-                            ClassLoader old = bindThread();
-                            try {
-                                return Boolean.valueOf(listenerStart());
-                            } finally {
-                                unbindThread(old);
-                            }
-                        }
-                    });
-                if (!listenerStarted.booleanValue()) {
+                if (!listenerStart()) {
                     log.error( "Error listenerStart");
                     ok = false;
                 }
@@ -5271,22 +5252,7 @@ public class StandardContext extends Con
 
             // Configure and call application filters
             if (ok) {
-                // we do it in a dedicated thread for memory leak protection, in
-                // case the Filters register some ThreadLocals that they forget
-                // to cleanup
-                Boolean filterStarted =
-                    temporaryExecutor.execute(new Callable<Boolean>() {
-                        @Override
-                        public Boolean call() throws Exception {
-                            ClassLoader old = bindThread();
-                            try {
-                                return Boolean.valueOf(filterStart());
-                            } finally {
-                                unbindThread(old);
-                            }
-                        }
-                    });
-                if (!filterStarted.booleanValue()) {
+                if (!filterStart()) {
                     log.error("Error filterStart");
                     ok = false;
                 }
@@ -5294,27 +5260,12 @@ public class StandardContext extends Con
             
             // Load and initialize all "load on startup" servlets
             if (ok) {
-                // we do it in a dedicated thread for memory leak protection, in
-                // case the Servlets register some ThreadLocals that they forget
-                // to cleanup
-                temporaryExecutor.execute(new Callable<Void>() {
-                    @Override
-                    public Void call() throws Exception {
-                        ClassLoader old = bindThread();
-                        try {
-                            loadOnStartup(findChildren());
-                            return null;
-                        } finally {
-                            unbindThread(old);
-                        }
-                    }
-                });
+                loadOnStartup(findChildren());
             }
             
         } finally {
             // Unbinding thread
             unbindThread(oldCCL);
-            temporaryExecutor.shutdown();
         }
 
         // Set available status depending upon startup success
@@ -5454,61 +5405,28 @@ public class StandardContext extends Con
 
             // Stop our child containers, if any
             final Container[] children = findChildren();
-            // we do it in a dedicated thread for memory leak protection, in
-            // case some webapp code registers some ThreadLocals that they
-            // forget to cleanup
-            // TODO Figure out why DedicatedThreadExecutor hangs randomly in the
-            //      unit tests if used here
-            RunnableWithLifecycleException stop =
-                    new RunnableWithLifecycleException() {
-                @Override
-                public void run() {
-                    ClassLoader old = bindThread();
-                    try {
-                        for (int i = 0; i < children.length; i++) {
-                            try {
-                                children[i].stop();
-                            } catch (LifecycleException e) {
-                                le = e;
-                                return;
-                            }
-                        }
             
-                        // Stop our filters
-                        filterStop();
+            ClassLoader old = bindThread();
+            try {
+                for (int i = 0; i < children.length; i++) {
+                    children[i].stop();
+                }
             
-                        // Stop ContainerBackgroundProcessor thread
-                        threadStop();
+                // Stop our filters
+                filterStop();
             
-                        if (manager != null && manager instanceof Lifecycle &&
-                                ((Lifecycle) manager).getState().isAvailable()) {
-                            try {
-                                ((Lifecycle) manager).stop();
-                            } catch (LifecycleException e) {
-                                le = e;
-                                return;
-                            }
-                        }
+                // Stop ContainerBackgroundProcessor thread
+                threadStop();
             
-                        // Stop our application listeners
-                        listenerStop();
-                    }finally{
-                        unbindThread(old);
-                    }
+                if (manager != null && manager instanceof Lifecycle &&
+                        ((Lifecycle) manager).getState().isAvailable()) {
+                    ((Lifecycle) manager).stop();
                 }
-            };
             
-            Thread t = new Thread(stop);
-            t.setName("stop children - " + getObjectName().toString());
-            t.start();
-            try {
-                t.join();
-            } catch (InterruptedException e) {
-                // Shouldn't happen
-                throw new LifecycleException(e);
-            }
-            if (stop.getLifecycleException() != null) {
-                throw stop.getLifecycleException();
+                // Stop our application listeners
+                listenerStop();
+            } finally{
+                unbindThread(old);
             }
 
             // Finalize our character set mapper
@@ -6564,14 +6482,4 @@ public class StandardContext extends Con
     public boolean isStatisticsProvider() {
         return false;
     }
-
-    private abstract static class RunnableWithLifecycleException
-            implements Runnable {
-        
-        protected LifecycleException le = null;
-        
-        public LifecycleException getLifecycleException() {
-            return le;
-        }
-    }
 }

Modified: tomcat/tc7.0.x/trunk/java/org/apache/catalina/core/StandardHost.java
URL: http://svn.apache.org/viewvc/tomcat/tc7.0.x/trunk/java/org/apache/catalina/core/StandardHost.java?rev=1190190&r1=1190189&r2=1190190&view=diff
==============================================================================
--- tomcat/tc7.0.x/trunk/java/org/apache/catalina/core/StandardHost.java (original)
+++ tomcat/tc7.0.x/trunk/java/org/apache/catalina/core/StandardHost.java Fri Oct 28 07:59:16 2011
@@ -22,6 +22,7 @@ import java.util.List;
 import java.util.Locale;
 import java.util.Map;
 import java.util.WeakHashMap;
+import java.util.concurrent.ExecutorService;
 import java.util.regex.Pattern;
 
 import org.apache.catalina.Container;
@@ -179,6 +180,11 @@ public class StandardHost extends Contai
 
     // ------------------------------------------------------------- Properties
 
+     @Override
+     public ExecutorService getStartStopExecutor() {
+         return startStopExecutor;
+     }
+
 
     /**
      * Return the application root for this Host.  This can be an absolute

Modified: tomcat/tc7.0.x/trunk/java/org/apache/catalina/core/mbeans-descriptors.xml
URL: http://svn.apache.org/viewvc/tomcat/tc7.0.x/trunk/java/org/apache/catalina/core/mbeans-descriptors.xml?rev=1190190&r1=1190189&r2=1190190&view=diff
==============================================================================
--- tomcat/tc7.0.x/trunk/java/org/apache/catalina/core/mbeans-descriptors.xml (original)
+++ tomcat/tc7.0.x/trunk/java/org/apache/catalina/core/mbeans-descriptors.xml Fri Oct 28 07:59:16 2011
@@ -1011,6 +1011,10 @@
                description="Will children be started automatically when they are added."
                type="boolean"/>  
 
+    <attribute name="startStopThreads"
+               description="The number of threads to use when starting and stopping child Hosts"
+               type="int"/>
+
     <attribute name="stateName"
                description="The name of the LifecycleState that this component is currently in"
                type="java.lang.String"
@@ -1198,6 +1202,10 @@
                description="Will children be started automatically when they are added?"
                type="boolean"/>            
 
+    <attribute name="startStopThreads"
+               description="The number of threads to use when starting, stopping and deploying child Contexts"
+               type="int"/>
+
     <attribute name="stateName"
                description="The name of the LifecycleState that this component is currently in"
                type="java.lang.String"

Modified: tomcat/tc7.0.x/trunk/java/org/apache/catalina/startup/ContextConfig.java
URL: http://svn.apache.org/viewvc/tomcat/tc7.0.x/trunk/java/org/apache/catalina/startup/ContextConfig.java?rev=1190190&r1=1190189&r2=1190190&view=diff
==============================================================================
--- tomcat/tc7.0.x/trunk/java/org/apache/catalina/startup/ContextConfig.java (original)
+++ tomcat/tc7.0.x/trunk/java/org/apache/catalina/startup/ContextConfig.java Fri Oct 28 07:59:16 2011
@@ -127,11 +127,6 @@ public class ContextConfig
     protected static final LoginConfig DUMMY_LOGIN_CONFIG =
         new LoginConfig("NONE", null, null, null);
 
-    /**
-     * The <code>Digester</code> we will use to process web application
-     * context files.
-     */
-    protected static Digester contextDigester = null;
     
 
     /**
@@ -143,32 +138,6 @@ public class ContextConfig
 
 
     /**
-     * The <code>Digester</code>s available to process web deployment descriptor
-     * files.
-     */
-    protected static Digester[] webDigesters = new Digester[4];
-
-
-    /**
-     * The <code>Digester</code>s available to process web fragment deployment
-     * descriptor files.
-     */
-    protected static Digester[] webFragmentDigesters = new Digester[4];
-
-
-    /**
-     * The <code>Rule</code>s used to parse the web.xml
-     */
-    protected static WebRuleSet webRuleSet = new WebRuleSet(false);
-
-
-    /**
-     * The <code>Rule</code>s used to parse the web-fragment.xml
-     */
-    protected static WebRuleSet webFragmentRuleSet = new WebRuleSet(true);
-
-
-    /**
      * Deployment count.
      */
     protected static long deploymentCount = 0L;
@@ -236,12 +205,14 @@ public class ContextConfig
      * deployment descriptor files.
      */
     protected Digester webDigester = null;
+    protected WebRuleSet webRuleSet = null;
 
     /**
      * The <code>Digester</code> we will use to process web fragment
      * deployment descriptor files.
      */
     protected Digester webFragmentDigester = null;
+    protected WebRuleSet webFragmentRuleSet = null;
 
     
     // ------------------------------------------------------------- Properties
@@ -485,60 +456,21 @@ public class ContextConfig
 
 
     /**
-     * Create (if necessary) and return a Digester configured to process the
+     * Create and return a Digester configured to process the
      * web application deployment descriptor (web.xml).
      */
     public void createWebXmlDigester(boolean namespaceAware,
             boolean validation) {
         
-        if (!namespaceAware && !validation) {
-            if (webDigesters[0] == null) {
-                webDigesters[0] = DigesterFactory.newDigester(validation,
-                        namespaceAware, webRuleSet);
-                webFragmentDigesters[0] = DigesterFactory.newDigester(validation,
-                        namespaceAware, webFragmentRuleSet);
-                webDigesters[0].getParser();
-                webFragmentDigesters[0].getParser();
-            }
-            webDigester = webDigesters[0];
-            webFragmentDigester = webFragmentDigesters[0];
-            
-        } else if (!namespaceAware && validation) {
-            if (webDigesters[1] == null) {
-                webDigesters[1] = DigesterFactory.newDigester(validation,
-                        namespaceAware, webRuleSet);
-                webFragmentDigesters[1] = DigesterFactory.newDigester(validation,
-                        namespaceAware, webFragmentRuleSet);
-                webDigesters[1].getParser();
-                webFragmentDigesters[1].getParser();
-            }
-            webDigester = webDigesters[1];
-            webFragmentDigester = webFragmentDigesters[1];
-            
-        } else if (namespaceAware && !validation) {
-            if (webDigesters[2] == null) {
-                webDigesters[2] = DigesterFactory.newDigester(validation,
-                        namespaceAware, webRuleSet);
-                webFragmentDigesters[2] = DigesterFactory.newDigester(validation,
-                        namespaceAware, webFragmentRuleSet);
-                webDigesters[2].getParser();
-                webFragmentDigesters[2].getParser();
-            }
-            webDigester = webDigesters[2];
-            webFragmentDigester = webFragmentDigesters[2];
-            
-        } else {
-            if (webDigesters[3] == null) {
-                webDigesters[3] = DigesterFactory.newDigester(validation,
-                        namespaceAware, webRuleSet);
-                webFragmentDigesters[3] = DigesterFactory.newDigester(validation,
-                        namespaceAware, webFragmentRuleSet);
-                webDigesters[3].getParser();
-                webFragmentDigesters[3].getParser();
-            }
-            webDigester = webDigesters[3];
-            webFragmentDigester = webFragmentDigesters[3];
-        }
+        webRuleSet = new WebRuleSet(false);
+        webDigester = DigesterFactory.newDigester(validation,
+                namespaceAware, webRuleSet);
+        webDigester.getParser();
+            
+        webFragmentRuleSet = new WebRuleSet(true);
+        webFragmentDigester = DigesterFactory.newDigester(validation,
+                namespaceAware, webFragmentRuleSet);
+        webFragmentDigester.getParser();
     }
 
     
@@ -576,7 +508,7 @@ public class ContextConfig
     /**
      * Process the default configuration file, if it exists.
      */
-    protected void contextConfig() {
+    protected void contextConfig(Digester digester) {
         
         // Open the default context.xml file, if it exists
         if( defaultContextXml==null && context instanceof StandardContext ) {
@@ -593,7 +525,7 @@ public class ContextConfig
             if (defaultContextFile.exists()) {
                 try {
                     URL defaultContextUrl = defaultContextFile.toURI().toURL();
-                    processContextConfig(defaultContextUrl);
+                    processContextConfig(digester, defaultContextUrl);
                 } catch (MalformedURLException e) {
                     log.error(sm.getString(
                             "contextConfig.badUrl", defaultContextFile), e);
@@ -605,7 +537,7 @@ public class ContextConfig
             if (hostContextFile.exists()) {
                 try {
                     URL hostContextUrl = hostContextFile.toURI().toURL();
-                    processContextConfig(hostContextUrl);
+                    processContextConfig(digester, hostContextUrl);
                 } catch (MalformedURLException e) {
                     log.error(sm.getString(
                             "contextConfig.badUrl", hostContextFile), e);
@@ -613,7 +545,7 @@ public class ContextConfig
             }
         }
         if (context.getConfigFile() != null)
-            processContextConfig(context.getConfigFile());
+            processContextConfig(digester, context.getConfigFile());
         
     }
 
@@ -621,7 +553,7 @@ public class ContextConfig
     /**
      * Process a context.xml.
      */
-    protected void processContextConfig(URL contextXml) {
+    protected void processContextConfig(Digester digester, URL contextXml) {
         
         if (log.isDebugEnabled())
             log.debug("Processing context [" + context.getName() 
@@ -647,44 +579,43 @@ public class ContextConfig
         
         if (source == null)
             return;
-        synchronized (contextDigester) {
-            try {
-                source.setByteStream(stream);
-                contextDigester.setClassLoader(this.getClass().getClassLoader());
-                contextDigester.setUseContextClassLoader(false);
-                contextDigester.push(context.getParent());
-                contextDigester.push(context);
-                XmlErrorHandler errorHandler = new XmlErrorHandler();
-                contextDigester.setErrorHandler(errorHandler);
-                contextDigester.parse(source);
-                if (errorHandler.getWarnings().size() > 0 ||
-                        errorHandler.getErrors().size() > 0) {
-                    errorHandler.logFindings(log, contextXml.toString());
-                    ok = false;
-                }
-                if (log.isDebugEnabled())
-                    log.debug("Successfully processed context [" + context.getName() 
-                            + "] configuration file [" + contextXml + "]");
-            } catch (SAXParseException e) {
-                log.error(sm.getString("contextConfig.contextParse",
-                        context.getName()), e);
-                log.error(sm.getString("contextConfig.defaultPosition",
-                                 "" + e.getLineNumber(),
-                                 "" + e.getColumnNumber()));
-                ok = false;
-            } catch (Exception e) {
-                log.error(sm.getString("contextConfig.contextParse",
-                        context.getName()), e);
+
+        try {
+            source.setByteStream(stream);
+            digester.setClassLoader(this.getClass().getClassLoader());
+            digester.setUseContextClassLoader(false);
+            digester.push(context.getParent());
+            digester.push(context);
+            XmlErrorHandler errorHandler = new XmlErrorHandler();
+            digester.setErrorHandler(errorHandler);
+            digester.parse(source);
+            if (errorHandler.getWarnings().size() > 0 ||
+                    errorHandler.getErrors().size() > 0) {
+                errorHandler.logFindings(log, contextXml.toString());
                 ok = false;
-            } finally {
-                contextDigester.reset();
-                try {
-                    if (stream != null) {
-                        stream.close();
-                    }
-                } catch (IOException e) {
-                    log.error(sm.getString("contextConfig.contextClose"), e);
+            }
+            if (log.isDebugEnabled()) {
+                log.debug("Successfully processed context [" + context.getName()
+                        + "] configuration file [" + contextXml + "]");
+            }
+        } catch (SAXParseException e) {
+            log.error(sm.getString("contextConfig.contextParse",
+                    context.getName()), e);
+            log.error(sm.getString("contextConfig.defaultPosition",
+                             "" + e.getLineNumber(),
+                             "" + e.getColumnNumber()));
+            ok = false;
+        } catch (Exception e) {
+            log.error(sm.getString("contextConfig.contextParse",
+                    context.getName()), e);
+            ok = false;
+        } finally {
+            try {
+                if (stream != null) {
+                    stream.close();
                 }
+            } catch (IOException e) {
+                log.error(sm.getString("contextConfig.contextClose"), e);
             }
         }
     }
@@ -851,17 +782,15 @@ public class ContextConfig
     protected void init() {
         // Called from StandardContext.init()
 
-        if (contextDigester == null){
-            contextDigester = createContextDigester();
-            contextDigester.getParser();
-        }
+        Digester contextDigester = createContextDigester();
+        contextDigester.getParser();
 
         if (log.isDebugEnabled())
             log.debug(sm.getString("contextConfig.init"));
         context.setConfigured(false);
         ok = true;
         
-        contextConfig();
+        contextConfig(contextDigester);
         
         createWebXmlDigester(context.getXmlNamespaceAware(),
                 context.getXmlValidation());
@@ -1413,8 +1342,9 @@ public class ContextConfig
         }
         
         // Parsing global web.xml is relatively expensive. Use a sync block to
-        // make sure it only happens once
-        synchronized (host) {
+        // make sure it only happens once. Use the pipeline since a lock will
+        // already be held on the host by another thread
+        synchronized (host.getPipeline()) {
             entry = hostWebXmlCache.get(host);
             if (entry != null && entry.getGlobalTimeStamp() == globalTimeStamp &&
                     entry.getHostTimeStamp() == hostTimeStamp) {
@@ -1672,8 +1602,8 @@ public class ContextConfig
         }
         return getWebXmlSource(defaultWebXml, getBaseDir());
     }
-    
-    
+
+
     /**
      * Identify the host web.xml to be used and obtain an input source for
      * it.
@@ -1797,9 +1727,6 @@ public class ContextConfig
 
         XmlErrorHandler handler = new XmlErrorHandler();
 
-        // Web digesters and rulesets are shared between contexts but are not
-        // thread safe. Whilst there should only be one thread at a time
-        // processing a config, play safe and sync.
         Digester digester;
         WebRuleSet ruleSet;
         if (fragment) {
@@ -1810,41 +1737,36 @@ public class ContextConfig
             ruleSet = webRuleSet;
         }
         
-        // Sync on the ruleSet since the same ruleSet is shared across all four
-        // digesters
-        synchronized(ruleSet) {
-            
-            digester.push(dest);
-            digester.setErrorHandler(handler);
-            
-            if(log.isDebugEnabled()) {
-                log.debug(sm.getString("contextConfig.applicationStart",
-                        source.getSystemId()));
-            }
-
-            try {
-                digester.parse(source);
+        digester.push(dest);
+        digester.setErrorHandler(handler);
+            
+        if(log.isDebugEnabled()) {
+            log.debug(sm.getString("contextConfig.applicationStart",
+                    source.getSystemId()));
+        }
+            
+        try {
+            digester.parse(source);
 
-                if (handler.getWarnings().size() > 0 ||
-                        handler.getErrors().size() > 0) {
-                    ok = false;
-                    handler.logFindings(log, source.getSystemId());
-                }
-            } catch (SAXParseException e) {
-                log.error(sm.getString("contextConfig.applicationParse",
-                        source.getSystemId()), e);
-                log.error(sm.getString("contextConfig.applicationPosition",
-                                 "" + e.getLineNumber(),
-                                 "" + e.getColumnNumber()));
+            if (handler.getWarnings().size() > 0 ||
+                    handler.getErrors().size() > 0) {
                 ok = false;
-            } catch (Exception e) {
-                log.error(sm.getString("contextConfig.applicationParse",
-                        source.getSystemId()), e);
-                ok = false;
-            } finally {
-                digester.reset();
-                ruleSet.recycle();
+                handler.logFindings(log, source.getSystemId());
             }
+        } catch (SAXParseException e) {
+            log.error(sm.getString("contextConfig.applicationParse",
+                    source.getSystemId()), e);
+            log.error(sm.getString("contextConfig.applicationPosition",
+                             "" + e.getLineNumber(),
+                             "" + e.getColumnNumber()));
+            ok = false;
+        } catch (Exception e) {
+            log.error(sm.getString("contextConfig.applicationParse",
+                    source.getSystemId()), e);
+            ok = false;
+        } finally {
+            digester.reset();
+            ruleSet.recycle();
         }
     }
 
@@ -2234,7 +2156,8 @@ public class ContextConfig
 
     /**
      * process filter annotation and merge with existing one!
-     * FIXME: refactoring method to long and has redundant subroutines with processAnnotationWebServlet!
+     * FIXME: refactoring method too long and has redundant subroutines with
+     *        processAnnotationWebServlet!
      * @param className
      * @param ae
      * @param fragment

Modified: tomcat/tc7.0.x/trunk/java/org/apache/catalina/startup/HostConfig.java
URL: http://svn.apache.org/viewvc/tomcat/tc7.0.x/trunk/java/org/apache/catalina/startup/HostConfig.java?rev=1190190&r1=1190189&r2=1190190&view=diff
==============================================================================
--- tomcat/tc7.0.x/trunk/java/org/apache/catalina/startup/HostConfig.java (original)
+++ tomcat/tc7.0.x/trunk/java/org/apache/catalina/startup/HostConfig.java Fri Oct 28 07:59:16 2011
@@ -14,8 +14,6 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
-
 package org.apache.catalina.startup;
 
 
@@ -33,7 +31,11 @@ import java.util.HashSet;
 import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Locale;
+import java.util.Map;
 import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Future;
 import java.util.jar.JarEntry;
 import java.util.jar.JarFile;
 import java.util.regex.Matcher;
@@ -144,8 +146,8 @@ public class HostConfig
     /**
      * Map of deployed applications.
      */
-    protected HashMap<String, DeployedApplication> deployed =
-        new HashMap<String, DeployedApplication>();
+    protected Map<String, DeployedApplication> deployed =
+        new ConcurrentHashMap<String, DeployedApplication>();
 
     
     /**
@@ -519,6 +521,10 @@ public class HostConfig
         ContextName cn = new ContextName(name);
         String baseName = cn.getBaseName();
         
+        if (deploymentExists(baseName)) {
+            return;
+        }
+
         // Deploy XML descriptors from configBase
         File xml = new File(configBase, baseName + ".xml");
         if (xml.exists())
@@ -542,17 +548,29 @@ public class HostConfig
         if (files == null)
             return;
         
+        ExecutorService es = host.getStartStopExecutor();
+        List<Future<?>> results = new ArrayList<Future<?>>();
+
         for (int i = 0; i < files.length; i++) {
             File contextXml = new File(configBase, files[i]);
 
             if (files[i].toLowerCase(Locale.ENGLISH).endsWith(".xml")) {
                 ContextName cn = new ContextName(files[i]);
-                String name = cn.getName();
 
-                if (isServiced(name))
+                if (isServiced(cn.getName()) || deploymentExists(cn.getName()))
                     continue;
                 
-                deployDescriptor(cn, contextXml);
+                results.add(
+                        es.submit(new DeployDescriptor(this, cn, contextXml)));
+            }
+        }
+
+        for (Future<?> result : results) {
+            try {
+                result.get();
+            } catch (Exception e) {
+                log.error(sm.getString(
+                        "hostConfig.deployDescriptor.threaded.error"), e);
             }
         }
     }
@@ -563,9 +581,6 @@ public class HostConfig
      * @param contextXml
      */
     protected void deployDescriptor(ContextName cn, File contextXml) {
-        if (deploymentExists(cn.getName())) {
-            return;
-        }
         
         DeployedApplication deployedApp = new DeployedApplication(cn.getName());
 
@@ -692,6 +707,9 @@ public class HostConfig
         if (files == null)
             return;
         
+        ExecutorService es = host.getStartStopExecutor();
+        List<Future<?>> results = new ArrayList<Future<?>>();
+
         for (int i = 0; i < files.length; i++) {
             
             if (files[i].equalsIgnoreCase("META-INF"))
@@ -712,10 +730,19 @@ public class HostConfig
                     continue;
                 }
 
-                if (isServiced(cn.getName()))
+                if (isServiced(cn.getName()) || deploymentExists(cn.getName()))
                     continue;
                 
-                deployWAR(cn, war);
+                results.add(es.submit(new DeployWar(this, cn, war)));
+            }
+        }
+
+        for (Future<?> result : results) {
+            try {
+                result.get();
+            } catch (Exception e) {
+                log.error(sm.getString(
+                        "hostConfig.deployWar.threaded.error"), e);
             }
         }
     }
@@ -763,9 +790,6 @@ public class HostConfig
      */
     protected void deployWAR(ContextName cn, File war) {
         
-        if (deploymentExists(cn.getName()))
-            return;
-        
         // Checking for a nested /META-INF/context.xml
         JarFile jar = null;
         JarEntry entry = null;
@@ -957,6 +981,9 @@ public class HostConfig
         if (files == null)
             return;
         
+        ExecutorService es = host.getStartStopExecutor();
+        List<Future<?>> results = new ArrayList<Future<?>>();
+
         for (int i = 0; i < files.length; i++) {
 
             if (files[i].equalsIgnoreCase("META-INF"))
@@ -967,10 +994,19 @@ public class HostConfig
             if (dir.isDirectory()) {
                 ContextName cn = new ContextName(files[i]);
 
-                if (isServiced(cn.getName()))
+                if (isServiced(cn.getName()) || deploymentExists(cn.getName()))
                     continue;
 
-                deployDirectory(cn, dir);
+                results.add(es.submit(new DeployDirectory(this, cn, dir)));
+            }
+        }
+
+        for (Future<?> result : results) {
+            try {
+                result.get();
+            } catch (Exception e) {
+                log.error(sm.getString(
+                        "hostConfig.deployDir.threaded.error"), e);
             }
         }
     }
@@ -982,9 +1018,6 @@ public class HostConfig
      */
     protected void deployDirectory(ContextName cn, File dir) {
         
-        if (deploymentExists(cn.getName()))
-            return;
-
         DeployedApplication deployedApp = new DeployedApplication(cn.getName());
 
         // Deploy the application in this directory
@@ -1473,7 +1506,61 @@ public class HostConfig
         /**
          * Instant where the application was last put in service.
          */
-     public long timestamp = System.currentTimeMillis();
+        public long timestamp = System.currentTimeMillis();
+    }
+
+    private static class DeployDescriptor implements Runnable {
+
+        private HostConfig config;
+        private ContextName cn;
+        private File descriptor;
+
+        public DeployDescriptor(HostConfig config, ContextName cn,
+                File descriptor) {
+            this.config = config;
+            this.cn = cn;
+            this.descriptor= descriptor;
+        }
+
+        @Override
+        public void run() {
+            config.deployDescriptor(cn, descriptor);
+        }
+    }
+
+    private static class DeployWar implements Runnable {
+
+        private HostConfig config;
+        private ContextName cn;
+        private File war;
+
+        public DeployWar(HostConfig config, ContextName cn, File war) {
+            this.config = config;
+            this.cn = cn;
+            this.war = war;
+        }
+
+        @Override
+        public void run() {
+            config.deployWAR(cn, war);
+        }
     }
 
+    private static class DeployDirectory implements Runnable {
+
+        private HostConfig config;
+        private ContextName cn;
+        private File dir;
+
+        public DeployDirectory(HostConfig config, ContextName cn, File dir) {
+            this.config = config;
+            this.cn = cn;
+            this.dir = dir;
+        }
+
+        @Override
+        public void run() {
+            config.deployDirectory(cn, dir);
+        }
+    }
 }

Modified: tomcat/tc7.0.x/trunk/java/org/apache/catalina/startup/LocalStrings.properties
URL: http://svn.apache.org/viewvc/tomcat/tc7.0.x/trunk/java/org/apache/catalina/startup/LocalStrings.properties?rev=1190190&r1=1190189&r2=1190190&view=diff
==============================================================================
--- tomcat/tc7.0.x/trunk/java/org/apache/catalina/startup/LocalStrings.properties (original)
+++ tomcat/tc7.0.x/trunk/java/org/apache/catalina/startup/LocalStrings.properties Fri Oct 28 07:59:16 2011
@@ -83,11 +83,14 @@ hostConfig.createDirs=Unable to create d
 hostConfig.deploy=Deploying web application directory {0}
 hostConfig.deployDescriptor=Deploying configuration descriptor {0}
 hostConfig.deployDescriptor.error=Error deploying configuration descriptor {0}
+hostConfig.deployDescriptor.threaded.error=Error waiting for multi-thread deployment of context descriptors to complete
 hostConfig.deployDescriptor.localDocBaseSpecified=A docBase {0} inside the host appBase has been specified, and will be ignored
 hostConfig.deployDir=Deploying web application directory {0}
 hostConfig.deployDir.error=Error deploying web application directory {0}
+hostConfig.deployDir.threaded.error=Error waiting for multi-thread deployment of directories to completehostConfig.deployWar=Deploying web application archive {0}
 hostConfig.deployWar=Deploying web application archive {0}
 hostConfig.deployWar.error=Error deploying web application archive {0}
+hostConfig.deployWar.threaded.error=Error waiting for multi-thread deployment of WAR files to complete
 hostConfig.deploy.error=Exception while deploying web application directory {0}
 hostConfig.deploying=Deploying discovered web applications
 hostConfig.expand=Expanding web application archive {0}

Modified: tomcat/tc7.0.x/trunk/java/org/apache/coyote/AbstractProtocol.java
URL: http://svn.apache.org/viewvc/tomcat/tc7.0.x/trunk/java/org/apache/coyote/AbstractProtocol.java?rev=1190190&r1=1190189&r2=1190190&view=diff
==============================================================================
--- tomcat/tc7.0.x/trunk/java/org/apache/coyote/AbstractProtocol.java (original)
+++ tomcat/tc7.0.x/trunk/java/org/apache/coyote/AbstractProtocol.java Fri Oct 28 07:59:16 2011
@@ -493,6 +493,12 @@ public abstract class AbstractProtocol i
                 SocketStatus status) {
             P processor = connections.remove(socket.getSocket());
 
+            if (getLog().isDebugEnabled()) {
+                getLog().debug("process() entry " +
+                        "Socket: [" + logHashcode(socket.getSocket()) + "], " +
+                        "Processor [" + logHashcode(processor) + "]");
+            }
+
             socket.setAsync(false);
 
             try {
@@ -503,20 +509,51 @@ public abstract class AbstractProtocol i
                     processor = createProcessor();
                 }
 
+                if (getLog().isDebugEnabled()) {
+                    getLog().debug("process() gotProcessor " +
+                            "Socket: [" + logHashcode(socket.getSocket()) + "], " +
+                            "Processor [" + logHashcode(processor) + "]");
+                }
+
                 initSsl(socket, processor);
 
                 SocketState state = SocketState.CLOSED;
                 do {
                     if (processor.isAsync() || state == SocketState.ASYNC_END) {
                         state = processor.asyncDispatch(status);
+                        if (getLog().isDebugEnabled()) {
+                            getLog().debug("process() asyncDispatch " +
+                                    "Socket: [" + logHashcode(socket.getSocket()) + "], " +
+                                    "Processor: [" + logHashcode(processor) + "], " +
+                                    "State: [" + state.toString() + "]");
+                        }
                     } else if (processor.isComet()) {
                         state = processor.event(status);
+                        if (getLog().isDebugEnabled()) {
+                            getLog().debug("process() event " +
+                                    "Socket: [" + logHashcode(socket.getSocket()) + "], " +
+                                    "Processor: [" + logHashcode(processor) + "], " +
+                                    "State: [" + state.toString() + "]");
+                        }
                     } else {
                         state = processor.process(socket);
+                        if (getLog().isDebugEnabled()) {
+                            getLog().debug("process() process " +
+                                    "Socket: [" + logHashcode(socket.getSocket()) + "], " +
+                                    "Processor: [" + logHashcode(processor) + "], " +
+                                    "State: [" + state.toString() + "]");
+                        }
                     }
     
                     if (state != SocketState.CLOSED && processor.isAsync()) {
                         state = processor.asyncPostProcess();
+                        if (getLog().isDebugEnabled()) {
+                            getLog().debug("process() asyncPostProcess " +
+                                    "Socket: [" + logHashcode(socket.getSocket()) + "], " +
+                                    "Processor: [" + logHashcode(processor) + "], " +
+                                    "State: [" + state.toString() + "]");
+                        }
+
                     }
                 } while (state == SocketState.ASYNC_END);
 
@@ -562,6 +599,14 @@ public abstract class AbstractProtocol i
             return SocketState.CLOSED;
         }
         
+        private String logHashcode (Object o) {
+            if (o == null) {
+                return "null";
+            } else {
+                return Integer.toString(o.hashCode());
+            }
+        }
+
         protected abstract P createProcessor();
         protected abstract void initSsl(SocketWrapper<S> socket, P processor);
         protected abstract void longPoll(SocketWrapper<S> socket, P processor);

Modified: tomcat/tc7.0.x/trunk/webapps/docs/config/engine.xml
URL: http://svn.apache.org/viewvc/tomcat/tc7.0.x/trunk/webapps/docs/config/engine.xml?rev=1190190&r1=1190189&r2=1190190&view=diff
==============================================================================
--- tomcat/tc7.0.x/trunk/webapps/docs/config/engine.xml (original)
+++ tomcat/tc7.0.x/trunk/webapps/docs/config/engine.xml Fri Oct 28 07:59:16 2011
@@ -102,6 +102,17 @@
         name.</em></p>
       </attribute>
 
+      <attribute name="startStopThreads" required="false">
+        <p>The number of threads this <strong>Engine</strong> will use to start
+        child <a href="host.html">Host</a> elements in parallel. The special
+        value of 0 will result in the value of
+        <code>Runtime.getRuntime().availableProcessors()</code> being used.
+        Negative values will result in
+        <code>Runtime.getRuntime().availableProcessors() + value</code> being
+        used unless this is less than 1 in which case 1 thread will be used. If
+        not specified, the default value of 1 will be used. </p>
+      </attribute>
+
     </attributes>
 
   </subsection>

Modified: tomcat/tc7.0.x/trunk/webapps/docs/config/host.xml
URL: http://svn.apache.org/viewvc/tomcat/tc7.0.x/trunk/webapps/docs/config/host.xml?rev=1190190&r1=1190189&r2=1190190&view=diff
==============================================================================
--- tomcat/tc7.0.x/trunk/webapps/docs/config/host.xml (original)
+++ tomcat/tc7.0.x/trunk/webapps/docs/config/host.xml Fri Oct 28 07:59:16 2011
@@ -188,6 +188,19 @@
         virtual host.</p>
       </attribute>
 
+      <attribute name="startStopThreads" required="false">
+        <p>The number of threads this <strong>Host</strong> will use to start
+        child <a href="context.html">Context</a> elements in parallel. The same
+        thread pool will be used to deploy new
+        <a href="context.html">Context</a>s if automatic deployment is being
+        used. The special value of 0 will result in the value of
+        <code>Runtime.getRuntime().availableProcessors()</code> being used.
+        Negative values will result in
+        <code>Runtime.getRuntime().availableProcessors() + value</code> being
+        used unless this is less than 1 in which case 1 thread will be used. If
+        not specified, the default value of 1 will be used.</p>
+      </attribute>
+
     </attributes>
 
   </subsection>



---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org