Comet connection handling. When the response.getWriter().close() method has been...
authorfhanik <fhanik@13f79535-47bb-0310-9956-ffa450edef68>
Wed, 19 Jul 2006 17:49:47 +0000 (17:49 +0000)
committerfhanik <fhanik@13f79535-47bb-0310-9956-ffa450edef68>
Wed, 19 Jul 2006 17:49:47 +0000 (17:49 +0000)
the comet connection is setup for closure instead of waiting for a timeout.
This is necessary since the servlet could have set a long timeout.
Also, improve on timeout checking. Only use the optimization for how frequently we need to check the keys if there has been no activity on the selector. During heavy activity, the optimization takes into effect.

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

java/org/apache/coyote/http11/Http11NioProcessor.java
java/org/apache/coyote/http11/InternalNioOutputBuffer.java
java/org/apache/tomcat/util/net/NioEndpoint.java

index 4d44aa0..ce2a7b2 100644 (file)
@@ -174,7 +174,14 @@ public class Http11NioProcessor implements ActionHook {
      * Comet used.\r
      */\r
     protected boolean comet = false;\r
-\r
+    \r
+    /**\r
+     * Closed flag, a Comet async thread can \r
+     * signal for this Nio processor to be closed and recycled instead\r
+     * of waiting for a timeout.\r
+     * Closed by HttpServletResponse.getWriter().close()\r
+     */\r
+    protected boolean cometClose = false;\r
 \r
     /**\r
      * Content delimitator for the request (if false, the connection will\r
@@ -970,6 +977,8 @@ public class Http11NioProcessor implements ActionHook {
         inputBuffer.recycle();\r
         outputBuffer.recycle();\r
         this.socket = null;\r
+        this.cometClose = false;\r
+        this.comet = false;\r
     }\r
 \r
 \r
@@ -1034,6 +1043,17 @@ public class Http11NioProcessor implements ActionHook {
             // transactions with the client\r
 \r
             comet = false;\r
+            cometClose = true;\r
+            SelectionKey key = socket.keyFor(endpoint.getPoller().getSelector());\r
+            if ( key != null ) {\r
+                NioEndpoint.KeyAttachment attach = (NioEndpoint.KeyAttachment) key.attachment();\r
+                if ( attach!=null && attach.getComet()) {\r
+                    //we need to recycle\r
+                    request.getAttributes().remove("org.apache.tomcat.comet.timeout");\r
+                    attach.setError(true);\r
+                }\r
+            }\r
+\r
             try {\r
                 outputBuffer.endRequest();\r
             } catch (IOException e) {\r
index 265927e..7947e42 100644 (file)
@@ -571,16 +571,11 @@ public class InternalNioOutputBuffer
 \r
     int total = 0;\r
     private synchronized void addToBB(byte[] buf, int offset, int length) throws IOException {\r
-        try {\r
-            if (bbuf.capacity() <= (offset + length)) {\r
-                flushBuffer();\r
-            }\r
-            bbuf.put(buf, offset, length);\r
-            total += length;\r
-        }catch ( Exception x ) {\r
-            x.printStackTrace();\r
+        if (bbuf.capacity() <= (offset + length)) {\r
+            flushBuffer();\r
         }\r
-        //System.out.println("Total:"+total);\r
+        bbuf.put(buf, offset, length);\r
+        total += length;\r
     }\r
 \r
 \r
index 8301cbd..abb8e8e 100644 (file)
@@ -312,7 +312,7 @@ public class NioEndpoint {
     public void setPollerThreadCount(int pollerThreadCount) { this.pollerThreadCount = pollerThreadCount; }\r
     public int getPollerThreadCount() { return pollerThreadCount; }\r
 \r
-    protected long selectorTimeout = 5000;\r
+    protected long selectorTimeout = 1000;\r
     public void setSelectorTimeout(long timeout){ this.selectorTimeout = timeout;}\r
     public long getSelectorTimeout(){ return this.selectorTimeout; }\r
     /**\r
@@ -1043,9 +1043,11 @@ public class NioEndpoint {
             addEvent(r);\r
         }\r
 \r
-        public void events() {\r
+        public boolean events() {\r
+            boolean result = false;\r
             synchronized (events) {\r
                 Runnable r = null;\r
+                result = (events.size() > 0);\r
                 while ( (events.size() > 0) && (r = events.removeFirst()) != null ) {\r
                     try {\r
                         r.run();\r
@@ -1055,6 +1057,7 @@ public class NioEndpoint {
                 }\r
                 events.clear();\r
             }\r
+            return result;\r
         }\r
         \r
         public void register(final SocketChannel socket)\r
@@ -1103,8 +1106,9 @@ public class NioEndpoint {
                         // Ignore\r
                     }\r
                 }\r
+                boolean hasEvents = false;\r
 \r
-                events();\r
+                hasEvents = (hasEvents | events());\r
                 // Time to terminate?\r
                 if (close) return;\r
 \r
@@ -1115,8 +1119,9 @@ public class NioEndpoint {
                     log.error("",x);\r
                     continue;\r
                 }\r
-                \r
-            \r
+\r
+                //either we timed out or we woke up, process events first\r
+                if ( keyCount == 0 ) hasEvents = (hasEvents | events());\r
 \r
                 //if (keyCount == 0) continue;\r
 \r
@@ -1162,16 +1167,18 @@ public class NioEndpoint {
                     }\r
                 }//while\r
                 //process timeouts\r
-                timeout();\r
-            }\r
+                timeout(keyCount,hasEvents);\r
+            }//while\r
             synchronized (this) {\r
                 this.notifyAll();\r
             }\r
 \r
         }\r
-        protected void timeout() {\r
+        protected void timeout(int keyCount, boolean hasEvents) {\r
             long now = System.currentTimeMillis();\r
-            if ( now < nextExpiration ) return;\r
+            //don't process timeouts too frequently, but if the selector simply timed out\r
+            //then we can check timeouts to avoid gaps\r
+            if ( (now < nextExpiration) && (keyCount>0 || hasEvents) ) return;\r
             nextExpiration = now + (long)soTimeout;\r
             //timeout\r
             Set<SelectionKey> keys = selector.keys();\r