You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tomcat.apache.org by re...@apache.org on 2019/12/04 14:01:24 UTC

[tomcat] 01/02: Call completion handler directly on timeout

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

remm pushed a commit to branch 8.5.x
in repository https://gitbox.apache.org/repos/asf/tomcat.git

commit dee4413449fc2070a220cd66a2f0d05c7c81cd43
Author: remm <re...@apache.org>
AuthorDate: Wed Dec 4 14:42:34 2019 +0100

    Call completion handler directly on timeout
    
    Although it is possible I will redo it in a more precise way (but it is
    harder) so that if an operation requires multiple IO operations it does
    use decreasing timeouts, for now simply call the completion handler
    directly on timeout to enforce the "global" operation timeout. The
    actual IO will remain pending until it completes on its own, taking at
    most the duration of the timeout in addition to the operation timeout.
---
 java/org/apache/tomcat/util/net/SocketWrapperBase.java | 13 ++++++++++---
 webapps/docs/changelog.xml                             |  5 +++++
 2 files changed, 15 insertions(+), 3 deletions(-)

diff --git a/java/org/apache/tomcat/util/net/SocketWrapperBase.java b/java/org/apache/tomcat/util/net/SocketWrapperBase.java
index 0d348a6..d1127ed 100644
--- a/java/org/apache/tomcat/util/net/SocketWrapperBase.java
+++ b/java/org/apache/tomcat/util/net/SocketWrapperBase.java
@@ -910,6 +910,7 @@ public abstract class SocketWrapperBase<E> {
         protected final CompletionHandler<Long, ? super A> handler;
         protected final Semaphore semaphore;
         protected final VectoredIOCompletionHandler<A> completion;
+        protected final AtomicBoolean callHandler;
         protected OperationState(boolean read, ByteBuffer[] buffers, int offset, int length,
                 BlockingMode block, long timeout, TimeUnit unit, A attachment,
                 CompletionCheck check, CompletionHandler<Long, ? super A> handler,
@@ -926,6 +927,7 @@ public abstract class SocketWrapperBase<E> {
             this.handler = handler;
             this.semaphore = semaphore;
             this.completion = completion;
+            callHandler = (handler != null) ? new AtomicBoolean(true) : null;
         }
         protected volatile long nBytes = 0;
         protected volatile CompletionState state = CompletionState.PENDING;
@@ -1008,7 +1010,7 @@ public abstract class SocketWrapperBase<E> {
                         state.state = currentState;
                     }
                     state.end();
-                    if (completion && state.handler != null) {
+                    if (completion && state.handler != null && state.callHandler.compareAndSet(true, false)) {
                         state.handler.completed(Long.valueOf(state.nBytes), state.attachment);
                     }
                     synchronized (state) {
@@ -1049,7 +1051,7 @@ public abstract class SocketWrapperBase<E> {
                 state.state = state.isInline() ? CompletionState.ERROR : CompletionState.DONE;
             }
             state.end();
-            if (state.handler != null) {
+            if (state.handler != null && state.callHandler.compareAndSet(true, false)) {
                 state.handler.failed(exc, state.attachment);
             }
             synchronized (state) {
@@ -1379,10 +1381,15 @@ public abstract class SocketWrapperBase<E> {
                     try {
                         state.wait(unit.toMillis(timeout));
                         if (state.state == CompletionState.PENDING) {
+                            if (handler != null && state.callHandler.compareAndSet(true, false)) {
+                                handler.failed(new SocketTimeoutException(), attachment);
+                            }
                             return CompletionState.ERROR;
                         }
                     } catch (InterruptedException e) {
-                        completion.failed(new SocketTimeoutException(), state);
+                        if (handler != null && state.callHandler.compareAndSet(true, false)) {
+                            handler.failed(new SocketTimeoutException(), attachment);
+                        }
                         return CompletionState.ERROR;
                     }
                 }
diff --git a/webapps/docs/changelog.xml b/webapps/docs/changelog.xml
index 572808d..7976830 100644
--- a/webapps/docs/changelog.xml
+++ b/webapps/docs/changelog.xml
@@ -117,6 +117,11 @@
         All regular writes will now be buffered for a more predictable
         behavior. (remm)
       </fix>
+      <fix>
+        Send an exception directly to the completion handler when a timeout
+        exception occurs for the operation, and add a boolean to make sure the
+        completion handler is called only once. (remm/markt)
+      </fix>
     </changelog>
   </subsection>
   <subsection name="WebSocket">


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