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]

Reply via email to