Author: markt Date: Wed Sep 7 09:06:28 2011 New Revision: 1166072 URL: http://svn.apache.org/viewvc?rev=1166072&view=rev Log: Fix https://issues.apache.org/bugzilla/show_bug.cgi?id=49683 Support separate connection and keep-alive timeouts for the APR/native connector HTTP and AJP connectors.
Modified: tomcat/tc7.0.x/trunk/ (props changed) tomcat/tc7.0.x/trunk/java/org/apache/coyote/ajp/AjpAprProtocol.java tomcat/tc7.0.x/trunk/java/org/apache/coyote/http11/Http11AprProtocol.java tomcat/tc7.0.x/trunk/java/org/apache/tomcat/util/net/AprEndpoint.java tomcat/tc7.0.x/trunk/webapps/docs/changelog.xml Propchange: tomcat/tc7.0.x/trunk/ ------------------------------------------------------------------------------ --- svn:mergeinfo (original) +++ svn:mergeinfo Wed Sep 7 09:06:28 2011 @@ -1 +1 @@ -/tomcat/trunk:1156171,1156276,1156304,1156530,1156602,1157015,1157018,1157151,1157198,1157204,1157810,1157832,1157834,1157847,1157908,1157939,1158155,1158160,1158176,1158195,1158198-1158199,1158227,1158331,1158334-1158335,1160347,1160592,1160611,1160619,1160626,1160639,1160652,1160720-1160721,1160772,1160774,1160776,1161303,1161310,1161322,1161339,1161486,1161540,1161549,1161584,1162082,1162149,1162169,1162721,1162769,1162836,1162932,1163630,1164419,1164438,1164469,1164480,1164567,1165234 +/tomcat/trunk:1156171,1156276,1156304,1156530,1156602,1157015,1157018,1157151,1157198,1157204,1157810,1157832,1157834,1157847,1157908,1157939,1158155,1158160,1158176,1158195,1158198-1158199,1158227,1158331,1158334-1158335,1158426,1160347,1160592,1160611,1160619,1160626,1160639,1160652,1160720-1160721,1160772,1160774,1160776,1161303,1161310,1161322,1161339,1161486,1161540,1161549,1161584,1162082,1162149,1162169,1162721,1162769,1162836,1162932,1163630,1164419,1164438,1164469,1164480,1164567,1165234 Modified: tomcat/tc7.0.x/trunk/java/org/apache/coyote/ajp/AjpAprProtocol.java URL: http://svn.apache.org/viewvc/tomcat/tc7.0.x/trunk/java/org/apache/coyote/ajp/AjpAprProtocol.java?rev=1166072&r1=1166071&r2=1166072&view=diff ============================================================================== --- tomcat/tc7.0.x/trunk/java/org/apache/coyote/ajp/AjpAprProtocol.java (original) +++ tomcat/tc7.0.x/trunk/java/org/apache/coyote/ajp/AjpAprProtocol.java Wed Sep 7 09:06:28 2011 @@ -126,7 +126,7 @@ public class AjpAprProtocol extends Abst recycledProcessors.offer(processor); if (addToPoller) { ((AprEndpoint)proto.endpoint).getPoller().add( - socket.getSocket().longValue()); + socket.getSocket().longValue(), true); } } Modified: tomcat/tc7.0.x/trunk/java/org/apache/coyote/http11/Http11AprProtocol.java URL: http://svn.apache.org/viewvc/tomcat/tc7.0.x/trunk/java/org/apache/coyote/http11/Http11AprProtocol.java?rev=1166072&r1=1166071&r2=1166072&view=diff ============================================================================== --- tomcat/tc7.0.x/trunk/java/org/apache/coyote/http11/Http11AprProtocol.java (original) +++ tomcat/tc7.0.x/trunk/java/org/apache/coyote/http11/Http11AprProtocol.java Wed Sep 7 09:06:28 2011 @@ -217,7 +217,7 @@ public class Http11AprProtocol extends A recycledProcessors.offer(processor); if (addToPoller) { ((AprEndpoint)proto.endpoint).getPoller().add( - socket.getSocket().longValue()); + socket.getSocket().longValue(), true); } } @@ -236,7 +236,7 @@ public class Http11AprProtocol extends A socket.setAsync(true); } else if (processor.comet) { ((AprEndpoint) proto.endpoint).getCometPoller().add( - socket.getSocket().longValue()); + socket.getSocket().longValue(), false); } } Modified: tomcat/tc7.0.x/trunk/java/org/apache/tomcat/util/net/AprEndpoint.java URL: http://svn.apache.org/viewvc/tomcat/tc7.0.x/trunk/java/org/apache/tomcat/util/net/AprEndpoint.java?rev=1166072&r1=1166071&r2=1166072&view=diff ============================================================================== --- tomcat/tc7.0.x/trunk/java/org/apache/tomcat/util/net/AprEndpoint.java (original) +++ tomcat/tc7.0.x/trunk/java/org/apache/tomcat/util/net/AprEndpoint.java Wed Sep 7 09:06:28 2011 @@ -1097,14 +1097,20 @@ public class AprEndpoint extends Abstrac */ public class Poller extends Thread { - protected long serverPollset = 0; - protected long pool = 0; - protected long[] desc; - - protected long[] addS; - protected volatile int addCount = 0; + // Need two pollsets since the socketTimeout and the keep-alive timeout + // can have different values. + private long connectionPollset = 0; + private long keepAlivePollset = 0; + private long pool = 0; + private long[] desc; + + private long[] addSocket; + private boolean[] addSocketKeepAlive; + + private volatile int addCount = 0; - protected boolean comet = true; + private boolean comet = true; + private boolean separateKeepAlive = false; protected volatile int keepAliveCount = 0; public int getKeepAliveCount() { return keepAliveCount; } @@ -1114,28 +1120,41 @@ public class AprEndpoint extends Abstrac } /** - * Create the poller. With some versions of APR, the maximum poller size will - * be 62 (recompiling APR is necessary to remove this limitation). + * Create the poller. With some versions of APR, the maximum poller size + * will be 62 (recompiling APR is necessary to remove this limitation). */ protected void init() { pool = Pool.create(serverSockPool); int size = getMaxConnections() / pollerThreadCount; - int timeout = getKeepAliveTimeout(); - if (timeout <= 0) { - timeout = socketProperties.getSoTimeout(); + int keepAliveTimeout = getKeepAliveTimeout(); + int socketTimeout = socketProperties.getSoTimeout(); + if (keepAliveTimeout > 0 && !comet) { + separateKeepAlive = true; + } + connectionPollset = allocatePoller(size, pool, socketTimeout); + if (separateKeepAlive) { + keepAlivePollset = allocatePoller(size, pool, keepAliveTimeout); } - serverPollset = allocatePoller(size, pool, timeout); - if (serverPollset == 0 && size > 1024) { + if (connectionPollset == 0 && size > 1024) { size = 1024; - serverPollset = allocatePoller(size, pool, timeout); + connectionPollset = allocatePoller(size, pool, socketTimeout); + if (separateKeepAlive) { + keepAlivePollset = + allocatePoller(size, pool, keepAliveTimeout); + } } - if (serverPollset == 0) { + if (connectionPollset == 0) { size = 62; - serverPollset = allocatePoller(size, pool, timeout); + connectionPollset = allocatePoller(size, pool, socketTimeout); + if (separateKeepAlive) { + keepAlivePollset = + allocatePoller(size, pool, keepAliveTimeout); + } } desc = new long[size * 2]; keepAliveCount = 0; - addS = new long[size]; + addSocket = new long[size]; + addSocketKeepAlive = new boolean[size]; addCount = 0; } @@ -1147,21 +1166,15 @@ public class AprEndpoint extends Abstrac // Close all sockets in the add queue for (int i = 0; i < addCount; i++) { if (comet) { - processSocket(addS[i], SocketStatus.STOP); + processSocket(addSocket[i], SocketStatus.STOP); } else { - destroySocket(addS[i]); + destroySocket(addSocket[i]); } } - // Close all sockets still in the poller - int rv = Poll.pollset(serverPollset, desc); - if (rv > 0) { - for (int n = 0; n < rv; n++) { - if (comet) { - processSocket(desc[n*2+1], SocketStatus.STOP); - } else { - destroySocket(desc[n*2+1]); - } - } + // Close all sockets still in the pollers + closePollset(connectionPollset); + if (separateKeepAlive) { + closePollset(keepAlivePollset); } Pool.destroy(pool); keepAliveCount = 0; @@ -1176,6 +1189,19 @@ public class AprEndpoint extends Abstrac } } + private void closePollset(long pollset) { + int rv = Poll.pollset(pollset, desc); + if (rv > 0) { + for (int n = 0; n < rv; n++) { + if (comet) { + processSocket(desc[n*2+1], SocketStatus.STOP); + } else { + destroySocket(desc[n*2+1]); + } + } + } + } + /** * Add specified socket and associated pool to the poller. The socket will * be added to a temporary array, and polled first after a maximum amount @@ -1184,11 +1210,11 @@ public class AprEndpoint extends Abstrac * * @param socket to add to the poller */ - public void add(long socket) { + public void add(long socket, boolean keepAlive) { synchronized (this) { // Add socket to the list. Newly added sockets will wait // at most for pollTime before being polled - if (addCount >= addS.length) { + if (addCount >= addSocket.length) { // Can't do anything: close the socket right away if (comet) { processSocket(socket, SocketStatus.ERROR); @@ -1197,7 +1223,8 @@ public class AprEndpoint extends Abstrac } return; } - addS[addCount] = socket; + addSocket[addCount] = socket; + addSocketKeepAlive[addCount] = keepAlive; addCount++; this.notify(); } @@ -1249,16 +1276,22 @@ public class AprEndpoint extends Abstrac int successCount = 0; try { for (int i = (addCount - 1); i >= 0; i--) { - int rv = Poll.add - (serverPollset, addS[i], Poll.APR_POLLIN); + int rv; + if (separateKeepAlive && addSocketKeepAlive[i]) { + rv = Poll.add(keepAlivePollset, + addSocket[i], Poll.APR_POLLIN); + } else { + rv = Poll.add(connectionPollset, + addSocket[i], Poll.APR_POLLIN); + } if (rv == Status.APR_SUCCESS) { successCount++; } else { // Can't do anything: close the socket right away if (comet) { - processSocket(addS[i], SocketStatus.ERROR); + processSocket(addSocket[i], SocketStatus.ERROR); } else { - destroySocket(addS[i]); + destroySocket(addSocket[i]); } } } @@ -1270,54 +1303,22 @@ public class AprEndpoint extends Abstrac } maintainTime += pollTime; - // Pool for the specified interval - int rv = Poll.poll(serverPollset, pollTime, desc, true); - if (rv > 0) { - keepAliveCount -= rv; - for (int n = 0; n < rv; n++) { - // Check for failed sockets and hand this socket off to a worker - if (((desc[n*2] & Poll.APR_POLLHUP) == Poll.APR_POLLHUP) - || ((desc[n*2] & Poll.APR_POLLERR) == Poll.APR_POLLERR) - || (comet && (!processSocket(desc[n*2+1], SocketStatus.OPEN))) - || (!comet && (!processSocket(desc[n*2+1])))) { - // Close socket and clear pool - if (comet) { - processSocket(desc[n*2+1], SocketStatus.DISCONNECT); - } else { - destroySocket(desc[n*2+1]); - } - continue; - } - } - } else if (rv < 0) { - int errn = -rv; - /* Any non timeup or interrupted error is critical */ - if ((errn != Status.TIMEUP) && (errn != Status.EINTR)) { - if (errn > Status.APR_OS_START_USERERR) { - errn -= Status.APR_OS_START_USERERR; - } - log.error(sm.getString("endpoint.poll.fail", "" + errn, Error.strerror(errn))); - // Handle poll critical failure - synchronized (this) { - destroy(); - init(); - } - continue; - } + // Poll for the specified interval + if (doPoll(connectionPollset)) { + continue; } - if (socketProperties.getSoTimeout() > 0 && maintainTime > 1000000L && running) { - rv = Poll.maintain(serverPollset, desc, true); + if (separateKeepAlive && doPoll(keepAlivePollset)) { + continue; + } + + // Check timeouts (much less frequently that polling) + if (maintainTime > 1000000L && running) { maintainTime = 0; - if (rv > 0) { - keepAliveCount -= rv; - for (int n = 0; n < rv; n++) { - // Close socket and clear pool - if (comet) { - processSocket(desc[n], SocketStatus.TIMEOUT); - } else { - destroySocket(desc[n]); - } - } + if (socketProperties.getSoTimeout() > 0) { + doTimeout(connectionPollset); + } + if (separateKeepAlive) { + doTimeout(keepAlivePollset); } } } catch (Throwable t) { @@ -1333,10 +1334,59 @@ public class AprEndpoint extends Abstrac } - } - + private boolean doPoll(long pollset) { + int rv = Poll.poll(pollset, pollTime, desc, true); + if (rv > 0) { + keepAliveCount -= rv; + for (int n = 0; n < rv; n++) { + // Check for failed sockets and hand this socket off to a worker + if (((desc[n*2] & Poll.APR_POLLHUP) == Poll.APR_POLLHUP) + || ((desc[n*2] & Poll.APR_POLLERR) == Poll.APR_POLLERR) + || (comet && (!processSocket(desc[n*2+1], SocketStatus.OPEN))) + || (!comet && (!processSocket(desc[n*2+1])))) { + // Close socket and clear pool + if (comet) { + processSocket(desc[n*2+1], SocketStatus.DISCONNECT); + } else { + destroySocket(desc[n*2+1]); + } + return true; + } + } + } else if (rv < 0) { + int errn = -rv; + /* Any non timeup or interrupted error is critical */ + if ((errn != Status.TIMEUP) && (errn != Status.EINTR)) { + if (errn > Status.APR_OS_START_USERERR) { + errn -= Status.APR_OS_START_USERERR; + } + log.error(sm.getString("endpoint.poll.fail", "" + errn, Error.strerror(errn))); + // Handle poll critical failure + synchronized (this) { + destroy(); + init(); + } + return true; + } + } + return false; + } - // ----------------------------------------------------- Worker Inner Class + private void doTimeout(long pollset) { + int rv = Poll.maintain(pollset, desc, true); + if (rv > 0) { + keepAliveCount -= rv; + for (int n = 0; n < rv; n++) { + // Close socket and clear pool + if (comet) { + processSocket(desc[n], SocketStatus.TIMEOUT); + } else { + destroySocket(desc[n]); + } + } + } + } + } // ----------------------------------------------- SendfileData Inner Class @@ -1622,7 +1672,7 @@ public class AprEndpoint extends Abstrac Socket.timeoutSet(state.socket, socketProperties.getSoTimeout() * 1000); // If all done put the socket back in the poller for // processing of further requests - getPoller().add(state.socket); + getPoller().add(state.socket, true); } else { // Close the socket since this is // the end of not keep-alive request. @@ -1713,7 +1763,7 @@ public class AprEndpoint extends Abstrac synchronized (socket) { if (!deferAccept) { if (setSocketOptions(socket.getSocket().longValue())) { - getPoller().add(socket.getSocket().longValue()); + getPoller().add(socket.getSocket().longValue(), false); } else { // Close socket and pool destroySocket(socket.getSocket().longValue()); Modified: tomcat/tc7.0.x/trunk/webapps/docs/changelog.xml URL: http://svn.apache.org/viewvc/tomcat/tc7.0.x/trunk/webapps/docs/changelog.xml?rev=1166072&r1=1166071&r2=1166072&view=diff ============================================================================== --- tomcat/tc7.0.x/trunk/webapps/docs/changelog.xml (original) +++ tomcat/tc7.0.x/trunk/webapps/docs/changelog.xml Wed Sep 7 09:06:28 2011 @@ -89,6 +89,10 @@ <changelog> <code>Remove unused and undocumented socketCloseDelay attribute from NIO connector. (markt)</code> + <fix> + <bug>49683</bug>: Support separate connection and keep-alive timeouts + for the APR/native connector HTTP and AJP connectors. (markt) + </fix> </changelog> </subsection> <subsection name="Web applications"> --------------------------------------------------------------------- To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org For additional commands, e-mail: dev-h...@tomcat.apache.org