This is an automated email from the ASF dual-hosted git repository.
markt pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/tomcat.git
The following commit(s) were added to refs/heads/master by this push:
new 6d44f6a Fix double counting in tracking of in-flight async requests
6d44f6a is described below
commit 6d44f6aa52748df930f1563bb5598705eb75e1aa
Author: Mark Thomas <[email protected]>
AuthorDate: Tue Sep 22 14:40:58 2020 +0100
Fix double counting in tracking of in-flight async requests
---
java/org/apache/catalina/core/AsyncContextImpl.java | 19 ++++++++++++-------
java/org/apache/coyote/AsyncContextCallback.java | 20 ++++++++++++++++++--
java/org/apache/coyote/AsyncStateMachine.java | 12 ++++++++++++
webapps/docs/changelog.xml | 5 +++++
4 files changed, 47 insertions(+), 9 deletions(-)
diff --git a/java/org/apache/catalina/core/AsyncContextImpl.java
b/java/org/apache/catalina/core/AsyncContextImpl.java
index 4d2dc4c..b332922 100644
--- a/java/org/apache/catalina/core/AsyncContextImpl.java
+++ b/java/org/apache/catalina/core/AsyncContextImpl.java
@@ -114,7 +114,6 @@ public class AsyncContextImpl implements AsyncContext,
AsyncContextCallback {
} finally {
context.fireRequestDestroyEvent(request.getRequest());
clearServletRequestResponse();
- this.context.decrementInProgressAsyncCount();
context.unbind(Globals.IS_SECURITY_ENABLED, oldCL);
}
}
@@ -207,16 +206,10 @@ public class AsyncContextImpl implements AsyncContext,
AsyncContextCallback {
(AsyncDispatcher) requestDispatcher;
final ServletRequest servletRequest = getRequest();
final ServletResponse servletResponse = getResponse();
- // https://bz.apache.org/bugzilla/show_bug.cgi?id=63246
- // Take a local copy as the dispatch may complete the
- // request/response and that in turn may trigger recycling of this
- // object before the in-progress count can be decremented
- final Context context = this.context;
this.dispatch = new AsyncRunnable(
request, applicationDispatcher, servletRequest,
servletResponse);
this.request.getCoyoteRequest().action(ActionCode.ASYNC_DISPATCH,
null);
clearServletRequestResponse();
- context.decrementInProgressAsyncCount();
}
}
@@ -458,6 +451,18 @@ public class AsyncContextImpl implements AsyncContext,
AsyncContextCallback {
}
+ @Override
+ public void incrementInProgressAsyncCount() {
+ context.incrementInProgressAsyncCount();
+ }
+
+
+ @Override
+ public void decrementInProgressAsyncCount() {
+ context.decrementInProgressAsyncCount();
+ }
+
+
private void logDebug(String method) {
String rHashCode;
String crHashCode;
diff --git a/java/org/apache/coyote/AsyncContextCallback.java
b/java/org/apache/coyote/AsyncContextCallback.java
index c1d742f..9f9b925 100644
--- a/java/org/apache/coyote/AsyncContextCallback.java
+++ b/java/org/apache/coyote/AsyncContextCallback.java
@@ -23,7 +23,7 @@ package org.apache.coyote;
* org.apache.catalina package.
*/
public interface AsyncContextCallback {
- public void fireOnComplete();
+ void fireOnComplete();
/**
* Reports if the web application associated with this async request is
@@ -32,5 +32,21 @@ public interface AsyncContextCallback {
* @return {@code true} if the associated web application is available,
* otherwise {@code false}
*/
- public boolean isAvailable();
+ boolean isAvailable();
+
+ /**
+ * Used to notify the Context that async processing has started.
+ * Specifically, for the counting of in-progress async requests to work
+ * correctly, this must be called exactly once every time the
+ * {@link AsyncStateMachine} transitions from DISPATCHED to any other
state.
+ */
+ void incrementInProgressAsyncCount();
+
+ /**
+ * Used to notify the Context that async processing has ended.
+ * Specifically, for the counting of in-progress async requests to work
+ * correctly, this must be called exactly once every time the
+ * {@link AsyncStateMachine} transitions to DISPATCHED from any other
state.
+ */
+ void decrementInProgressAsyncCount();
}
diff --git a/java/org/apache/coyote/AsyncStateMachine.java
b/java/org/apache/coyote/AsyncStateMachine.java
index 7b28ad2..a993a39 100644
--- a/java/org/apache/coyote/AsyncStateMachine.java
+++ b/java/org/apache/coyote/AsyncStateMachine.java
@@ -235,6 +235,9 @@ class AsyncStateMachine {
if (state == AsyncState.DISPATCHED) {
generation.incrementAndGet();
state = AsyncState.STARTING;
+ // Note: In this instance, caller is responsible for calling
+ // asyncCtxt.incrementInProgressAsyncCount() as that allows simpler
+ // error handling.
this.asyncCtxt = asyncCtxt;
lastAsyncStart = System.currentTimeMillis();
} else {
@@ -274,12 +277,14 @@ class AsyncStateMachine {
} else if (state == AsyncState.MUST_COMPLETE || state ==
AsyncState.COMPLETING) {
asyncCtxt.fireOnComplete();
state = AsyncState.DISPATCHED;
+ asyncCtxt.decrementInProgressAsyncCount();
return SocketState.ASYNC_END;
} else if (state == AsyncState.MUST_DISPATCH) {
state = AsyncState.DISPATCHING;
return SocketState.ASYNC_END;
} else if (state == AsyncState.DISPATCHING) {
state = AsyncState.DISPATCHED;
+ asyncCtxt.decrementInProgressAsyncCount();
return SocketState.ASYNC_END;
} else if (state == AsyncState.STARTED) {
// This can occur if an async listener does a dispatch to an async
@@ -401,6 +406,7 @@ class AsyncStateMachine {
if (state == AsyncState.DISPATCHING ||
state == AsyncState.MUST_DISPATCH) {
state = AsyncState.DISPATCHED;
+ asyncCtxt.decrementInProgressAsyncCount();
} else {
throw new IllegalStateException(
sm.getString("asyncStateMachine.invalidAsyncState",
@@ -413,6 +419,12 @@ class AsyncStateMachine {
clearNonBlockingListeners();
if (state == AsyncState.STARTING) {
state = AsyncState.MUST_ERROR;
+ } else if (state == AsyncState.DISPATCHED) {
+ // Async error handling has moved processing back into an async
+ // state. Need to increment in progress count as it will decrement
+ // when the async state is exited again.
+ asyncCtxt.incrementInProgressAsyncCount();
+ state = AsyncState.ERROR;
} else {
state = AsyncState.ERROR;
}
diff --git a/webapps/docs/changelog.xml b/webapps/docs/changelog.xml
index d7e275b..62527c1 100644
--- a/webapps/docs/changelog.xml
+++ b/webapps/docs/changelog.xml
@@ -100,6 +100,11 @@
When logging HTTP/2 debug messages, use consistent formatting for
stream
identifiers. (markt)
</fix>
+ <fix>
+ Correct some double counting in the code that tracks the number of
+ in-flight asynchronous requests. The tracking enables Tomcat to
shutdown
+ gracefully when asynchronous processing is in use. (markt)
+ </fix>
</changelog>
</subsection>
<subsection name="Jasper">
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]