Add in a slightly different behavior for dispatch.
authorfhanik <fhanik@13f79535-47bb-0310-9956-ffa450edef68>
Wed, 24 Mar 2010 21:26:47 +0000 (21:26 +0000)
committerfhanik <fhanik@13f79535-47bb-0310-9956-ffa450edef68>
Wed, 24 Mar 2010 21:26:47 +0000 (21:26 +0000)
dispatch() will return immediately, according to spec. But if dispatch is called from the tomcat worker thread, then the dispatch will not happen until the worker thread has backed out of the call. This prevents multiple threads being launched into the same request/response and causing potential concurrency issues.
The Async state machine guarantees that multiple dispatch can not be called.

git-svn-id: https://svn.apache.org/repos/asf/tomcat/trunk@927182 13f79535-47bb-0310-9956-ffa450edef68

java/org/apache/catalina/connector/CoyoteAdapter.java
java/org/apache/catalina/connector/Request.java
java/org/apache/catalina/core/StandardWrapperValve.java
java/org/apache/coyote/http11/Http11NioProcessor.java
java/org/apache/coyote/http11/Http11Processor.java

index 1886946..d8e8d22 100644 (file)
@@ -270,26 +270,48 @@ public class CoyoteAdapter implements Adapter {
         boolean success = true;
         
         try {
-            // Calling the container
-            try {
-                if (status==SocketStatus.TIMEOUT) {
-                   AsyncContextImpl asyncConImpl = (AsyncContextImpl)request.getAsyncContext();
-                   //TODO SERVLET3 - async
-                   //configure settings for timed out
-                   asyncConImpl.setTimeoutState();
-                }
-                if (status==SocketStatus.ERROR || status==SocketStatus.STOP || status==SocketStatus.DISCONNECT) {
-                    AsyncContextImpl asyncConImpl = (AsyncContextImpl)request.getAsyncContext();
+            if (status==SocketStatus.TIMEOUT) {
+                AsyncContextImpl asyncConImpl = (AsyncContextImpl)request.getAsyncContext();
+                //TODO SERVLET3 - async
+                //configure settings for timed out
+                asyncConImpl.setTimeoutState();
+            }
+            if (status==SocketStatus.ERROR || status==SocketStatus.STOP || status==SocketStatus.DISCONNECT) {
+                AsyncContextImpl asyncConImpl = (AsyncContextImpl)request.getAsyncContext();
+                //TODO SERVLET3 - async
+                //configure settings for timed out
+                asyncConImpl.setErrorState();
+            }
+            while (success) {
+                AsyncContextImpl impl = (AsyncContextImpl)request.getAsyncContext();
+                    // Calling the container
+                if (impl.getState()==AsyncContextImpl.AsyncState.DISPATCHED) {
+                    // Calling the container
+                    try {
+                        impl.complete();
+                        connector.getContainer().getPipeline().getFirst().invoke(request, response);
+                    } finally {
+                        success = false;
+                    }
+                } else if (impl.getState()==AsyncContextImpl.AsyncState.STARTED){
                     //TODO SERVLET3 - async
-                    //configure settings for timed out
-                    asyncConImpl.setErrorState();
+                    res.action(ActionCode.ACTION_ASYNC_START, request.getAsyncContext());
+                    async = true;
+                    break;
+                } else if (impl.getState()==AsyncContextImpl.AsyncState.NOT_STARTED){
+                        //TODO SERVLET3 - async
+                        async = false;
+                        break;
+                } else {
+                    try {
+                        connector.getContainer().getPipeline().getFirst().invoke(request, response);
+                    }catch (RuntimeException x) {
+                        success = false;
+                    } finally {
+                    }
                 }
-                connector.getContainer().getPipeline().getFirst().invoke(request, response);
-            }catch (RuntimeException x) {
-                success = false;
-            } finally {
             }
-
+            
             if (request.isComet()) {
                 if (!response.isClosed() && !response.isError()) {
                     if (request.getAvailable() || (request.getContentLength() > 0 && (!request.isParametersParsed()))) {
@@ -308,12 +330,7 @@ public class CoyoteAdapter implements Adapter {
                     request.setFilterChain(null);
                 }
             }
-
-            if (request.isAsyncStarted()) {
-                //TODO SERVLET3 - async
-                res.action(ActionCode.ACTION_ASYNC_START, request.getAsyncContext());
-                async = true;
-            } else if (!comet) {
+            if (!async && !comet) {
                 response.finishResponse();
                 req.action(ActionCode.ACTION_POST_REQUEST , null);
             }
@@ -410,11 +427,16 @@ public class CoyoteAdapter implements Adapter {
                 }
 
             }
-
+            AsyncContextImpl asyncConImpl = (AsyncContextImpl)request.getAsyncContext();
             if (request.isAsyncStarted()) {
-                //TODO SERVLET3 - async
                 res.action(ActionCode.ACTION_ASYNC_START, request.getAsyncContext());
                 async = true;
+            } else if (asyncConImpl!=null && 
+                          (asyncConImpl.getState()==AsyncContextImpl.AsyncState.DISPATCHING ||
+                           asyncConImpl.getState()==AsyncContextImpl.AsyncState.COMPLETING  ||
+                           asyncConImpl.getState()==AsyncContextImpl.AsyncState.TIMING_OUT  ||
+                           asyncConImpl.getState()==AsyncContextImpl.AsyncState.ERROR_DISPATCHING)) {
+                asyncDispatch(req, res, SocketStatus.OPEN);
             } else if (!comet) {
                 response.finishResponse();
                 req.action(ActionCode.ACTION_POST_REQUEST , null);
index 65d4091..36c15c3 100644 (file)
@@ -1539,6 +1539,15 @@ public class Request
         else return asyncContext.isStarted();
     }
 
+    public boolean isAsyncDispatching() {
+        if (asyncContext==null) return false;
+        else return (asyncContext.getState()==AsyncContextImpl.AsyncState.DISPATCHING ||
+                     asyncContext.getState()==AsyncContextImpl.AsyncState.TIMING_OUT  ||
+                     asyncContext.getState()==AsyncContextImpl.AsyncState.STARTED     ||
+                     asyncContext.getState()==AsyncContextImpl.AsyncState.ERROR_DISPATCHING ||
+                     asyncContext.getState()==AsyncContextImpl.AsyncState.COMPLETING);
+    }
+
     public boolean isAsyncSupported() {
         // TODO SERVLET3 - async
         if (this.asyncSupported==null) { 
index 01fd140..6d11bac 100644 (file)
@@ -217,7 +217,7 @@ final class StandardWrapperValve
                 if (context.getSwallowOutput()) {
                     try {
                         SystemLogHandler.startCapture();
-                        if (request.isAsyncStarted()) {
+                        if (request.isAsyncDispatching()) {
                             //TODO SERVLET3 - async
                             ((AsyncContextImpl)request.getAsyncContext()).doInternalDispatch(); 
                         } else if (comet) {
@@ -234,7 +234,7 @@ final class StandardWrapperValve
                         }
                     }
                 } else {
-                    if (request.isAsyncStarted()) {
+                    if (request.isAsyncDispatching()) {
                         //TODO SERVLET3 - async
                         ((AsyncContextImpl)request.getAsyncContext()).doInternalDispatch();
                     } else if (comet) {
index 5c31372..b27a005 100644 (file)
@@ -777,6 +777,8 @@ public class Http11NioProcessor extends AbstractHttp11Processor implements Actio
             if ( rp.getStage() != org.apache.coyote.Constants.STAGE_SERVICE ) { //async handling
                 dispatch.set(true);
                 endpoint.processSocket(this.socket, SocketStatus.STOP, true);
+            } else {
+                dispatch.set(true);
             }
         } else if (actionCode == ActionCode.ACTION_ASYNC_SETTIMEOUT) {
           //TODO SERVLET3 - async
@@ -793,7 +795,7 @@ public class Http11NioProcessor extends AbstractHttp11Processor implements Actio
                 endpoint.processSocket(this.socket, SocketStatus.OPEN, true);
                 dispatch.set(true);
             } else { 
-                
+                dispatch.set(true);
             }
         }
     }
index af76297..b195dd2 100644 (file)
@@ -621,7 +621,7 @@ public class Http11Processor extends AbstractHttp11Processor implements ActionHo
                 dispatch.set(true);
                 endpoint.processSocket(this.socket, SocketStatus.STOP);
             } else {
-                //TODO SERVLET3 async=false
+                dispatch.set(true);
             }
         } else if (actionCode == ActionCode.ACTION_ASYNC_SETTIMEOUT) {
           //TODO SERVLET3 - async
@@ -636,7 +636,7 @@ public class Http11Processor extends AbstractHttp11Processor implements ActionHo
                 endpoint.processSocket(this.socket, SocketStatus.OPEN);
                 dispatch.set(true);
             } else { 
-                //TODO SERVLET3 - do nothing?
+                dispatch.set(true);
             }
         }