Fix (may not be complete yet) to the memory leak in the NIO connector.
authorfhanik <fhanik@13f79535-47bb-0310-9956-ffa450edef68>
Tue, 20 Feb 2007 23:59:05 +0000 (23:59 +0000)
committerfhanik <fhanik@13f79535-47bb-0310-9956-ffa450edef68>
Tue, 20 Feb 2007 23:59:05 +0000 (23:59 +0000)
The caches where holding references they aren't supposed to hold.
Added in the ability to use the pollers selector (share a selector) instead of each thread
using one from the selector pool. Selector pools can be very resource intensive.

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

java/org/apache/tomcat/util/net/NioBlockingSelector.java [new file with mode: 0644]
java/org/apache/tomcat/util/net/NioEndpoint.java
java/org/apache/tomcat/util/net/NioSelectorPool.java
java/org/apache/tomcat/util/net/SocketProperties.java
webapps/docs/changelog.xml
webapps/docs/config/http.xml

diff --git a/java/org/apache/tomcat/util/net/NioBlockingSelector.java b/java/org/apache/tomcat/util/net/NioBlockingSelector.java
new file mode 100644 (file)
index 0000000..e046caa
--- /dev/null
@@ -0,0 +1,149 @@
+/*\r
+ *  Copyright 2005-2006 The Apache Software Foundation\r
+ *\r
+ *  Licensed under the Apache License, Version 2.0 (the "License");\r
+ *  you may not use this file except in compliance with the License.\r
+ *  You may obtain a copy of the License at\r
+ *\r
+ *      http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ *  Unless required by applicable law or agreed to in writing, software\r
+ *  distributed under the License is distributed on an "AS IS" BASIS,\r
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ *  See the License for the specific language governing permissions and\r
+ *  limitations under the License.\r
+ */\r
+package org.apache.tomcat.util.net;\r
+\r
+import java.io.EOFException;\r
+import java.io.IOException;\r
+import java.net.SocketTimeoutException;\r
+import java.nio.ByteBuffer;\r
+import java.nio.channels.SelectionKey;\r
+import java.util.concurrent.TimeUnit;\r
+\r
+import org.apache.tomcat.util.net.NioEndpoint.KeyAttachment;\r
+\r
+public class NioBlockingSelector {\r
+    public NioBlockingSelector() {\r
+    }\r
+\r
+    /**\r
+     * Performs a blocking write using the bytebuffer for data to be written\r
+     * If the <code>selector</code> parameter is null, then it will perform a busy write that could\r
+     * take up a lot of CPU cycles.\r
+     * @param buf ByteBuffer - the buffer containing the data, we will write as long as <code>(buf.hasRemaining()==true)</code>\r
+     * @param socket SocketChannel - the socket to write data to\r
+     * @param writeTimeout long - the timeout for this write operation in milliseconds, -1 means no timeout\r
+     * @return int - returns the number of bytes written\r
+     * @throws EOFException if write returns -1\r
+     * @throws SocketTimeoutException if the write times out\r
+     * @throws IOException if an IO Exception occurs in the underlying socket logic\r
+     */\r
+    public static int write(ByteBuffer buf, NioChannel socket, long writeTimeout) throws IOException {\r
+        final SelectionKey key = socket.getIOChannel().keyFor(socket.getPoller().getSelector());\r
+        int written = 0;\r
+        boolean timedout = false;\r
+        int keycount = 1; //assume we can write\r
+        long time = System.currentTimeMillis(); //start the timeout timer\r
+        if (socket.getBufHandler().getWriteBuffer() != buf) {\r
+            socket.getBufHandler().getWriteBuffer().put(buf);\r
+            buf = socket.getBufHandler().getWriteBuffer();\r
+        }\r
+        try {\r
+            while ( (!timedout) && buf.hasRemaining()) {\r
+                if (keycount > 0) { //only write if we were registered for a write\r
+                    int cnt = socket.write(buf); //write the data\r
+                    if (cnt == -1)\r
+                        throw new EOFException();\r
+                    written += cnt;\r
+                    if (cnt > 0) {\r
+                        time = System.currentTimeMillis(); //reset our timeout timer\r
+                        continue; //we successfully wrote, try again without a selector\r
+                    }\r
+                }\r
+                \r
+                KeyAttachment att = (KeyAttachment) key.attachment();\r
+                try {\r
+                    att.startLatch(1);\r
+                    socket.getPoller().add(socket,SelectionKey.OP_WRITE);\r
+                    att.getLatch().await(writeTimeout,TimeUnit.MILLISECONDS);\r
+                }catch (InterruptedException ignore) {\r
+                }\r
+                if ( att.getLatch() == null ) keycount = 1;\r
+                else keycount = 0;\r
+                if (writeTimeout > 0 && (keycount == 0))\r
+                    timedout = (System.currentTimeMillis() - time) >= writeTimeout;\r
+            } //while\r
+            if (timedout) \r
+                throw new SocketTimeoutException();\r
+        } finally {\r
+//            if (key != null) {\r
+//                socket.getPoller().addEvent(\r
+//                    new Runnable() {\r
+//                    public void run() {\r
+//                        key.cancel();\r
+//                    }\r
+//                });\r
+//            }\r
+        }\r
+        return written;\r
+    }\r
+\r
+    /**\r
+     * Performs a blocking read using the bytebuffer for data to be read\r
+     * If the <code>selector</code> parameter is null, then it will perform a busy read that could\r
+     * take up a lot of CPU cycles.\r
+     * @param buf ByteBuffer - the buffer containing the data, we will read as until we have read at least one byte or we timed out\r
+     * @param socket SocketChannel - the socket to write data to\r
+     * @param selector Selector - the selector to use for blocking, if null then a busy read will be initiated\r
+     * @param readTimeout long - the timeout for this read operation in milliseconds, -1 means no timeout\r
+     * @return int - returns the number of bytes read\r
+     * @throws EOFException if read returns -1\r
+     * @throws SocketTimeoutException if the read times out\r
+     * @throws IOException if an IO Exception occurs in the underlying socket logic\r
+     */\r
+    public static int read(ByteBuffer buf, NioChannel socket, long readTimeout) throws IOException {\r
+        final SelectionKey key = socket.getIOChannel().keyFor(socket.getPoller().getSelector());\r
+        int read = 0;\r
+        boolean timedout = false;\r
+        int keycount = 1; //assume we can write\r
+        long time = System.currentTimeMillis(); //start the timeout timer\r
+        try {\r
+            while ( (!timedout) && read == 0) {\r
+                if (keycount > 0) { //only read if we were registered for a read\r
+                    int cnt = socket.read(buf);\r
+                    if (cnt == -1)\r
+                        throw new EOFException();\r
+                    read += cnt;\r
+                    if (cnt > 0)\r
+                        break;\r
+                }\r
+                KeyAttachment att = (KeyAttachment) key.attachment();\r
+                try {\r
+                    att.startLatch(1);\r
+                    socket.getPoller().add(socket,SelectionKey.OP_READ);\r
+                    att.getLatch().await(readTimeout,TimeUnit.MILLISECONDS);\r
+                }catch (InterruptedException ignore) {\r
+                }\r
+                if ( att.getLatch() == null ) keycount = 1;\r
+                else keycount = 0;\r
+                if (readTimeout > 0 && (keycount == 0))\r
+                    timedout = (System.currentTimeMillis() - time) >= readTimeout;\r
+            } //while\r
+            if (timedout)\r
+                throw new SocketTimeoutException();\r
+        } finally {\r
+//            if (key != null) {\r
+//                socket.getPoller().addEvent(\r
+//                    new Runnable() {\r
+//                    public void run() {\r
+//                        key.cancel();\r
+//                    }\r
+//                });\r
+//            }\r
+        }\r
+        return read;\r
+    }\r
+\r
+}
\ No newline at end of file
index be95ec6..f6f51c5 100644 (file)
@@ -46,6 +46,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;
 
 /**
  * NIO tailored thread pool, providing the following services:
@@ -150,12 +151,70 @@ public class NioEndpoint {
     /**
      * Cache for key attachment objects
      */
-    protected ConcurrentLinkedQueue<KeyAttachment> keyCache = new ConcurrentLinkedQueue<KeyAttachment>();
+    protected ConcurrentLinkedQueue<KeyAttachment> keyCache = new ConcurrentLinkedQueue<KeyAttachment>() {
+        protected AtomicInteger size = new AtomicInteger(0);
+        public boolean offer(KeyAttachment ka) {
+            ka.reset();
+            boolean offer = socketProperties.getKeyCache()==-1?true:size.get()<socketProperties.getKeyCache();
+            //avoid over growing our cache or add after we have stopped
+            if ( running && (!paused) && (offer) ) {
+                boolean result = super.offer(ka);
+                if ( result ) {
+                    size.incrementAndGet();
+                }
+                return result;
+            }
+            else return false;
+        }
+
+        public KeyAttachment poll() {
+            KeyAttachment result = super.poll();
+            if ( result != null ) {
+                size.decrementAndGet();
+            }
+            return result;
+        }
+
+        public void clear() {
+            super.clear();
+            size.set(0);
+        }
+    };
+
     
     /**
      * Cache for poller events
      */
-    protected ConcurrentLinkedQueue<PollerEvent> eventCache = new ConcurrentLinkedQueue<PollerEvent>();
+    protected ConcurrentLinkedQueue<PollerEvent> eventCache = new ConcurrentLinkedQueue<PollerEvent>() {
+        protected AtomicInteger size = new AtomicInteger(0);
+        public boolean offer(PollerEvent pe) {
+            pe.reset();
+            boolean offer = socketProperties.getEventCache()==-1?true:size.get()<socketProperties.getEventCache();
+            //avoid over growing our cache or add after we have stopped
+            if ( running && (!paused) && (offer) ) {
+                boolean result = super.offer(pe);
+                if ( result ) {
+                    size.incrementAndGet();
+                }
+                return result;
+            }
+            else return false;
+        }
+
+        public PollerEvent poll() {
+            PollerEvent result = super.poll();
+            if ( result != null ) {
+                size.decrementAndGet();
+            }
+            return result;
+        }
+
+        public void clear() {
+            super.clear();
+            size.set(0);
+        }
+    };
+
 
     /**
      * Bytebuffer cache, each channel holds a set of buffers (two, except for SSL holds four)
@@ -163,7 +222,7 @@ public class NioEndpoint {
     protected ConcurrentLinkedQueue<NioChannel> nioChannels = new ConcurrentLinkedQueue<NioChannel>() {
         protected AtomicInteger size = new AtomicInteger(0);
         protected AtomicInteger bytes = new AtomicInteger(0);
-        public boolean offer(NioChannel socket, KeyAttachment att) {
+        public boolean offer(NioChannel socket) {
             boolean offer = socketProperties.getBufferPool()==-1?true:size.get()<socketProperties.getBufferPool();
             offer = offer && (socketProperties.getBufferPoolSize()==-1?true:(bytes.get()+socket.getBufferSize())<socketProperties.getBufferPoolSize());
             //avoid over growing our cache or add after we have stopped
@@ -190,6 +249,7 @@ public class NioEndpoint {
         public void clear() {
             super.clear();
             size.set(0);
+            bytes.set(0);
         }
     };
 
@@ -1208,6 +1268,9 @@ public class NioEndpoint {
                                 if ( attachment.getComet() ) {
                                     if (!processSocket(channel, SocketStatus.OPEN))
                                         processSocket(channel, SocketStatus.DISCONNECT);
+                                } else if ( attachment.getLatch() != null ) {
+                                    attachment.getLatch().countDown();
+                                    attachment.resetLatch();
                                 } else {
                                     boolean close = (!processSocket(channel));
                                     if ( close ) {
@@ -1310,6 +1373,12 @@ public class NioEndpoint {
         protected int interestOps = 0;
         public int interestOps() { return interestOps;}
         public int interestOps(int ops) { this.interestOps  = ops; return ops; }
+        public CountDownLatch getLatch() { return latch; }
+        public void resetLatch() { if ( latch.getCount() == 0 ) latch = null; else throw new IllegalStateException("Latch must be at count 0");}
+        public void startLatch(int cnt) { 
+            if ( latch == null || latch.getCount() == 0 ) this.latch = new CountDownLatch(cnt); 
+            else throw new IllegalStateException("Latch must be at count 0 or null.");
+        }
         protected Object mutex = new Object();
         protected long lastAccess = -1;
         protected boolean currentAccess = false;
@@ -1317,6 +1386,7 @@ public class NioEndpoint {
         protected long timeout = -1;
         protected boolean error = false;
         protected NioChannel channel = null;
+        protected CountDownLatch latch = null;
 
     }
 
index cc8a0d7..6e5101c 100644 (file)
@@ -24,9 +24,11 @@ import java.nio.channels.SelectionKey;
 import java.io.EOFException;
 import java.net.SocketTimeoutException;
 import java.util.concurrent.ConcurrentLinkedQueue;
+import org.apache.juli.logging.Log;
+import org.apache.juli.logging.LogFactory;
 
 /**
- * 
+ *
  * Thread safe non blocking selector pool
  * @author Filip Hanik
  * @version 1.0
@@ -34,15 +36,33 @@ import java.util.concurrent.ConcurrentLinkedQueue;
  */
 
 public class NioSelectorPool {
+    protected static Log log = LogFactory.getLog(NioSelectorPool.class);
+
+    protected final static boolean SHARED =
+        Boolean.valueOf(System.getProperty("org.apache.tomcat.util.net.NioSelectorShared", "true")).booleanValue();
+    protected static Selector SHARED_SELECTOR;
+    protected static Selector getSharedSelector() throws IOException {
+        if (SHARED && SHARED_SELECTOR == null) {
+            synchronized ( NioSelectorPool.class ) {
+                if ( SHARED_SELECTOR == null )  {
+                                       SHARED_SELECTOR = Selector.open();
+                    log.info("Using a shared selector for servlet write/read");
+                           }
+            }
+        }
+        return  SHARED_SELECTOR;
+    }
     protected int maxSelectors = 200;
     protected int maxSpareSelectors = -1;
     protected boolean enabled = true;
     protected AtomicInteger active = new AtomicInteger(0);
     protected AtomicInteger spare = new AtomicInteger(0);
-    //protected LinkedList<Selector> selectors = new LinkedList<Selector>();
     protected ConcurrentLinkedQueue<Selector> selectors = new ConcurrentLinkedQueue<Selector>();
-    
+
     public Selector get() throws IOException{
+        if ( SHARED ) {
+            return getSharedSelector();
+        }
         if ( (!enabled) || active.incrementAndGet() >= maxSelectors ) {
             if ( enabled ) active.decrementAndGet();
             return null;
@@ -52,18 +72,19 @@ public class NioSelectorPool {
             s = selectors.size()>0?selectors.poll():null;
             if (s == null) s = Selector.open();
             else spare.decrementAndGet();
-            
+
         }catch (NoSuchElementException x ) {
             try {s = Selector.open();}catch (IOException iox){}
         } finally {
             if ( s == null ) active.decrementAndGet();//we were unable to find a selector
         }
-        return s;            
+        return s;
     }
-    
-    
-    
+
+
+
     public void put(Selector s) throws IOException {
+        if ( SHARED ) return;
         if ( enabled ) active.decrementAndGet();
         if ( enabled && (maxSpareSelectors==-1 || spare.get() < Math.min(maxSpareSelectors,maxSelectors)) ) {
             spare.incrementAndGet();
@@ -71,19 +92,24 @@ public class NioSelectorPool {
         }
         else s.close();
     }
-    
+
     public void close() throws IOException {
         enabled = false;
         Selector s;
         while ( (s = selectors.poll()) != null ) s.close();
         spare.set(0);
         active.set(0);
+        if ( SHARED && getSharedSelector()!=null ) {
+            getSharedSelector().close();
+            SHARED_SELECTOR = null;
+        }
     }
-    
-    public void open(){
+
+    public void open() throws IOException {
         enabled = true;
+        getSharedSelector();
     }
-    
+
     /**
      * Performs a blocking write using the bytebuffer for data to be written and a selector to block.
      * If the <code>selector</code> parameter is null, then it will perform a busy write that could
@@ -98,6 +124,9 @@ public class NioSelectorPool {
      * @throws IOException if an IO Exception occurs in the underlying socket logic
      */
     public int write(ByteBuffer buf, NioChannel socket, Selector selector, long writeTimeout) throws IOException {
+        if ( SHARED ) {
+            return NioBlockingSelector.write(buf,socket,writeTimeout);
+        }
         SelectionKey key = null;
         int written = 0;
         boolean timedout = false;
@@ -123,7 +152,7 @@ public class NioSelectorPool {
                     if (key==null) key = socket.getIOChannel().register(selector, SelectionKey.OP_WRITE);
                     else key.interestOps(SelectionKey.OP_WRITE);
                     keycount = selector.select(writeTimeout);
-                }                
+                }
                 if (writeTimeout > 0 && (selector == null || keycount == 0) ) timedout = (System.currentTimeMillis()-time)>=writeTimeout;
             }//while
             if ( timedout ) throw new SocketTimeoutException();
@@ -135,7 +164,7 @@ public class NioSelectorPool {
         }
         return written;
     }
-     
+
     /**
      * Performs a blocking read using the bytebuffer for data to be read and a selector to block.
      * If the <code>selector</code> parameter is null, then it will perform a busy read that could
@@ -150,6 +179,9 @@ public class NioSelectorPool {
      * @throws IOException if an IO Exception occurs in the underlying socket logic
      */
     public int read(ByteBuffer buf, NioChannel socket, Selector selector, long readTimeout) throws IOException {
+        if ( SHARED ) {
+            return NioBlockingSelector.read(buf,socket,readTimeout);
+        }
         SelectionKey key = null;
         int read = 0;
         boolean timedout = false;
@@ -168,7 +200,7 @@ public class NioSelectorPool {
                     if (key==null) key = socket.getIOChannel().register(selector, SelectionKey.OP_READ);
                     else key.interestOps(SelectionKey.OP_READ);
                     keycount = selector.select(readTimeout);
-                }                
+                }
                 if (readTimeout > 0 && (selector == null || keycount == 0) ) timedout = (System.currentTimeMillis()-time)>=readTimeout;
             }//while
             if ( timedout ) throw new SocketTimeoutException();
@@ -180,7 +212,7 @@ public class NioSelectorPool {
         }
         return read;
     }
-    
+
     public void setMaxSelectors(int maxSelectors) {
         this.maxSelectors = maxSelectors;
     }
index 350d218..8a2a726 100644 (file)
-package org.apache.tomcat.util.net;
-
-import java.net.Socket;
-import java.net.SocketException;
-
-public class SocketProperties {
-    /**
-     * Enable/disable direct buffers for the network buffers
-     * Default value is enabled
-     */
-    protected boolean directBuffer = true;
-    /**
-     * Socket receive buffer size in bytes (SO_RCVBUF)
-     * Default value is 25188
-     */
-    protected int rxBufSize = 25188;
-    /**
-     * Socket send buffer size in bytes (SO_SNDBUF)
-     * Default value is 43800
-     */
-    protected int txBufSize = 43800;
-    
-    /**
-     * NioChannel pool size for the endpoint,
-     * this value is how many channels
-     * -1 means unlimited cached, 0 means no cache
-     * Default value is 500
-     */
-    protected int bufferPool = 500;
-    
-
-    /**
-     * Buffer pool size in bytes to be cached
-     * -1 means unlimited, 0 means no cache
-     * Default value is 100MB (1024*1024*100 bytes)
-     */
-    protected int bufferPoolSize = 1024*1024*100;
-    
-    /**
-     * TCP_NO_DELAY option, default is true
-     */
-    protected boolean tcpNoDelay = true;
-    /**
-     * SO_KEEPALIVE option, default is false
-     */
-    protected boolean soKeepAlive = false;
-    /**
-     * OOBINLINE option, default is true
-     */
-    protected boolean ooBInline = true;
-    /**
-     * SO_REUSEADDR option, default is true
-     */
-    protected boolean soReuseAddress = true;
-    /**
-     * SO_LINGER option, default is true, paired with the <code>soLingerTime</code> value
-     */
-    protected boolean soLingerOn = true;
-    /**
-     * SO_LINGER option, default is 25 seconds.
-     */
-    protected int soLingerTime = 25;
-    /**
-     * SO_TIMEOUT option, default is 5000 milliseconds
-     */
-    protected int soTimeout = 5000;
-    /**
-     * Traffic class option, value between 0 and 255
-     * IPTOS_LOWCOST (0x02)
-     * IPTOS_RELIABILITY (0x04)
-     * IPTOS_THROUGHPUT (0x08)
-     * IPTOS_LOWDELAY (0x10)
-     * Default value is 0x04 | 0x08 | 0x010
-     */
-    protected int soTrafficClass = 0x04 | 0x08 | 0x010;
-    /**
-     * Performance preferences according to
-     * http://java.sun.com/j2se/1.5.0/docs/api/java/net/Socket.html#setPerformancePreferences(int,%20int,%20int)
-     * Default value is 1
-     */
-    protected int performanceConnectionTime = 1;
-    /**
-     * Performance preferences according to
-     * http://java.sun.com/j2se/1.5.0/docs/api/java/net/Socket.html#setPerformancePreferences(int,%20int,%20int)
-     * Default value is 0
-     */
-    protected int performanceLatency = 0;
-    /**
-     * Performance preferences according to
-     * http://java.sun.com/j2se/1.5.0/docs/api/java/net/Socket.html#setPerformancePreferences(int,%20int,%20int)
-     * Default value is 1
-     */
-    protected int performanceBandwidth = 1;
-    
-
-    public void setProperties(Socket socket) throws SocketException{
-        socket.setReceiveBufferSize(rxBufSize);
-        socket.setSendBufferSize(txBufSize);
-        socket.setOOBInline(ooBInline);
-        socket.setKeepAlive(soKeepAlive);
-        socket.setPerformancePreferences(performanceConnectionTime,performanceLatency,performanceBandwidth);
-        socket.setReuseAddress(soReuseAddress);
-        socket.setSoLinger(soLingerOn,soLingerTime);
-        socket.setSoTimeout(soTimeout);
-        socket.setTcpNoDelay(tcpNoDelay);
-        socket.setTrafficClass(soTrafficClass);
-    }
-
-    public boolean getDirectBuffer() {
-        return directBuffer;
-    }
-
-    public boolean getOoBInline() {
-        return ooBInline;
-    }
-
-    public int getPerformanceBandwidth() {
-        return performanceBandwidth;
-    }
-
-    public int getPerformanceConnectionTime() {
-        return performanceConnectionTime;
-    }
-
-    public int getPerformanceLatency() {
-        return performanceLatency;
-    }
-
-    public int getRxBufSize() {
-        return rxBufSize;
-    }
-
-    public boolean getSoKeepAlive() {
-        return soKeepAlive;
-    }
-
-    public boolean getSoLingerOn() {
-        return soLingerOn;
-    }
-
-    public int getSoLingerTime() {
-        return soLingerTime;
-    }
-
-    public boolean getSoReuseAddress() {
-        return soReuseAddress;
-    }
-
-    public int getSoTimeout() {
-        return soTimeout;
-    }
-
-    public int getSoTrafficClass() {
-        return soTrafficClass;
-    }
-
-    public boolean getTcpNoDelay() {
-        return tcpNoDelay;
-    }
-
-    public int getTxBufSize() {
-        return txBufSize;
-    }
-
-    public int getBufferPool() {
-        return bufferPool;
-    }
-
-    public int getBufferPoolSize() {
-        return bufferPoolSize;
-    }
-
-    public int getDirectBufferPool() {
-        return bufferPool;
-    }
-
-    public void setPerformanceConnectionTime(int performanceConnectionTime) {
-        this.performanceConnectionTime = performanceConnectionTime;
-    }
-
-    public void setTxBufSize(int txBufSize) {
-        this.txBufSize = txBufSize;
-    }
-
-    public void setTcpNoDelay(boolean tcpNoDelay) {
-        this.tcpNoDelay = tcpNoDelay;
-    }
-
-    public void setSoTrafficClass(int soTrafficClass) {
-        this.soTrafficClass = soTrafficClass;
-    }
-
-    public void setSoTimeout(int soTimeout) {
-        this.soTimeout = soTimeout;
-    }
-
-    public void setSoReuseAddress(boolean soReuseAddress) {
-        this.soReuseAddress = soReuseAddress;
-    }
-
-    public void setSoLingerTime(int soLingerTime) {
-        this.soLingerTime = soLingerTime;
-    }
-
-    public void setSoKeepAlive(boolean soKeepAlive) {
-        this.soKeepAlive = soKeepAlive;
-    }
-
-    public void setRxBufSize(int rxBufSize) {
-        this.rxBufSize = rxBufSize;
-    }
-
-    public void setPerformanceLatency(int performanceLatency) {
-        this.performanceLatency = performanceLatency;
-    }
-
-    public void setPerformanceBandwidth(int performanceBandwidth) {
-        this.performanceBandwidth = performanceBandwidth;
-    }
-
-    public void setOoBInline(boolean ooBInline) {
-        this.ooBInline = ooBInline;
-    }
-
-    public void setDirectBuffer(boolean directBuffer) {
-        this.directBuffer = directBuffer;
-    }
-
-    public void setSoLingerOn(boolean soLingerOn) {
-        this.soLingerOn = soLingerOn;
-    }
-
-    public void setBufferPool(int bufferPool) {
-        this.bufferPool = bufferPool;
-    }
-
-    public void setBufferPoolSize(int bufferPoolSize) {
-        this.bufferPoolSize = bufferPoolSize;
-    }
-
-    public void setDirectBufferPool(int directBufferPool) {
-        this.bufferPool = directBufferPool;
-    }
-
+/*\r
+ *  Copyright 2005-2006 The Apache Software Foundation\r
+ *\r
+ *  Licensed under the Apache License, Version 2.0 (the "License");\r
+ *  you may not use this file except in compliance with the License.\r
+ *  You may obtain a copy of the License at\r
+ *\r
+ *      http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ *  Unless required by applicable law or agreed to in writing, software\r
+ *  distributed under the License is distributed on an "AS IS" BASIS,\r
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ *  See the License for the specific language governing permissions and\r
+ *  limitations under the License.\r
+ */\r
+package org.apache.tomcat.util.net;\r
+\r
+import java.net.Socket;\r
+import java.net.SocketException;\r
+/**\r
+ * Properties that can be set in the &lt;Connector&gt; element \r
+ * in server.xml. All properties are prefixed with &quot;socket.&quot;\r
+ * and are currently only working for the Nio connector\r
+ * \r
+ * @author Filip Hanik\r
+ */\r
+public class SocketProperties {\r
+    /**\r
+     * Enable/disable key cache, this bounced cache stores \r
+     * KeyAttachment objects to reduce GC\r
+     * Default is 100\r
+     * -1 is unlimited\r
+     * 0 is disabled\r
+     */\r
+    protected int keyCache = 500;\r
+    \r
+    /**\r
+     * Enable/disable poller event cache, this bounded cache stores \r
+     * PollerEvent objects to reduce GC for the poller\r
+     * Default is -1 (unlimited)\r
+     * -1 is unlimited\r
+     * 0 is disabled\r
+     * >0 the max number of objects to keep in cache.\r
+     */\r
+    protected int eventCache = -1;\r
+    \r
+\r
+    /**\r
+     * Enable/disable direct buffers for the network buffers\r
+     * Default value is enabled\r
+     */\r
+    protected boolean directBuffer = true;\r
+    /**\r
+     * Socket receive buffer size in bytes (SO_RCVBUF)\r
+     * Default value is 25188\r
+     */\r
+    protected int rxBufSize = 25188;\r
+    /**\r
+     * Socket send buffer size in bytes (SO_SNDBUF)\r
+     * Default value is 43800\r
+     */\r
+    protected int txBufSize = 43800;\r
+    \r
+    /**\r
+     * NioChannel pool size for the endpoint,\r
+     * this value is how many channels\r
+     * -1 means unlimited cached, 0 means no cache\r
+     * Default value is 500\r
+     */\r
+    protected int bufferPool = 500;\r
+    \r
+\r
+    /**\r
+     * Buffer pool size in bytes to be cached\r
+     * -1 means unlimited, 0 means no cache\r
+     * Default value is 100MB (1024*1024*100 bytes)\r
+     */\r
+    protected int bufferPoolSize = 1024*1024*100;\r
+    \r
+    /**\r
+     * TCP_NO_DELAY option, default is true\r
+     */\r
+    protected boolean tcpNoDelay = true;\r
+    /**\r
+     * SO_KEEPALIVE option, default is false\r
+     */\r
+    protected boolean soKeepAlive = false;\r
+    /**\r
+     * OOBINLINE option, default is true\r
+     */\r
+    protected boolean ooBInline = true;\r
+    /**\r
+     * SO_REUSEADDR option, default is true\r
+     */\r
+    protected boolean soReuseAddress = true;\r
+    /**\r
+     * SO_LINGER option, default is true, paired with the <code>soLingerTime</code> value\r
+     */\r
+    protected boolean soLingerOn = true;\r
+    /**\r
+     * SO_LINGER option, default is 25 seconds.\r
+     */\r
+    protected int soLingerTime = 25;\r
+    /**\r
+     * SO_TIMEOUT option, default is 5000 milliseconds\r
+     */\r
+    protected int soTimeout = 5000;\r
+    /**\r
+     * Traffic class option, value between 0 and 255\r
+     * IPTOS_LOWCOST (0x02)\r
+     * IPTOS_RELIABILITY (0x04)\r
+     * IPTOS_THROUGHPUT (0x08)\r
+     * IPTOS_LOWDELAY (0x10)\r
+     * Default value is 0x04 | 0x08 | 0x010\r
+     */\r
+    protected int soTrafficClass = 0x04 | 0x08 | 0x010;\r
+    /**\r
+     * Performance preferences according to\r
+     * http://java.sun.com/j2se/1.5.0/docs/api/java/net/Socket.html#setPerformancePreferences(int,%20int,%20int)\r
+     * Default value is 1\r
+     */\r
+    protected int performanceConnectionTime = 1;\r
+    /**\r
+     * Performance preferences according to\r
+     * http://java.sun.com/j2se/1.5.0/docs/api/java/net/Socket.html#setPerformancePreferences(int,%20int,%20int)\r
+     * Default value is 0\r
+     */\r
+    protected int performanceLatency = 0;\r
+    /**\r
+     * Performance preferences according to\r
+     * http://java.sun.com/j2se/1.5.0/docs/api/java/net/Socket.html#setPerformancePreferences(int,%20int,%20int)\r
+     * Default value is 1\r
+     */\r
+    protected int performanceBandwidth = 1;\r
+    private Socket properties;\r
+\r
+    public void setProperties(Socket socket) throws SocketException{\r
+        socket.setReceiveBufferSize(rxBufSize);\r
+        socket.setSendBufferSize(txBufSize);\r
+        socket.setOOBInline(ooBInline);\r
+        socket.setKeepAlive(soKeepAlive);\r
+        socket.setPerformancePreferences(performanceConnectionTime,performanceLatency,performanceBandwidth);\r
+        socket.setReuseAddress(soReuseAddress);\r
+        socket.setSoLinger(soLingerOn,soLingerTime);\r
+        socket.setSoTimeout(soTimeout);\r
+        socket.setTcpNoDelay(tcpNoDelay);\r
+        socket.setTrafficClass(soTrafficClass);\r
+    }\r
+\r
+    public boolean getDirectBuffer() {\r
+        return directBuffer;\r
+    }\r
+\r
+    public boolean getOoBInline() {\r
+        return ooBInline;\r
+    }\r
+\r
+    public int getPerformanceBandwidth() {\r
+        return performanceBandwidth;\r
+    }\r
+\r
+    public int getPerformanceConnectionTime() {\r
+        return performanceConnectionTime;\r
+    }\r
+\r
+    public int getPerformanceLatency() {\r
+        return performanceLatency;\r
+    }\r
+\r
+    public int getRxBufSize() {\r
+        return rxBufSize;\r
+    }\r
+\r
+    public boolean getSoKeepAlive() {\r
+        return soKeepAlive;\r
+    }\r
+\r
+    public boolean getSoLingerOn() {\r
+        return soLingerOn;\r
+    }\r
+\r
+    public int getSoLingerTime() {\r
+        return soLingerTime;\r
+    }\r
+\r
+    public boolean getSoReuseAddress() {\r
+        return soReuseAddress;\r
+    }\r
+\r
+    public int getSoTimeout() {\r
+        return soTimeout;\r
+    }\r
+\r
+    public int getSoTrafficClass() {\r
+        return soTrafficClass;\r
+    }\r
+\r
+    public boolean getTcpNoDelay() {\r
+        return tcpNoDelay;\r
+    }\r
+\r
+    public int getTxBufSize() {\r
+        return txBufSize;\r
+    }\r
+\r
+    public int getBufferPool() {\r
+        return bufferPool;\r
+    }\r
+\r
+    public int getBufferPoolSize() {\r
+        return bufferPoolSize;\r
+    }\r
+\r
+    public int getEventCache() {\r
+        return eventCache;\r
+    }\r
+\r
+    public int getKeyCache() {\r
+        return keyCache;\r
+    }\r
+\r
+    public Socket getProperties() {\r
+        return properties;\r
+    }\r
+\r
+    public int getDirectBufferPool() {\r
+        return bufferPool;\r
+    }\r
+\r
+    public void setPerformanceConnectionTime(int performanceConnectionTime) {\r
+        this.performanceConnectionTime = performanceConnectionTime;\r
+    }\r
+\r
+    public void setTxBufSize(int txBufSize) {\r
+        this.txBufSize = txBufSize;\r
+    }\r
+\r
+    public void setTcpNoDelay(boolean tcpNoDelay) {\r
+        this.tcpNoDelay = tcpNoDelay;\r
+    }\r
+\r
+    public void setSoTrafficClass(int soTrafficClass) {\r
+        this.soTrafficClass = soTrafficClass;\r
+    }\r
+\r
+    public void setSoTimeout(int soTimeout) {\r
+        this.soTimeout = soTimeout;\r
+    }\r
+\r
+    public void setSoReuseAddress(boolean soReuseAddress) {\r
+        this.soReuseAddress = soReuseAddress;\r
+    }\r
+\r
+    public void setSoLingerTime(int soLingerTime) {\r
+        this.soLingerTime = soLingerTime;\r
+    }\r
+\r
+    public void setSoKeepAlive(boolean soKeepAlive) {\r
+        this.soKeepAlive = soKeepAlive;\r
+    }\r
+\r
+    public void setRxBufSize(int rxBufSize) {\r
+        this.rxBufSize = rxBufSize;\r
+    }\r
+\r
+    public void setPerformanceLatency(int performanceLatency) {\r
+        this.performanceLatency = performanceLatency;\r
+    }\r
+\r
+    public void setPerformanceBandwidth(int performanceBandwidth) {\r
+        this.performanceBandwidth = performanceBandwidth;\r
+    }\r
+\r
+    public void setOoBInline(boolean ooBInline) {\r
+        this.ooBInline = ooBInline;\r
+    }\r
+\r
+    public void setDirectBuffer(boolean directBuffer) {\r
+        this.directBuffer = directBuffer;\r
+    }\r
+\r
+    public void setSoLingerOn(boolean soLingerOn) {\r
+        this.soLingerOn = soLingerOn;\r
+    }\r
+\r
+    public void setBufferPool(int bufferPool) {\r
+        this.bufferPool = bufferPool;\r
+    }\r
+\r
+    public void setBufferPoolSize(int bufferPoolSize) {\r
+        this.bufferPoolSize = bufferPoolSize;\r
+    }\r
+\r
+    public void setEventCache(int eventCache) {\r
+        this.eventCache = eventCache;\r
+    }\r
+\r
+    public void setKeyCache(int keyCache) {\r
+        this.keyCache = keyCache;\r
+    }\r
+\r
+    public void setDirectBufferPool(int directBufferPool) {\r
+        this.bufferPool = directBufferPool;\r
+    }\r
+\r
 }
\ No newline at end of file
index 6691e61..0113b62 100644 (file)
   </properties>
 
 <body>
+<section name="Tomcat 6.0.11 (remm)">
+  <subsection name="Coyote">
+    <changelog>
+      <update>
+        Fixed NIO memory leak caused by the NioChannel cache not working properly.
+      </update>
+      <update>
+        Added flag to enable/disable the usage of the pollers selector instead of a Selector pool
+        when the serviet is reading/writing from the input/output streams
+        The flag is <code>-Dorg.apache.tomcat.util.net.NioSelectorShared=true</code>
+      </update>
+    </changelog>  
+  </subsection>
+</section>
 <section name="Tomcat 6.0.10 (remm)">
   <subsection name="Catalina">
     <changelog>
index 6bd0f4a..1cddd27 100644 (file)
         The value is in bytes, the default value is 1024*1024*100 (100MB)
         </p>
       </attribute>
+      <attribute name="socket.keyCache" required="false">
+        <p>Document TBD
+          Other values are -1. unlimited cache, and 0, no cache.</p>
+      </attribute>
+      <attribute name="socket.eventCache" required="false">
+        <p>Document TBD
+          Other values are -1. unlimited cache, and 0, no cache.</p>
+      </attribute>
       <attribute name="socket.tcpNoDelay" required="false">
         <p>same as the standard setting <code>tcpNoDelay</code>. Default value is false</p>
       </attribute>