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 2021/10/11 14:04:18 UTC

[tomcat] 01/02: Improve Connector stop performance - primarily to speed up tests

This is an automated email from the ASF dual-hosted git repository.

markt pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/tomcat.git

commit 3d60c5edc601bbb7f671d48bb4b7e77057dcaf48
Author: Mark Thomas <ma...@apache.org>
AuthorDate: Mon Oct 11 13:51:05 2021 +0100

    Improve Connector stop performance - primarily to speed up tests
---
 .../apache/tomcat/util/net/AbstractEndpoint.java   | 17 +++++++----
 java/org/apache/tomcat/util/net/Acceptor.java      | 35 ++++++++++++++++++----
 java/org/apache/tomcat/util/net/Nio2Endpoint.java  |  4 +--
 webapps/docs/changelog.xml                         |  8 +++++
 4 files changed, 50 insertions(+), 14 deletions(-)

diff --git a/java/org/apache/tomcat/util/net/AbstractEndpoint.java b/java/org/apache/tomcat/util/net/AbstractEndpoint.java
index 2938135..832119a 100644
--- a/java/org/apache/tomcat/util/net/AbstractEndpoint.java
+++ b/java/org/apache/tomcat/util/net/AbstractEndpoint.java
@@ -1032,12 +1032,17 @@ public abstract class AbstractEndpoint<S,U> {
                     getLog().debug("Socket unlock completed for:" + unlockAddress);
                 }
             }
-            // Wait for upto 1000ms acceptor threads to unlock
-            long waitLeft = 1000;
-            while (waitLeft > 0 &&
-                    acceptor.getState() == AcceptorState.RUNNING) {
-                Thread.sleep(5);
-                waitLeft -= 5;
+            // Wait for up to 1000ms acceptor threads to unlock. Particularly
+            // for the unit tests, we want to exit this loop as quickly as
+            // possible. However, we also don't want to trigger excessive CPU
+            // usage if the unlock takes longer than expected. Therefore, we
+            // initially wait for the unlock in a tight loop but if that takes
+            // more than 1ms we start using short sleeps to reduce CPU usage.
+            long startTime = System.nanoTime();
+            while (startTime + 1_000_000_000 > System.nanoTime() && acceptor.getState() == AcceptorState.RUNNING) {
+                if (startTime + 1_000_000 < System.nanoTime()) {
+                    Thread.sleep(1);
+                }
             }
         } catch(Throwable t) {
             ExceptionUtils.handleThrowable(t);
diff --git a/java/org/apache/tomcat/util/net/Acceptor.java b/java/org/apache/tomcat/util/net/Acceptor.java
index c526145..b1083b2 100644
--- a/java/org/apache/tomcat/util/net/Acceptor.java
+++ b/java/org/apache/tomcat/util/net/Acceptor.java
@@ -68,18 +68,41 @@ public class Acceptor<U> implements Runnable {
     public void run() {
 
         int errorDelay = 0;
+        long pauseStart = 0;
 
         try {
             // Loop until we receive a shutdown command
             while (!stopCalled) {
 
-                // Loop if endpoint is paused
+                // Loop if endpoint is paused.
+                // There are two likely scenarios here.
+                // The first scenario is that Tomcat is shutting down. In this
+                // case - and particularly for the unit tests - we want to exit
+                // this loop as quickly as possible. The second scenario is a
+                // genuine pause of the connector. In this case we want to avoid
+                // excessive CPU usage.
+                // Therefore, we start with a tight loop but if there isn't a
+                // rapid transition to stop then sleeps are introduced.
+                // < 1ms       - tight loop
+                // 1ms to 10ms - 1ms sleep
+                // > 10ms      - 10ms sleep
                 while (endpoint.isPaused() && !stopCalled) {
-                    state = AcceptorState.PAUSED;
-                    try {
-                        Thread.sleep(50);
-                    } catch (InterruptedException e) {
-                        // Ignore
+                    if (state != AcceptorState.PAUSED) {
+                        pauseStart = System.nanoTime();
+                        // Entered pause state
+                        state = AcceptorState.PAUSED;
+                    }
+                    if ((System.nanoTime() - pauseStart) > 1_000_000) {
+                        // Paused for more than 1ms
+                        try {
+                            if ((System.nanoTime() - pauseStart) > 10_000_000) {
+                                Thread.sleep(10);
+                            } else {
+                                Thread.sleep(1);
+                            }
+                        } catch (InterruptedException e) {
+                            // Ignore
+                        }
                     }
                 }
 
diff --git a/java/org/apache/tomcat/util/net/Nio2Endpoint.java b/java/org/apache/tomcat/util/net/Nio2Endpoint.java
index 2c56ddd..5fb0477 100644
--- a/java/org/apache/tomcat/util/net/Nio2Endpoint.java
+++ b/java/org/apache/tomcat/util/net/Nio2Endpoint.java
@@ -253,8 +253,8 @@ public class Nio2Endpoint extends AbstractJsseEndpoint<Nio2Channel,AsynchronousS
             try {
                 long timeout = getExecutorTerminationTimeoutMillis();
                 while (timeout > 0 && !allClosed) {
-                    timeout -= 100;
-                    Thread.sleep(100);
+                    timeout -= 1;
+                    Thread.sleep(1);
                 }
                 threadGroup.shutdownNow();
                 if (timeout > 0) {
diff --git a/webapps/docs/changelog.xml b/webapps/docs/changelog.xml
index 94bbb54..01da994 100644
--- a/webapps/docs/changelog.xml
+++ b/webapps/docs/changelog.xml
@@ -105,6 +105,14 @@
   issues do not "pop up" wrt. others).
 -->
 <section name="Tomcat 10.1.0-M7 (markt)" rtext="in development">
+  <subsection name="Coyote">
+    <changelog>
+      <scode>
+        Improve performance of Connector shutdown - primarily to reduce the time
+        it takes to run the test suite. (markt)
+      </scode>
+    </changelog>
+  </subsection>
   <subsection name="Jasper">
     <changelog>
       <update>

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