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 15:50:10 UTC
[tomcat] branch 8.5.x updated: 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 8.5.x
in repository https://gitbox.apache.org/repos/asf/tomcat.git
The following commit(s) were added to refs/heads/8.5.x by this push:
new 3b82538 Improve Connector stop performance - primarily to speed up tests
3b82538 is described below
commit 3b82538e9d1e5da932ba4dff13c3201ac7c39e27
Author: Mark Thomas <ma...@apache.org>
AuthorDate: Mon Oct 11 16:48:26 2021 +0100
Improve Connector stop performance - primarily to speed up tests
---
.../apache/tomcat/util/net/AbstractEndpoint.java | 14 ++++++++
java/org/apache/tomcat/util/net/AprEndpoint.java | 35 +++++++++++++++----
java/org/apache/tomcat/util/net/Nio2Endpoint.java | 39 +++++++++++++++++-----
java/org/apache/tomcat/util/net/NioEndpoint.java | 39 +++++++++++++++++-----
webapps/docs/changelog.xml | 8 +++++
5 files changed, 113 insertions(+), 22 deletions(-)
diff --git a/java/org/apache/tomcat/util/net/AbstractEndpoint.java b/java/org/apache/tomcat/util/net/AbstractEndpoint.java
index 9aad8c2..8830658 100644
--- a/java/org/apache/tomcat/util/net/AbstractEndpoint.java
+++ b/java/org/apache/tomcat/util/net/AbstractEndpoint.java
@@ -1022,6 +1022,20 @@ public abstract class AbstractEndpoint<S> {
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();
+ for (Acceptor acceptor : acceptors) {
+ 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);
if (getLog().isDebugEnabled()) {
diff --git a/java/org/apache/tomcat/util/net/AprEndpoint.java b/java/org/apache/tomcat/util/net/AprEndpoint.java
index 413a8ad..eda0abf 100644
--- a/java/org/apache/tomcat/util/net/AprEndpoint.java
+++ b/java/org/apache/tomcat/util/net/AprEndpoint.java
@@ -803,17 +803,40 @@ public class AprEndpoint extends AbstractEndpoint<Long> implements SNICallBack {
public void run() {
int errorDelay = 0;
+ long pauseStart = 0;
// Loop until we receive a shutdown command
while (running) {
- // 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 (paused && running) {
- 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 5e0dfe1..a2e0bd3 100644
--- a/java/org/apache/tomcat/util/net/Nio2Endpoint.java
+++ b/java/org/apache/tomcat/util/net/Nio2Endpoint.java
@@ -255,8 +255,8 @@ public class Nio2Endpoint extends AbstractJsseEndpoint<Nio2Channel> {
try {
long timeout = getExecutorTerminationTimeoutMillis();
while (timeout > 0 && !allClosed) {
- timeout -= 100;
- Thread.sleep(100);
+ timeout -= 1;
+ Thread.sleep(1);
}
threadGroup.shutdownNow();
if (timeout > 0) {
@@ -363,17 +363,40 @@ public class Nio2Endpoint extends AbstractJsseEndpoint<Nio2Channel> {
public void run() {
int errorDelay = 0;
+ long pauseStart = 0;
// Loop until we receive a shutdown command
while (running) {
- // 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 (paused && running) {
- 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/NioEndpoint.java b/java/org/apache/tomcat/util/net/NioEndpoint.java
index 4fd9137..8f2ee6c 100644
--- a/java/org/apache/tomcat/util/net/NioEndpoint.java
+++ b/java/org/apache/tomcat/util/net/NioEndpoint.java
@@ -461,18 +461,41 @@ public class NioEndpoint extends AbstractJsseEndpoint<NioChannel> {
public void run() {
int errorDelay = 0;
+ long pauseStart = 0;
// Loop until we receive a shutdown command
while (running) {
- // Loop if endpoint is paused
- while (paused && running) {
- state = AcceptorState.PAUSED;
- try {
- Thread.sleep(50);
- } catch (InterruptedException e) {
- // Ignore
- }
+ // 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 (paused && running) {
+ 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
+ }
+ }
}
if (!running) {
diff --git a/webapps/docs/changelog.xml b/webapps/docs/changelog.xml
index 3342f1d..0205463 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 8.5.73 (schultz)">
+ <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="WebSocket">
<changelog>
<update>
---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org