Author: fhanik Date: Wed Jan 14 16:13:39 2009 New Revision: 734574 URL: http://svn.apache.org/viewvc?rev=734574&view=rev Log: implement last of NIO fixes
Modified: tomcat/tc6.0.x/trunk/STATUS.txt tomcat/tc6.0.x/trunk/java/org/apache/coyote/http11/Http11NioProtocol.java tomcat/tc6.0.x/trunk/java/org/apache/tomcat/util/net/NioChannel.java tomcat/tc6.0.x/trunk/java/org/apache/tomcat/util/net/NioEndpoint.java tomcat/tc6.0.x/trunk/java/org/apache/tomcat/util/net/SecureNioChannel.java tomcat/tc6.0.x/trunk/webapps/docs/changelog.xml Modified: tomcat/tc6.0.x/trunk/STATUS.txt URL: http://svn.apache.org/viewvc/tomcat/tc6.0.x/trunk/STATUS.txt?rev=734574&r1=734573&r2=734574&view=diff ============================================================================== --- tomcat/tc6.0.x/trunk/STATUS.txt (original) +++ tomcat/tc6.0.x/trunk/STATUS.txt Wed Jan 14 16:13:39 2009 @@ -118,18 +118,6 @@ really old to me, so where would this come from ?) -1: -* [4] Fix https://issues.apache.org/bugzilla/show_bug.cgi?id=45154 (add sendfile support to NIO/SSL) - performance improvement - http://svn.apache.org/viewvc?rev=720724&view=rev - http://svn.apache.org/viewvc?rev=720728&view=rev - http://svn.apache.org/viewvc?rev=725417&view=rev - +1: fhanik, jim, markt - -1: - -* [5] Fix Comet interest registration bug - http://people.apache.org/~fhanik/tomcat/comet-ops.patch - +1: fhanik, funkman, markt - -1: - * Changes required to run with a security manager http://svn.apache.org/viewvc?rev=721286&view=rev http://svn.apache.org/viewvc?rev=721704&view=rev Modified: tomcat/tc6.0.x/trunk/java/org/apache/coyote/http11/Http11NioProtocol.java URL: http://svn.apache.org/viewvc/tomcat/tc6.0.x/trunk/java/org/apache/coyote/http11/Http11NioProtocol.java?rev=734574&r1=734573&r2=734574&view=diff ============================================================================== --- tomcat/tc6.0.x/trunk/java/org/apache/coyote/http11/Http11NioProtocol.java (original) +++ tomcat/tc6.0.x/trunk/java/org/apache/coyote/http11/Http11NioProtocol.java Wed Jan 14 16:13:39 2009 @@ -309,7 +309,6 @@ public void setUseSendfile(boolean useSendfile) { ep.setUseSendfile(useSendfile); } - // -------------------- Tcp setup -------------------- Modified: tomcat/tc6.0.x/trunk/java/org/apache/tomcat/util/net/NioChannel.java URL: http://svn.apache.org/viewvc/tomcat/tc6.0.x/trunk/java/org/apache/tomcat/util/net/NioChannel.java?rev=734574&r1=734573&r2=734574&view=diff ============================================================================== --- tomcat/tc6.0.x/trunk/java/org/apache/tomcat/util/net/NioChannel.java (original) +++ tomcat/tc6.0.x/trunk/java/org/apache/tomcat/util/net/NioChannel.java Wed Jan 14 16:13:39 2009 @@ -47,6 +47,8 @@ protected ApplicationBufferHandler bufHandler; protected Poller poller; + + protected boolean sendFile = false; public NioChannel(SocketChannel channel, ApplicationBufferHandler bufHandler) throws IOException { this.sc = channel; @@ -56,6 +58,7 @@ public void reset() throws IOException { bufHandler.getReadBuffer().clear(); bufHandler.getWriteBuffer().clear(); + this.sendFile = false; } public int getBufferSize() { @@ -191,5 +194,27 @@ public String toString() { return super.toString()+":"+this.sc.toString(); } + + public int getOutboundRemaining() { + return 0; + } + + /** + * Return true if the buffer wrote data + * @return + * @throws IOException + */ + public boolean flushOutbound() throws IOException { + return false; + } + + public boolean isSendFile() { + return sendFile; + } + + public void setSendFile(boolean s) { + this.sendFile = s; + } + } Modified: tomcat/tc6.0.x/trunk/java/org/apache/tomcat/util/net/NioEndpoint.java URL: http://svn.apache.org/viewvc/tomcat/tc6.0.x/trunk/java/org/apache/tomcat/util/net/NioEndpoint.java?rev=734574&r1=734573&r2=734574&view=diff ============================================================================== --- tomcat/tc6.0.x/trunk/java/org/apache/tomcat/util/net/NioEndpoint.java (original) +++ tomcat/tc6.0.x/trunk/java/org/apache/tomcat/util/net/NioEndpoint.java Wed Jan 14 16:13:39 2009 @@ -30,6 +30,7 @@ import java.nio.channels.Selector; import java.nio.channels.ServerSocketChannel; import java.nio.channels.SocketChannel; +import java.nio.channels.WritableByteChannel; import java.security.KeyStore; import java.util.Collection; import java.util.Iterator; @@ -491,7 +492,7 @@ /** * Poller thread count. */ - protected int pollerThreadCount = 1; + protected int pollerThreadCount = Runtime.getRuntime().availableProcessors(); public void setPollerThreadCount(int pollerThreadCount) { this.pollerThreadCount = pollerThreadCount; } public int getPollerThreadCount() { return pollerThreadCount; } @@ -501,9 +502,15 @@ /** * The socket poller. */ - protected Poller poller = null; + protected Poller[] pollers = null; + protected AtomicInteger pollerRotater = new AtomicInteger(0); + /** + * Return an available poller in true round robin fashion + * @return + */ public Poller getPoller0() { - return poller; + int idx = Math.abs(pollerRotater.incrementAndGet()) % pollers.length; + return pollers[idx]; } /** @@ -652,7 +659,6 @@ } public void setUseSendfile(boolean useSendfile) { - this.useSendfile = useSendfile; } @@ -703,10 +709,14 @@ * Number of keepalive sockets. */ public int getKeepAliveCount() { - if (poller == null) { + if (pollers == null) { return 0; } else { - return poller.selector.keys().size(); + int sum = 0; + for (int i=0; i<pollers.length; i++) { + sum += pollers[i].selector.keys().size(); + } + return sum; } } @@ -861,12 +871,15 @@ workers = new WorkerStack(maxThreads); } - // Start poller thread - poller = new Poller(); - Thread pollerThread = new Thread(poller, getName() + "-ClientPoller"); - pollerThread.setPriority(threadPriority); - pollerThread.setDaemon(true); - pollerThread.start(); + // Start poller threads + pollers = new Poller[getPollerThreadCount()]; + for (int i=0; i<pollers.length; i++) { + pollers[i] = new Poller(); + Thread pollerThread = new Thread(pollers[i], getName() + "-ClientPoller-"+i); + pollerThread.setPriority(threadPriority); + pollerThread.setDaemon(true); + pollerThread.start(); + } // Start acceptor threads for (int i = 0; i < acceptorThreadCount; i++) { @@ -908,8 +921,11 @@ if (running) { running = false; unlockAccept(); - poller.destroy(); - poller = null; + for (int i=0; pollers!=null && i<pollers.length; i++) { + if (pollers[i]==null) continue; + pollers[i].destroy(); + pollers[i] = null; + } } eventCache.clear(); keyCache.clear(); @@ -974,8 +990,7 @@ } public boolean getUseSendfile() { - //send file doesn't work with SSL - return useSendfile && (!isSSLEnabled()); + return useSendfile; } public int getOomParachute() { @@ -1345,10 +1360,10 @@ } else { cancel = true; } - if ( cancel ) getPoller0().cancelledKey(key,SocketStatus.ERROR,false); + if ( cancel ) socket.getPoller().cancelledKey(key,SocketStatus.ERROR,false); }catch (CancelledKeyException ckx) { try { - getPoller0().cancelledKey(key,SocketStatus.DISCONNECT,true); + socket.getPoller().cancelledKey(key,SocketStatus.DISCONNECT,true); }catch (Exception ignore) {} } }//end if @@ -1645,6 +1660,7 @@ } public boolean processSendfile(SelectionKey sk, KeyAttachment attachment, boolean reg, boolean event) { + NioChannel sc = null; try { //unreg(sk,attachment);//only do this if we do process send file on a separate thread SendfileData sd = attachment.getSendfileData(); @@ -1656,13 +1672,23 @@ } sd.fchannel = new FileInputStream(f).getChannel(); } - SocketChannel sc = attachment.getChannel().getIOChannel(); - long written = sd.fchannel.transferTo(sd.pos,sd.length,sc); - if ( written > 0 ) { - sd.pos += written; - sd.length -= written; + sc = attachment.getChannel(); + sc.setSendFile(true); + WritableByteChannel wc =(WritableByteChannel) ((sc instanceof SecureNioChannel)?sc:sc.getIOChannel()); + + if (sc.getOutboundRemaining()>0) { + if (sc.flushOutbound()) { + attachment.access(); + } + } else { + long written = sd.fchannel.transferTo(sd.pos,sd.length,wc); + if ( written > 0 ) { + sd.pos += written; + sd.length -= written; + attachment.access(); + } } - if ( sd.length <= 0 ) { + if ( sd.length <= 0 && sc.getOutboundRemaining()<=0) { if (log.isDebugEnabled()) { log.debug("Send file complete for:"+sd.fileName); } @@ -1703,6 +1729,8 @@ log.error("",t); cancelledKey(sk, SocketStatus.ERROR, false); return false; + }finally { + if (sc!=null) sc.setSendFile(false); } return true; } @@ -1738,14 +1766,15 @@ if ( ka == null ) { cancelledKey(key, SocketStatus.ERROR,false); //we don't support any keys without attachments } else if ( ka.getError() ) { - cancelledKey(key, SocketStatus.ERROR,true); + cancelledKey(key, SocketStatus.ERROR,true);//TODO this is not yet being used } else if (ka.getComet() && ka.getCometNotify() ) { ka.setCometNotify(false); reg(key,ka,0);//avoid multiple calls, this gets reregistered after invokation //if (!processSocket(ka.getChannel(), SocketStatus.OPEN_CALLBACK)) processSocket(ka.getChannel(), SocketStatus.DISCONNECT); if (!processSocket(ka.getChannel(), SocketStatus.OPEN)) processSocket(ka.getChannel(), SocketStatus.DISCONNECT); - }else if ((ka.interestOps()&SelectionKey.OP_READ) == SelectionKey.OP_READ) { - //only timeout sockets that we are waiting for a read from + }else if ((ka.interestOps()&SelectionKey.OP_READ) == SelectionKey.OP_READ || + (ka.interestOps()&SelectionKey.OP_WRITE) == SelectionKey.OP_WRITE) { + //only timeout sockets that we are waiting for a read from - or write (send file) long delta = now - ka.getLastAccess(); long timeout = (ka.getTimeout()==-1)?((long) socketProperties.getSoTimeout()):(ka.getTimeout()); boolean isTimedout = delta > timeout; Modified: tomcat/tc6.0.x/trunk/java/org/apache/tomcat/util/net/SecureNioChannel.java URL: http://svn.apache.org/viewvc/tomcat/tc6.0.x/trunk/java/org/apache/tomcat/util/net/SecureNioChannel.java?rev=734574&r1=734573&r2=734574&view=diff ============================================================================== --- tomcat/tc6.0.x/trunk/java/org/apache/tomcat/util/net/SecureNioChannel.java (original) +++ tomcat/tc6.0.x/trunk/java/org/apache/tomcat/util/net/SecureNioChannel.java Wed Jan 14 16:13:39 2009 @@ -400,7 +400,7 @@ return written; } else { //make sure we can handle expand, and that we only use on buffer - if ( src != bufHandler.getWriteBuffer() ) throw new IllegalArgumentException("You can only write using the application write buffer provided by the handler."); + if ( (!this.isSendFile()) && (src != bufHandler.getWriteBuffer()) ) throw new IllegalArgumentException("You can only write using the application write buffer provided by the handler."); //are we closing or closed? if ( closing || closed) throw new IOException("Channel is in closing state."); @@ -434,6 +434,20 @@ } } + @Override + public int getOutboundRemaining() { + return netOutBuffer.remaining(); + } + + @Override + public boolean flushOutbound() throws IOException { + int remaining = netOutBuffer.remaining(); + flush(netOutBuffer); + int remaining2= netOutBuffer.remaining(); + return remaining2 < remaining; + } + + /** * Callback interface to be able to expand buffers * when buffer overflow exceptions happen Modified: tomcat/tc6.0.x/trunk/webapps/docs/changelog.xml URL: http://svn.apache.org/viewvc/tomcat/tc6.0.x/trunk/webapps/docs/changelog.xml?rev=734574&r1=734573&r2=734574&view=diff ============================================================================== --- tomcat/tc6.0.x/trunk/webapps/docs/changelog.xml (original) +++ tomcat/tc6.0.x/trunk/webapps/docs/changelog.xml Wed Jan 14 16:13:39 2009 @@ -237,6 +237,9 @@ </subsection> <subsection name="Coyote"> <changelog> + <fix><bug>45154</bug> + Implement SEND_FILE behavior for SSL connections using NIO (fhanik) + </fix> <update> Fix file descriptor leak during NIO send file behavior. (fhanik) </update> --------------------------------------------------------------------- To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org For additional commands, e-mail: dev-h...@tomcat.apache.org