Author: markt
Date: Thu Oct 13 22:28:22 2011
New Revision: 1183142

URL: http://svn.apache.org/viewvc?rev=1183142&view=rev
Log:
Cache the result of parsing global and host defaults for web.xml to speed up 
web application start.
This change reduces applciation start time by ~15% with trunk and the TCK web 
apps

Modified:
    tomcat/trunk/java/org/apache/catalina/startup/Constants.java
    tomcat/trunk/java/org/apache/catalina/startup/ContextConfig.java
    tomcat/trunk/java/org/apache/catalina/startup/LocalStrings.properties

Modified: tomcat/trunk/java/org/apache/catalina/startup/Constants.java
URL: 
http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/startup/Constants.java?rev=1183142&r1=1183141&r2=1183142&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/catalina/startup/Constants.java (original)
+++ tomcat/trunk/java/org/apache/catalina/startup/Constants.java Thu Oct 13 
22:28:22 2011
@@ -34,7 +34,7 @@ public final class Constants {
     public static final String ApplicationContextXml = "META-INF/context.xml";
     public static final String ApplicationWebXml = "/WEB-INF/web.xml";
     public static final String DefaultContextXml = "conf/context.xml";
-    public static final String DefaultWebXml = "conf/web.xml";
+    public static final String DefaultWebXml = "web.xml";
     public static final String HostContextXml = "context.xml.default";
     public static final String HostWebXml = "web.xml.default";
 

Modified: tomcat/trunk/java/org/apache/catalina/startup/ContextConfig.java
URL: 
http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/startup/ContextConfig.java?rev=1183142&r1=1183141&r2=1183142&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/catalina/startup/ContextConfig.java (original)
+++ tomcat/trunk/java/org/apache/catalina/startup/ContextConfig.java Thu Oct 13 
22:28:22 2011
@@ -43,6 +43,7 @@ import java.util.Locale;
 import java.util.Map;
 import java.util.Properties;
 import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
 
 import javax.servlet.ServletContainerInitializer;
 import javax.servlet.ServletContext;
@@ -172,6 +173,13 @@ public class ContextConfig
     protected static long deploymentCount = 0L;
 
 
+    /**
+     * Cache of default web.xml fragments per Host
+     */
+    protected static final Map<Host,DefaultWebXmlCacheEntry> hostWebXmlCache =
+        new ConcurrentHashMap<Host,DefaultWebXmlCacheEntry>();
+
+
     // ----------------------------------------------------- Instance Variables
     /**
      * Custom mappings of login methods to authenticators
@@ -1210,7 +1218,6 @@ public class ContextConfig
      * web.xml file.
      */
     protected void webConfig() {
-        WebXml webXml = createWebXml();
         /* Anything and everything can override the global and host defaults.
          * This is implemented in two parts
          * - Handle as a web fragment that gets added after everything else so
@@ -1218,34 +1225,11 @@ public class ContextConfig
          * - Mark Servlets as overridable so SCI configuration can replace
          *   configuration from the defaults
          */ 
-        WebXml webXmlDefaultFragment = createWebXml();
-        webXmlDefaultFragment.setOverridable(true);
-        // Set to distributable else every app will be prevented from being
-        // distributable when the default fragment is merged with the main
-        // web.xml
-        webXmlDefaultFragment.setDistributable(true);
-        // When merging, the default welcome files are only used if the app has
-        // not defined any welcomes files.
-        webXmlDefaultFragment.setAlwaysAddWelcomeFiles(false);
-
-        // Parse global web.xml if present
-        InputSource globalWebXml = getGlobalWebXmlSource();
-        if (globalWebXml == null) {
-            // This is unusual enough to log
-            log.info(sm.getString("contextConfig.defaultMissing"));
-        } else {
-            parseWebXml(globalWebXml, webXmlDefaultFragment, false);
-        }
-
-        // Parse host level web.xml if present
-        // Additive apart from welcome pages
-        webXmlDefaultFragment.setReplaceWelcomeFiles(true);
-        InputSource hostWebXml = getHostWebXmlSource();
-        parseWebXml(hostWebXml, webXmlDefaultFragment, false);
-        
         Set<WebXml> defaults = new HashSet<WebXml>();
-        defaults.add(webXmlDefaultFragment);
-        
+        defaults.add(getDefaultWebXmlFragment());
+
+        WebXml webXml = createWebXml();
+
         // Parse context level web.xml
         InputSource contextWebXml = getContextWebXmlSource();
         parseWebXml(contextWebXml, webXml, false);
@@ -1376,6 +1360,98 @@ public class ContextConfig
         }
     }
 
+    private WebXml getDefaultWebXmlFragment() {
+
+        // Host should never be null
+        Host host = (Host) context.getParent();
+
+        DefaultWebXmlCacheEntry entry = hostWebXmlCache.get(host);
+        
+        File globalWebXml = getGlobalWebXml();
+        File hostWebXml = getHostWebXml();
+        
+        long globalTimeStamp = 0;
+        long hostTimeStamp = 0;
+        
+        if (globalWebXml != null) {
+            globalTimeStamp = globalWebXml.lastModified();
+        }
+        
+        if (hostWebXml != null) {
+            hostTimeStamp = hostWebXml.lastModified();
+        }
+        
+        if (entry != null && entry.getGlobalTimeStamp() == globalTimeStamp &&
+                entry.getHostTimeStamp() == hostTimeStamp) {
+            addWatchedResource(globalWebXml);
+            addWatchedResource(hostWebXml);
+            return entry.getWebXml();
+        }
+        
+        // Parsing global web.xml is relatively expensive. Use a sync block to
+        // make sure it only happens once
+        synchronized (host) {
+            entry = hostWebXmlCache.get(host);
+            if (entry != null && entry.getGlobalTimeStamp() == globalTimeStamp 
&&
+                    entry.getHostTimeStamp() == hostTimeStamp) {
+                addWatchedResource(globalWebXml);
+                addWatchedResource(hostWebXml);
+                return entry.getWebXml();
+            }
+
+            WebXml webXmlDefaultFragment = createWebXml();
+            webXmlDefaultFragment.setOverridable(true);
+            // Set to distributable else every app will be prevented from being
+            // distributable when the default fragment is merged with the main
+            // web.xml
+            webXmlDefaultFragment.setDistributable(true);
+            // When merging, the default welcome files are only used if the 
app has
+            // not defined any welcomes files.
+            webXmlDefaultFragment.setAlwaysAddWelcomeFiles(false);
+
+            // Parse global web.xml if present
+            if (globalWebXml == null || !globalWebXml.isFile()) {
+                // This is unusual enough to log
+                log.info(sm.getString("contextConfig.defaultMissing"));
+                globalTimeStamp = 0;
+            } else {
+                parseWebXml(getWebXmlSource(globalWebXml.getName(),
+                                            globalWebXml.getParent()),
+                            webXmlDefaultFragment,
+                            false);
+                globalTimeStamp = globalWebXml.lastModified();
+            }
+            
+            // Parse host level web.xml if present
+            // Additive apart from welcome pages
+            webXmlDefaultFragment.setReplaceWelcomeFiles(true);
+            
+            if (hostWebXml == null || !hostWebXml.isFile()) {
+                hostTimeStamp = 0;
+            } else {
+                parseWebXml(getWebXmlSource(hostWebXml.getName(),
+                                hostWebXml.getParent()),
+                                webXmlDefaultFragment,
+                                false);
+                hostTimeStamp = hostWebXml.lastModified();
+            }
+            
+            entry = new DefaultWebXmlCacheEntry(webXmlDefaultFragment,
+                    globalTimeStamp, hostTimeStamp);
+            
+            hostWebXmlCache.put(host, entry);
+
+            addWatchedResource(globalWebXml);
+            addWatchedResource(hostWebXml);
+            return webXmlDefaultFragment;
+        }
+    }
+
+    private void addWatchedResource(File f) {
+        if (f != null) {
+            context.addWatchedResource(f.getAbsolutePath());
+        }
+    }
     private void convertJsps(WebXml webXml) {
         Map<String,String> jspInitParams;
         ServletDef jspServlet = webXml.getServlets().get("jsp");
@@ -1574,10 +1650,9 @@ public class ContextConfig
     
     
     /**
-     * Identify the default web.xml to be used and obtain an input source for
-     * it.
+     * Identify the default web.xml to be used.
      */
-    protected InputSource getGlobalWebXmlSource() {
+    protected File getGlobalWebXml() {
         // Is a default web.xml specified for the Context?
         if (defaultWebXml == null && context instanceof StandardContext) {
             defaultWebXml = ((StandardContext) context).getDefaultWebXml();
@@ -1589,14 +1664,27 @@ public class ContextConfig
         if (Constants.NoDefaultWebXml.equals(defaultWebXml)) {
             return null;
         }
-        return getWebXmlSource(defaultWebXml, getBaseDir());
+
+        // In an embedded environment, configBase might not be set
+        File configBase = getConfigBase();
+        if (configBase == null)
+            return null;
+
+        String basePath = null;
+        try {
+            basePath = configBase.getCanonicalPath();
+        } catch (IOException e) {
+            log.error(sm.getString("contextConfig.baseError"), e);
+            return null;
+        }
+
+        return new File(basePath, defaultWebXml);
     }
     
     /**
-     * Identify the host web.xml to be used and obtain an input source for
-     * it.
+     * Identify the host web.xml to be used.
      */
-    protected InputSource getHostWebXmlSource() {
+    protected File getHostWebXml() {
         String resourceName = getHostConfigPath(Constants.HostWebXml);
         
         // In an embedded environment, configBase might not be set
@@ -1608,11 +1696,11 @@ public class ContextConfig
         try {
             basePath = configBase.getCanonicalPath();
         } catch (IOException e) {
-            log.error(sm.getString("contectConfig.baseError"), e);
+            log.error(sm.getString("contextConfig.baseError"), e);
             return null;
         }
 
-        return getWebXmlSource(resourceName, basePath);
+        return new File(basePath, resourceName);
     }
     
     /**
@@ -1693,7 +1781,6 @@ public class ContextConfig
             } else {
                 source = new InputSource("file://" + file.getAbsolutePath());
                 stream = new FileInputStream(file);
-                context.addWatchedResource(file.getAbsolutePath());
             }
 
             if (stream != null && source != null) {
@@ -2419,4 +2506,29 @@ public class ContextConfig
             return fragments;
         }
     }
+
+    private static class DefaultWebXmlCacheEntry {
+        private final WebXml webXml;
+        private final long globalTimeStamp;
+        private final long hostTimeStamp;
+
+        public DefaultWebXmlCacheEntry(WebXml webXml, long globalTimeStamp,
+                long hostTimeStamp) {
+            this.webXml = webXml;
+            this.globalTimeStamp = globalTimeStamp;
+            this.hostTimeStamp = hostTimeStamp;
+        }
+
+        public WebXml getWebXml() {
+            return webXml;
+        }
+
+        public long getGlobalTimeStamp() {
+            return globalTimeStamp;
+        }
+
+        public long getHostTimeStamp() {
+            return hostTimeStamp;
+        }
+    }
 }

Modified: tomcat/trunk/java/org/apache/catalina/startup/LocalStrings.properties
URL: 
http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/startup/LocalStrings.properties?rev=1183142&r1=1183141&r2=1183142&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/catalina/startup/LocalStrings.properties 
(original)
+++ tomcat/trunk/java/org/apache/catalina/startup/LocalStrings.properties Thu 
Oct 13 22:28:22 2011
@@ -27,7 +27,7 @@ contextConfig.authenticatorInstantiate=C
 contextConfig.authenticatorMissing=Cannot configure an authenticator for 
method {0}
 contextConfig.authenticatorResources=Cannot load authenticators mapping list
 contextConfig.badUrl=Unable to process context descriptor [{0}]
-contectConfig.baseError=Unable to determine $CATALINA_BASE
+contextConfig.baseError=Unable to determine location of global configuration 
(usually $CATALINA_BASE/conf)
 contextConfig.cce=Lifecycle event data object {0} is not a Context
 contextConfig.contextClose=Error closing context.xml
 contextConfig.contextMissing=Missing context.xml: {0}



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

Reply via email to