Author: markt
Date: Mon Jul  2 19:47:37 2018
New Revision: 1834877

URL: http://svn.apache.org/viewvc?rev=1834877&view=rev
Log:
Make the Java file generation process multi-threaded. By default, one thread 
will be used per core.
Based on a patch by Dan Fabulich.

Modified:
    tomcat/trunk/java/org/apache/jasper/JspC.java
    tomcat/trunk/java/org/apache/jasper/resources/LocalStrings.properties
    tomcat/trunk/webapps/docs/changelog.xml

Modified: tomcat/trunk/java/org/apache/jasper/JspC.java
URL: 
http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/jasper/JspC.java?rev=1834877&r1=1834876&r2=1834877&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/jasper/JspC.java (original)
+++ tomcat/trunk/java/org/apache/jasper/JspC.java Mon Jul  2 19:47:37 2018
@@ -40,6 +40,11 @@ import java.util.Set;
 import java.util.Stack;
 import java.util.StringTokenizer;
 import java.util.Vector;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ExecutorCompletionService;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
 
 import javax.servlet.jsp.JspFactory;
 import javax.servlet.jsp.tagext.TagLibraryInfo;
@@ -140,6 +145,7 @@ public class JspC extends Task implement
     protected static final String SWITCH_NO_STRICT_QUOTE_ESCAPING = 
"-no-strictQuoteEscaping";
     protected static final String SWITCH_QUOTE_ATTRIBUTE_EL = 
"-quoteAttributeEL";
     protected static final String SWITCH_NO_QUOTE_ATTRIBUTE_EL = 
"-no-quoteAttributeEL";
+    protected static final String SWITCH_THREAD_COUNT = "-threadCount";
     protected static final String SHOW_SUCCESS ="-s";
     protected static final String LIST_ERRORS = "-l";
     protected static final int INC_WEBXML = 10;
@@ -235,6 +241,9 @@ public class JspC extends Task implement
      */
     protected String javaEncoding = "UTF-8";
 
+    /** The number of threads to use; default is one per core */
+    protected int threadCount = Runtime.getRuntime().availableProcessors();
+
     // Generation of web.xml fragments
     protected String webxmlFile;
     protected int webxmlLevel;
@@ -414,6 +423,8 @@ public class JspC extends Task implement
                 setQuoteAttributeEL(true);
             } else if (tok.equals(SWITCH_NO_QUOTE_ATTRIBUTE_EL)) {
                 setQuoteAttributeEL(false);
+            } else if (tok.equals(SWITCH_THREAD_COUNT)) {
+                setThreadCount(nextArg());
             } else {
                 if (tok.startsWith("-")) {
                     throw new JasperException("Unrecognized option: " + tok +
@@ -970,6 +981,31 @@ public class JspC extends Task implement
         return quoteAttributeEL;
     }
 
+    public int getThreadCount() {
+        return threadCount;
+    }
+
+    public void setThreadCount(String threadCount) {
+        if (threadCount == null) {
+            return;
+        }
+        int newThreadCount;
+        try {
+            if (threadCount.endsWith("C")) {
+                double factor = Double.parseDouble(threadCount.substring(0, 
threadCount.length() - 1));
+                newThreadCount = (int) (factor * 
Runtime.getRuntime().availableProcessors());
+            } else {
+                newThreadCount = Integer.parseInt(threadCount);
+            }
+        } catch (NumberFormatException e) {
+            throw new BuildException("Couldn't parse thread count: " + 
threadCount);
+        }
+        if (newThreadCount < 1) {
+            throw new BuildException("There must be at least one thread: " + 
newThreadCount);
+        }
+        this.threadCount = newThreadCount;
+    }
+
     public void setListErrors( boolean b ) {
         listErrors = b;
     }
@@ -1273,9 +1309,8 @@ public class JspC extends Task implement
         return result.toString();
     }
 
-    protected void processFile(String file)
-        throws JasperException
-    {
+    protected void processFile(String file) throws JasperException {
+
         if (log.isDebugEnabled()) {
             log.debug("Processing file: " + file);
         }
@@ -1406,29 +1441,25 @@ public class JspC extends Task implement
 
         try {
             if (uriRoot == null) {
-                if( pages.size() == 0 ) {
-                    throw new JasperException(
-                        Localizer.getMessage("jsp.error.jspc.missingTarget"));
+                if (pages.size() == 0) {
+                    throw new 
JasperException(Localizer.getMessage("jsp.error.jspc.missingTarget"));
                 }
-                String firstJsp = pages.get( 0 );
-                File firstJspF = new File( firstJsp );
+                String firstJsp = pages.get(0);
+                File firstJspF = new File(firstJsp);
                 if (!firstJspF.exists()) {
-                    throw new JasperException(
-                        Localizer.getMessage("jspc.error.fileDoesNotExist",
-                                             firstJsp));
+                    throw new JasperException(Localizer.getMessage(
+                            "jspc.error.fileDoesNotExist", firstJsp));
                 }
-                locateUriRoot( firstJspF );
+                locateUriRoot(firstJspF);
             }
 
             if (uriRoot == null) {
-                throw new JasperException(
-                    Localizer.getMessage("jsp.error.jspc.no_uriroot"));
+                throw new 
JasperException(Localizer.getMessage("jsp.error.jspc.no_uriroot"));
             }
 
             File uriRootF = new File(uriRoot);
             if (!uriRootF.isDirectory()) {
-                throw new JasperException(
-                    Localizer.getMessage("jsp.error.jspc.uriroot_not_dir"));
+                throw new 
JasperException(Localizer.getMessage("jsp.error.jspc.uriroot_not_dir"));
             }
 
             if (loader == null) {
@@ -1448,6 +1479,10 @@ public class JspC extends Task implement
             int errorCount = 0;
             long start = System.currentTimeMillis();
 
+            ExecutorService threadPool = 
Executors.newFixedThreadPool(threadCount);
+            ExecutorCompletionService<Void> service = new 
ExecutorCompletionService<>(threadPool);
+            int pageCount = pages.size();
+
             for (String nextjsp : pages) {
                 File fjsp = new File(nextjsp);
                 if (!fjsp.isAbsolute()) {
@@ -1455,9 +1490,8 @@ public class JspC extends Task implement
                 }
                 if (!fjsp.exists()) {
                     if (log.isWarnEnabled()) {
-                        log.warn
-                            (Localizer.getMessage
-                             ("jspc.error.fileDoesNotExist", fjsp.toString()));
+                        log.warn(Localizer.getMessage(
+                                "jspc.error.fileDoesNotExist", 
fjsp.toString()));
                     }
                     continue;
                 }
@@ -1468,19 +1502,38 @@ public class JspC extends Task implement
                 if (nextjsp.startsWith("." + File.separatorChar)) {
                     nextjsp = nextjsp.substring(2);
                 }
+                service.submit(new ProcessFile(nextjsp));
+            }
+            JasperException reportableError = null;
+            for (int i = 0; i < pageCount; i++) {
                 try {
-                    processFile(nextjsp);
-                } catch (JasperException e) {
+                    service.take().get();
+                } catch (ExecutionException e) {
                     if (failFast) {
-                        throw e;
+                        // Generation is not interruptible so any tasks that
+                        // have started will complete.
+                        List<Runnable> notExecuted = threadPool.shutdownNow();
+                        i += notExecuted.size();
+                        Throwable t = e.getCause();
+                        if (t instanceof JasperException) {
+                            reportableError = (JasperException) t;
+                        } else {
+                            reportableError = new JasperException(t);
+                        }
+                    } else {
+                        errorCount++;
+                        log.error(e.getMessage());
                     }
-                    errorCount++;
-                    log.error(nextjsp + ":" + e.getMessage());
+                } catch (InterruptedException e) {
+                    // Ignore
                 }
             }
+            if (reportableError != null) {
+                throw reportableError;
+            }
 
             long time = System.currentTimeMillis() - start;
-            String msg = Localizer.getMessage("jspc.compilation.result",
+            String msg = Localizer.getMessage("jspc.generation.result",
                     Integer.toString(errorCount), Long.toString(time));
             if (failOnError && errorCount > 0) {
                 System.out.println("Error Count: " + errorCount);
@@ -1801,4 +1854,19 @@ public class JspC extends Task implement
             throw ex;
         }
     }
+
+
+    private class ProcessFile implements Callable<Void> {
+        private final String file;
+
+        private ProcessFile(String file) {
+            this.file = file;
+        }
+
+        @Override
+        public Void call() throws Exception {
+            processFile(file);
+            return null;
+        }
+    }
 }

Modified: tomcat/trunk/java/org/apache/jasper/resources/LocalStrings.properties
URL: 
http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/jasper/resources/LocalStrings.properties?rev=1834877&r1=1834876&r2=1834877&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/jasper/resources/LocalStrings.properties 
(original)
+++ tomcat/trunk/java/org/apache/jasper/resources/LocalStrings.properties Mon 
Jul  2 19:47:37 2018
@@ -153,7 +153,7 @@ jsp.warning.compiler.javafile.delete.fai
 jsp.error.jspc.uriroot_not_dir=The -uriroot option must specify a pre-existing 
directory
 jsp.error.jspc.missingTarget=Missing target: Must specify -webapp or -uriroot, 
or one or more JSP pages
 jsp.error.jspc.no_uriroot=The uriroot is not specified and cannot be located 
with the specified JSP file(s)
-jspc.compilation.result=Compilation completed with [{0}] errors in [{1}] 
milliseconds
+jspc.generation.result=Generation completed with [{0}] errors in [{1}] 
milliseconds
 jspc.implicit.uriRoot=uriRoot implicitly set to [{0}]
 jspc.usage=Usage: jspc <options> [--] <jsp files>\n\
 where jsp files is\n\
@@ -191,6 +191,8 @@ where options include:\n\
 \    -javaEncoding <enc>   Set the encoding charset for Java classes (default 
UTF-8)\n\
 \    -source <version>     Set the -source argument to the compiler (default 
1.8)\n\
 \    -target <version>     Set the -target argument to the compiler (default 
1.8)\n\
+\    -threadCount <count>  Number of threads to use for compilation.\n\
+\                          (\"2.0C\" means two threads per core)\n\
 
 jspc.webxml.header=<?xml version="1.0" encoding="{0}"?>\n\
 <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee";

Modified: tomcat/trunk/webapps/docs/changelog.xml
URL: 
http://svn.apache.org/viewvc/tomcat/trunk/webapps/docs/changelog.xml?rev=1834877&r1=1834876&r2=1834877&view=diff
==============================================================================
--- tomcat/trunk/webapps/docs/changelog.xml (original)
+++ tomcat/trunk/webapps/docs/changelog.xml Mon Jul  2 19:47:37 2018
@@ -81,6 +81,15 @@
       </update>
     </changelog>
   </subsection>
+  <subsection name="Jasper">
+    <changelog>
+      <add>
+        <bug>53492</bug>: Make the Java file generation process multi-threaded.
+        By default, one thread will be used per core. Based on a patch by Dan
+        Fabulich. (markt)
+      </add>
+    </changelog>
+  </subsection>
   <subsection name="Other">
     <changelog>
       <update>



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

Reply via email to