From cb2104fc2eb9d2fce2b59f340364e3ef4d4fccf1 Mon Sep 17 00:00:00 2001 From: fhanik Date: Wed, 19 Jul 2006 17:49:47 +0000 Subject: [PATCH] Comet connection handling. When the response.getWriter().close() method has been called, 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 --- .../apache/coyote/http11/Http11NioProcessor.java | 22 ++++++++++++++++++- .../coyote/http11/InternalNioOutputBuffer.java | 13 ++++------- java/org/apache/tomcat/util/net/NioEndpoint.java | 25 ++++++++++++++-------- 3 files changed, 41 insertions(+), 19 deletions(-) diff --git a/java/org/apache/coyote/http11/Http11NioProcessor.java b/java/org/apache/coyote/http11/Http11NioProcessor.java index 4d44aa033..ce2a7b299 100644 --- a/java/org/apache/coyote/http11/Http11NioProcessor.java +++ b/java/org/apache/coyote/http11/Http11NioProcessor.java @@ -174,7 +174,14 @@ public class Http11NioProcessor implements ActionHook { * Comet used. */ protected boolean comet = false; - + + /** + * Closed flag, a Comet async thread can + * signal for this Nio processor to be closed and recycled instead + * of waiting for a timeout. + * Closed by HttpServletResponse.getWriter().close() + */ + protected boolean cometClose = false; /** * Content delimitator for the request (if false, the connection will @@ -970,6 +977,8 @@ public class Http11NioProcessor implements ActionHook { inputBuffer.recycle(); outputBuffer.recycle(); this.socket = null; + this.cometClose = false; + this.comet = false; } @@ -1034,6 +1043,17 @@ public class Http11NioProcessor implements ActionHook { // transactions with the client comet = false; + cometClose = true; + SelectionKey key = socket.keyFor(endpoint.getPoller().getSelector()); + if ( key != null ) { + NioEndpoint.KeyAttachment attach = (NioEndpoint.KeyAttachment) key.attachment(); + if ( attach!=null && attach.getComet()) { + //we need to recycle + request.getAttributes().remove("org.apache.tomcat.comet.timeout"); + attach.setError(true); + } + } + try { outputBuffer.endRequest(); } catch (IOException e) { diff --git a/java/org/apache/coyote/http11/InternalNioOutputBuffer.java b/java/org/apache/coyote/http11/InternalNioOutputBuffer.java index 265927ee8..7947e42ed 100644 --- a/java/org/apache/coyote/http11/InternalNioOutputBuffer.java +++ b/java/org/apache/coyote/http11/InternalNioOutputBuffer.java @@ -571,16 +571,11 @@ public class InternalNioOutputBuffer int total = 0; private synchronized void addToBB(byte[] buf, int offset, int length) throws IOException { - try { - if (bbuf.capacity() <= (offset + length)) { - flushBuffer(); - } - bbuf.put(buf, offset, length); - total += length; - }catch ( Exception x ) { - x.printStackTrace(); + if (bbuf.capacity() <= (offset + length)) { + flushBuffer(); } - //System.out.println("Total:"+total); + bbuf.put(buf, offset, length); + total += length; } diff --git a/java/org/apache/tomcat/util/net/NioEndpoint.java b/java/org/apache/tomcat/util/net/NioEndpoint.java index 8301cbd6d..abb8e8eaa 100644 --- a/java/org/apache/tomcat/util/net/NioEndpoint.java +++ b/java/org/apache/tomcat/util/net/NioEndpoint.java @@ -312,7 +312,7 @@ public class NioEndpoint { public void setPollerThreadCount(int pollerThreadCount) { this.pollerThreadCount = pollerThreadCount; } public int getPollerThreadCount() { return pollerThreadCount; } - protected long selectorTimeout = 5000; + protected long selectorTimeout = 1000; public void setSelectorTimeout(long timeout){ this.selectorTimeout = timeout;} public long getSelectorTimeout(){ return this.selectorTimeout; } /** @@ -1043,9 +1043,11 @@ public class NioEndpoint { addEvent(r); } - public void events() { + public boolean events() { + boolean result = false; synchronized (events) { Runnable r = null; + result = (events.size() > 0); while ( (events.size() > 0) && (r = events.removeFirst()) != null ) { try { r.run(); @@ -1055,6 +1057,7 @@ public class NioEndpoint { } events.clear(); } + return result; } public void register(final SocketChannel socket) @@ -1103,8 +1106,9 @@ public class NioEndpoint { // Ignore } } + boolean hasEvents = false; - events(); + hasEvents = (hasEvents | events()); // Time to terminate? if (close) return; @@ -1115,8 +1119,9 @@ public class NioEndpoint { log.error("",x); continue; } - - + + //either we timed out or we woke up, process events first + if ( keyCount == 0 ) hasEvents = (hasEvents | events()); //if (keyCount == 0) continue; @@ -1162,16 +1167,18 @@ public class NioEndpoint { } }//while //process timeouts - timeout(); - } + timeout(keyCount,hasEvents); + }//while synchronized (this) { this.notifyAll(); } } - protected void timeout() { + protected void timeout(int keyCount, boolean hasEvents) { long now = System.currentTimeMillis(); - if ( now < nextExpiration ) return; + //don't process timeouts too frequently, but if the selector simply timed out + //then we can check timeouts to avoid gaps + if ( (now < nextExpiration) && (keyCount>0 || hasEvents) ) return; nextExpiration = now + (long)soTimeout; //timeout Set keys = selector.keys(); -- 2.11.0