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 13:42:46 UTC

[tomcat] branch master updated: Call completion handler directly on timeout

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

remm 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 e9630b6  Call completion handler directly on timeout
e9630b6 is described below

commit e9630b66d883f6113e70689fe9963a6f8dbe9664
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 deddf81..f205725 100644
--- a/java/org/apache/tomcat/util/net/SocketWrapperBase.java
+++ b/java/org/apache/tomcat/util/net/SocketWrapperBase.java
@@ -960,6 +960,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,
@@ -976,6 +977,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;
@@ -1058,7 +1060,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) {
@@ -1099,7 +1101,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) {
@@ -1429,10 +1431,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 6b0d199..5ed9c6d 100644
--- a/webapps/docs/changelog.xml
+++ b/webapps/docs/changelog.xml
@@ -114,6 +114,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