You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tomcat.apache.org by ma...@apache.org on 2011/09/07 11:06:28 UTC

svn commit: r1166072 - in /tomcat/tc7.0.x/trunk: ./ java/org/apache/coyote/ajp/AjpAprProtocol.java java/org/apache/coyote/http11/Http11AprProtocol.java java/org/apache/tomcat/util/net/AprEndpoint.java webapps/docs/changelog.xml

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-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org