Author: fhanik Date: Thu Mar 22 14:52:25 2007 New Revision: 521487 URL: http://svn.apache.org/viewvc?view=rev&rev=521487 Log: Added in sendfile support for the NIO connector Currently the sending is done on the poller thread, could dispatch to the thread pool as well
Modified: tomcat/tc6.0.x/trunk/java/org/apache/coyote/http11/Http11NioProcessor.java tomcat/tc6.0.x/trunk/java/org/apache/coyote/http11/Http11NioProtocol.java tomcat/tc6.0.x/trunk/java/org/apache/tomcat/util/net/NioEndpoint.java Modified: tomcat/tc6.0.x/trunk/java/org/apache/coyote/http11/Http11NioProcessor.java URL: http://svn.apache.org/viewvc/tomcat/tc6.0.x/trunk/java/org/apache/coyote/http11/Http11NioProcessor.java?view=diff&rev=521487&r1=521486&r2=521487 ============================================================================== --- tomcat/tc6.0.x/trunk/java/org/apache/coyote/http11/Http11NioProcessor.java (original) +++ tomcat/tc6.0.x/trunk/java/org/apache/coyote/http11/Http11NioProcessor.java Thu Mar 22 14:52:25 2007 @@ -52,6 +52,7 @@ import org.apache.tomcat.util.net.SocketStatus; import org.apache.tomcat.util.net.NioEndpoint.Handler.SocketState; import org.apache.tomcat.util.res.StringManager; +import org.apache.tomcat.util.net.NioEndpoint.KeyAttachment; /** @@ -173,7 +174,10 @@ */ protected boolean http09 = false; - + /** + * Sendfile data. + */ + protected NioEndpoint.SendfileData sendfileData = null; /** * Comet used. @@ -926,6 +930,17 @@ response.setStatus(500); } request.updateCounters(); + + // Do sendfile as needed: add socket to sendfile and end + if (sendfileData != null && !error) { + KeyAttachment ka = (KeyAttachment)socket.getAttachment(false); + ka.setSendfileData(sendfileData); + sendfileData.keepAlive = keepAlive; + endpoint.getPoller0().add(socket,SelectionKey.OP_WRITE); + openSocket = true; + break; + } + rp.setStage(org.apache.coyote.Constants.STAGE_KEEPALIVE); @@ -1249,6 +1264,7 @@ http09 = false; contentDelimitation = false; expectation = false; + sendfileData = null; if (ssl) { request.scheme().setString("https"); } @@ -1410,6 +1426,9 @@ contentDelimitation = true; } + // Advertise sendfile support through a request attribute + if (endpoint.getUseSendfile()) + request.setAttribute("org.apache.tomcat.sendfile.support", Boolean.TRUE); // Advertise comet support through a request attribute request.setAttribute("org.apache.tomcat.comet.support", Boolean.TRUE); // Advertise comet timeout support @@ -1585,11 +1604,26 @@ (outputFilters[Constants.VOID_FILTER]); contentDelimitation = true; } + + // Sendfile support + if (this.endpoint.getUseSendfile()) { + String fileName = (String) request.getAttribute("org.apache.tomcat.sendfile.filename"); + if (fileName != null) { + // No entity body sent here + outputBuffer.addActiveFilter(outputFilters[Constants.VOID_FILTER]); + contentDelimitation = true; + sendfileData = new NioEndpoint.SendfileData(); + sendfileData.fileName = fileName; + sendfileData.pos = ((Long) request.getAttribute("org.apache.tomcat.sendfile.start")).longValue(); + sendfileData.length = ((Long) request.getAttribute("org.apache.tomcat.sendfile.end")).longValue() - sendfileData.pos; + } + } + // Check for compression boolean useCompression = false; - if (entityBody && (compressionLevel > 0)) { + if (entityBody && (compressionLevel > 0) && (sendfileData == null)) { useCompression = isCompressable(); // Change content-length to -1 to force chunking if (useCompression) { 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?view=diff&rev=521487&r1=521486&r2=521487 ============================================================================== --- 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 Thu Mar 22 14:52:25 2007 @@ -298,6 +298,15 @@ } + public boolean getUseSendfile() { + return ep.getUseSendfile(); + } + + public void setUseSendfile(boolean useSendfile) { + ep.setUseSendfile(useSendfile); + } + + // -------------------- Tcp setup -------------------- public int getBacklog() { 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?view=diff&rev=521487&r1=521486&r2=521487 ============================================================================== --- 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 Thu Mar 22 14:52:25 2007 @@ -24,16 +24,25 @@ import java.net.Socket; import java.nio.ByteBuffer; import java.nio.channels.CancelledKeyException; +import java.nio.channels.FileChannel; import java.nio.channels.SelectionKey; import java.nio.channels.Selector; import java.nio.channels.ServerSocketChannel; import java.nio.channels.SocketChannel; import java.security.KeyStore; +import java.util.Collection; +import java.util.Comparator; import java.util.Iterator; import java.util.Set; import java.util.StringTokenizer; import java.util.concurrent.ConcurrentLinkedQueue; +import java.util.concurrent.CountDownLatch; import java.util.concurrent.Executor; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.ThreadFactory; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicLong; import javax.net.ssl.KeyManagerFactory; import javax.net.ssl.SSLContext; @@ -45,14 +54,7 @@ import org.apache.tomcat.util.IntrospectionUtils; import org.apache.tomcat.util.net.SecureNioChannel.ApplicationBufferHandler; import org.apache.tomcat.util.res.StringManager; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.concurrent.CountDownLatch; -import java.util.Comparator; -import java.util.concurrent.ThreadPoolExecutor; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.LinkedBlockingQueue; -import java.util.Collection; -import java.util.concurrent.ThreadFactory; +import java.io.File; /** * NIO tailored thread pool, providing the following services: @@ -154,7 +156,13 @@ * Server socket "pointer". */ protected ServerSocketChannel serverSock = null; - + + /** + * use send file + */ + private boolean useSendfile = true; + + /** * Cache for SocketProcessor objects */ @@ -574,6 +582,11 @@ this.socketProperties = socketProperties; } + public void setUseSendfile(boolean useSendfile) { + + this.useSendfile = useSendfile; + } + protected SSLContext sslContext = null; public SSLContext getSSLContext() { return sslContext;} public void setSSLContext(SSLContext c) { sslContext = c;} @@ -655,7 +668,7 @@ serverSock.socket().bind(addr,backlog); serverSock.configureBlocking(true); //mimic APR behavior - // Initialize thread count defaults for acceptor, poller and sendfile + // Initialize thread count defaults for acceptor, poller if (acceptorThreadCount == 0) { // FIXME: Doesn't seem to work that well with multiple accept threads acceptorThreadCount = 1; @@ -832,6 +845,11 @@ return socketProperties; } + public boolean getUseSendfile() { + + return useSendfile; + } + /** * Unlock the server socket accept using a bogus connection. */ @@ -1387,7 +1405,9 @@ sk.attach(attachment);//cant remember why this is here NioChannel channel = attachment.getChannel(); if (sk.isReadable() || sk.isWritable() ) { - if ( attachment.getComet() ) { + if ( attachment.getSendfileData() != null ) { + processSendfile(sk,attachment); + } else if ( attachment.getComet() ) { //check if thread is available if ( isWorkerAvailable() ) { unreg(sk, attachment); @@ -1430,12 +1450,48 @@ } return result; } + + protected void processSendfile(SelectionKey sk, KeyAttachment attachment) { + try { + //unreg(sk,attachment);//only do this if we do process send file on a separate thread + SendfileData sd = attachment.getSendfileData(); + if ( sd.fchannel == null ) { + File f = new File(sd.fileName); + if ( !f.exists() ) { + cancelledKey(sk,SocketStatus.ERROR,false); + return; + } + 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; + } + if ( sd.length <= 0 ) { + attachment.setSendfileData(null); + if ( sd.keepAlive ) + reg(sk,attachment,SelectionKey.OP_READ); + else + cancelledKey(sk,SocketStatus.STOP,false); + } + }catch ( Throwable t ) { + log.error("",t); + cancelledKey(sk, SocketStatus.ERROR); + } + } protected void unreg(SelectionKey sk, KeyAttachment attachment) { - sk.interestOps(0); //this is a must, so that we don't have multiple threads messing with the socket - attachment.interestOps(0);//fast access interestp ops + //this is a must, so that we don't have multiple threads messing with the socket + reg(sk,attachment,0); } + protected void reg(SelectionKey sk, KeyAttachment attachment, int intops) { + sk.interestOps(intops); + attachment.interestOps(intops); + } + protected void timeout(int keyCount, boolean hasEvents) { long now = System.currentTimeMillis(); //don't process timeouts too frequently, but if the selector simply timed out @@ -1531,6 +1587,9 @@ public long getLastRegistered() { return lastRegistered; }; public void setLastRegistered(long reg) { lastRegistered = reg; } + public void setSendfileData(SendfileData sf) { this.sendfileData = sf;} + public SendfileData getSendfileData() { return this.sendfileData;} + protected Object mutex = new Object(); protected long lastAccess = -1; protected boolean currentAccess = false; @@ -1541,6 +1600,7 @@ protected CountDownLatch latch = null; protected int fairness = 0; protected long lastRegistered = 0; + protected SendfileData sendfileData = null; } // ----------------------------------------------------- Key Fairness Comparator public static class KeyFairnessComparator implements Comparator<SelectionKey> { @@ -1951,4 +2011,21 @@ return t; } } + + // ----------------------------------------------- SendfileData Inner Class + + + /** + * SendfileData class. + */ + public static class SendfileData { + // File + public String fileName; + public FileChannel fchannel; + public long pos; + public long length; + // KeepAlive flag + public boolean keepAlive; + } + } --------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]