From dcb1636a7d0aac6092bf7010cc23d67cd425583f Mon Sep 17 00:00:00 2001
From: fhanik selector parameter is null, then it will perform a busy write that could
+ * take up a lot of CPU cycles.
+ * @param buf ByteBuffer - the buffer containing the data, we will write as long as (buf.hasRemaining()==true)
+ * @param socket SocketChannel - the socket to write data to
+ * @param writeTimeout long - the timeout for this write operation in milliseconds, -1 means no timeout
+ * @return int - returns the number of bytes written
+ * @throws EOFException if write returns -1
+ * @throws SocketTimeoutException if the write times out
+ * @throws IOException if an IO Exception occurs in the underlying socket logic
+ */
+ public static int write(ByteBuffer buf, NioChannel socket, long writeTimeout) throws IOException {
+ final SelectionKey key = socket.getIOChannel().keyFor(socket.getPoller().getSelector());
+ int written = 0;
+ boolean timedout = false;
+ int keycount = 1; //assume we can write
+ long time = System.currentTimeMillis(); //start the timeout timer
+ if (socket.getBufHandler().getWriteBuffer() != buf) {
+ socket.getBufHandler().getWriteBuffer().put(buf);
+ buf = socket.getBufHandler().getWriteBuffer();
+ }
+ try {
+ while ( (!timedout) && buf.hasRemaining()) {
+ if (keycount > 0) { //only write if we were registered for a write
+ int cnt = socket.write(buf); //write the data
+ if (cnt == -1)
+ throw new EOFException();
+ written += cnt;
+ if (cnt > 0) {
+ time = System.currentTimeMillis(); //reset our timeout timer
+ continue; //we successfully wrote, try again without a selector
+ }
+ }
+
+ KeyAttachment att = (KeyAttachment) key.attachment();
+ try {
+ att.startLatch(1);
+ socket.getPoller().add(socket,SelectionKey.OP_WRITE);
+ att.getLatch().await(writeTimeout,TimeUnit.MILLISECONDS);
+ }catch (InterruptedException ignore) {
+ }
+ if ( att.getLatch() == null ) keycount = 1;
+ else keycount = 0;
+ if (writeTimeout > 0 && (keycount == 0))
+ timedout = (System.currentTimeMillis() - time) >= writeTimeout;
+ } //while
+ if (timedout)
+ throw new SocketTimeoutException();
+ } finally {
+// if (key != null) {
+// socket.getPoller().addEvent(
+// new Runnable() {
+// public void run() {
+// key.cancel();
+// }
+// });
+// }
+ }
+ return written;
+ }
+
+ /**
+ * Performs a blocking read using the bytebuffer for data to be read
+ * If the selector parameter is null, then it will perform a busy read that could
+ * take up a lot of CPU cycles.
+ * @param buf ByteBuffer - the buffer containing the data, we will read as until we have read at least one byte or we timed out
+ * @param socket SocketChannel - the socket to write data to
+ * @param selector Selector - the selector to use for blocking, if null then a busy read will be initiated
+ * @param readTimeout long - the timeout for this read operation in milliseconds, -1 means no timeout
+ * @return int - returns the number of bytes read
+ * @throws EOFException if read returns -1
+ * @throws SocketTimeoutException if the read times out
+ * @throws IOException if an IO Exception occurs in the underlying socket logic
+ */
+ public static int read(ByteBuffer buf, NioChannel socket, long readTimeout) throws IOException {
+ final SelectionKey key = socket.getIOChannel().keyFor(socket.getPoller().getSelector());
+ int read = 0;
+ boolean timedout = false;
+ int keycount = 1; //assume we can write
+ long time = System.currentTimeMillis(); //start the timeout timer
+ try {
+ while ( (!timedout) && read == 0) {
+ if (keycount > 0) { //only read if we were registered for a read
+ int cnt = socket.read(buf);
+ if (cnt == -1)
+ throw new EOFException();
+ read += cnt;
+ if (cnt > 0)
+ break;
+ }
+ KeyAttachment att = (KeyAttachment) key.attachment();
+ try {
+ att.startLatch(1);
+ socket.getPoller().add(socket,SelectionKey.OP_READ);
+ att.getLatch().await(readTimeout,TimeUnit.MILLISECONDS);
+ }catch (InterruptedException ignore) {
+ }
+ if ( att.getLatch() == null ) keycount = 1;
+ else keycount = 0;
+ if (readTimeout > 0 && (keycount == 0))
+ timedout = (System.currentTimeMillis() - time) >= readTimeout;
+ } //while
+ if (timedout)
+ throw new SocketTimeoutException();
+ } finally {
+// if (key != null) {
+// socket.getPoller().addEvent(
+// new Runnable() {
+// public void run() {
+// key.cancel();
+// }
+// });
+// }
+ }
+ return read;
+ }
+
+}
\ No newline at end of file
diff --git a/java/org/apache/tomcat/util/net/NioEndpoint.java b/java/org/apache/tomcat/util/net/NioEndpoint.java
index be95ec664..f6f51c5a2 100644
--- a/java/org/apache/tomcat/util/net/NioEndpoint.java
+++ b/java/org/apache/tomcat/util/net/NioEndpoint.java
@@ -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 ConcurrentLinkedQueueselector 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 selector 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;
}
diff --git a/java/org/apache/tomcat/util/net/SocketProperties.java b/java/org/apache/tomcat/util/net/SocketProperties.java
index 350d218ce..8a2a72622 100644
--- a/java/org/apache/tomcat/util/net/SocketProperties.java
+++ b/java/org/apache/tomcat/util/net/SocketProperties.java
@@ -1,245 +1,306 @@
-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 soLingerTime 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;
- }
-
+/*
+ * Copyright 2005-2006 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.tomcat.util.net;
+
+import java.net.Socket;
+import java.net.SocketException;
+/**
+ * Properties that can be set in the <Connector> element
+ * in server.xml. All properties are prefixed with "socket."
+ * and are currently only working for the Nio connector
+ *
+ * @author Filip Hanik
+ */
+public class SocketProperties {
+ /**
+ * Enable/disable key cache, this bounced cache stores
+ * KeyAttachment objects to reduce GC
+ * Default is 100
+ * -1 is unlimited
+ * 0 is disabled
+ */
+ protected int keyCache = 500;
+
+ /**
+ * Enable/disable poller event cache, this bounded cache stores
+ * PollerEvent objects to reduce GC for the poller
+ * Default is -1 (unlimited)
+ * -1 is unlimited
+ * 0 is disabled
+ * >0 the max number of objects to keep in cache.
+ */
+ protected int eventCache = -1;
+
+
+ /**
+ * 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 soLingerTime 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;
+ private Socket properties;
+
+ 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 getEventCache() {
+ return eventCache;
+ }
+
+ public int getKeyCache() {
+ return keyCache;
+ }
+
+ public Socket getProperties() {
+ return properties;
+ }
+
+ 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 setEventCache(int eventCache) {
+ this.eventCache = eventCache;
+ }
+
+ public void setKeyCache(int keyCache) {
+ this.keyCache = keyCache;
+ }
+
+ public void setDirectBufferPool(int directBufferPool) {
+ this.bufferPool = directBufferPool;
+ }
+
}
\ No newline at end of file
diff --git a/webapps/docs/changelog.xml b/webapps/docs/changelog.xml
index 6691e6101..0113b62f1 100644
--- a/webapps/docs/changelog.xml
+++ b/webapps/docs/changelog.xml
@@ -14,6 +14,20 @@
+-Dorg.apache.tomcat.util.net.NioSelectorShared=true
+
Document TBD + Other values are -1. unlimited cache, and 0, no cache.
+Document TBD + Other values are -1. unlimited cache, and 0, no cache.
+same as the standard setting tcpNoDelay. Default value is false