Author: fhanik
Date: Mon Dec 20 16:42:13 2010
New Revision: 1051202

URL: http://svn.apache.org/viewvc?rev=1051202&view=rev
Log:
Implement a maxConnection threshold for the JIoEndpoint, to be able to 
constraint how many connections the connector will accept

Added:
    tomcat/trunk/test/org/apache/catalina/connector/TestMaxConnections.java   
(with props)
Modified:
    tomcat/trunk/java/org/apache/tomcat/util/net/JIoEndpoint.java
    tomcat/trunk/test/org/apache/catalina/startup/SimpleHttpClient.java
    tomcat/trunk/webapps/docs/config/http.xml

Modified: tomcat/trunk/java/org/apache/tomcat/util/net/JIoEndpoint.java
URL: 
http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/util/net/JIoEndpoint.java?rev=1051202&r1=1051201&r2=1051202&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/tomcat/util/net/JIoEndpoint.java (original)
+++ tomcat/trunk/java/org/apache/tomcat/util/net/JIoEndpoint.java Mon Dec 20 
16:42:13 2010
@@ -32,6 +32,7 @@ import org.apache.juli.logging.Log;
 import org.apache.juli.logging.LogFactory;
 import org.apache.tomcat.util.ExceptionUtils;
 import org.apache.tomcat.util.net.AbstractEndpoint.Handler.SocketState;
+import org.apache.tomcat.util.threads.CounterLatch;
 
 
 /**
@@ -107,6 +108,8 @@ public class JIoEndpoint extends Abstrac
         // Not supported
         return false;
     }
+    
+    protected CounterLatch connectionCounterLatch = null;
 
 
     // ------------------------------------------------ Handler Inner Interface
@@ -197,20 +200,24 @@ public class JIoEndpoint extends Abstrac
                     break;
                 }
                 try {
+                    //if we have reached max connections, wait
+                    connectionCounterLatch.await();
                     // Accept the next incoming connection from the server 
socket
                     Socket socket = 
serverSocketFactory.acceptSocket(serverSocket);
                     
                     // Configure the socket
                     if (setSocketOptions(socket)) {
-                    // Hand this socket off to an appropriate processor
-                    if (!processSocket(socket)) {
-                        // Close socket right away
-                        try {
-                            socket.close();
-                        } catch (IOException e) {
-                            // Ignore
+                        // Hand this socket off to an appropriate processor
+                        if (!processSocket(socket)) {
+                            // Close socket right away
+                            try {
+                                socket.close();
+                            } catch (IOException e) {
+                                // Ignore
+                            }
+                        } else {
+                            connectionCounterLatch.countUp();
                         }
-                    }
                     } else {
                         // Close socket right away
                         try {
@@ -286,6 +293,7 @@ public class JIoEndpoint extends Abstrac
                         if (log.isTraceEnabled()) {
                             log.trace("Closing socket:"+socket);
                         }
+                        connectionCounterLatch.countDown();
                         try {
                             socket.getSocket().close();
                         } catch (IOException e) {
@@ -373,6 +381,8 @@ public class JIoEndpoint extends Abstrac
             if (getExecutor() == null) {
                 createExecutor();
             }
+            
+            connectionCounterLatch = new CounterLatch(0,getMaxConnections());
 
             // Start acceptor threads
             for (int i = 0; i < acceptorThreadCount; i++) {
@@ -394,6 +404,8 @@ public class JIoEndpoint extends Abstrac
 
     @Override
     public void stopInternal() {
+        connectionCounterLatch.releaseAll();
+        connectionCounterLatch = null;
         if (!paused) {
             pause();
         }

Added: tomcat/trunk/test/org/apache/catalina/connector/TestMaxConnections.java
URL: 
http://svn.apache.org/viewvc/tomcat/trunk/test/org/apache/catalina/connector/TestMaxConnections.java?rev=1051202&view=auto
==============================================================================
--- tomcat/trunk/test/org/apache/catalina/connector/TestMaxConnections.java 
(added)
+++ tomcat/trunk/test/org/apache/catalina/connector/TestMaxConnections.java Mon 
Dec 20 16:42:13 2010
@@ -0,0 +1,180 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You 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.catalina.connector;
+
+import java.io.IOException;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.catalina.Context;
+import org.apache.catalina.startup.SimpleHttpClient;
+import org.apache.catalina.startup.Tomcat;
+import org.apache.catalina.startup.TomcatBaseTest;
+
+public class TestMaxConnections extends TomcatBaseTest{
+
+    Tomcat tomcat = null;
+    static int soTimeout = 3000;
+    static int connectTimeout = 1000;
+    
+    public void test1() throws Exception {
+        init();
+        start();
+        ConnectThread[] t = new ConnectThread[10];
+        int passcount = 0;
+        int connectfail = 0;
+        for (int i=0; i<t.length; i++) {
+            t[i] = new ConnectThread();
+            t[i].setName("ConnectThread["+i+"+]");
+            t[i].start();
+        }
+        for (int i=0; i<t.length; i++) {
+            t[i].join();
+            if (t[i].passed) passcount++;
+            if (t[i].connectfailed) connectfail++;
+        }
+        assertEquals("The number of successful requests should have been 
5.",5, passcount);
+        assertEquals("The number of failed connects should have been 5.",5, 
connectfail);
+        stop();
+    }
+    
+
+    private class ConnectThread extends Thread {
+        public boolean passed = true;
+        public boolean connectfailed = false;
+        public void run() {
+            try {
+                TestKeepAliveClient client = new TestKeepAliveClient();
+                client.doHttp10Request();
+            }catch (Exception x) {
+                passed = false;
+                System.err.println(Thread.currentThread().getName()+" 
Error:"+x.getMessage());
+                connectfailed = "connect timed out".equals(x.getMessage());
+            }
+        }
+    }
+
+    private boolean init;
+    
+    private synchronized void init() {
+        if (init) return;
+        
+        Tomcat tomcat = getTomcatInstance();
+        Context root = tomcat.addContext("", SimpleHttpClient.TEMP_DIR);
+        Tomcat.addServlet(root, "Simple", new SimpleServlet());
+        root.addServletMapping("/test", "Simple");
+        tomcat.getConnector().setProperty("maxKeepAliveRequests", "5");
+        tomcat.getConnector().setProperty("soTimeout", "20000");
+        tomcat.getConnector().setProperty("keepAliveTimeout", "50000");
+        tomcat.getConnector().setProperty("port", "8080");
+        tomcat.getConnector().setProperty("maxConnections", "4");
+        tomcat.getConnector().setProperty("acceptCount", "1");
+        init = true;
+    }
+
+    private synchronized void start() throws Exception {
+        tomcat = getTomcatInstance();
+        init();
+        tomcat.start();
+    }
+    
+    private synchronized void stop() throws Exception {
+        tomcat.stop();
+    }
+    
+    private class TestKeepAliveClient extends SimpleHttpClient {
+
+        private void doHttp10Request() throws Exception {
+            
+            long start = System.currentTimeMillis();
+            // Open connection
+            connect(connectTimeout,soTimeout);
+            
+            // Send request in two parts
+            String[] request = new String[1];
+            request[0] =
+                "GET /test HTTP/1.0" + CRLF + CRLF;
+            setRequest(request);
+            boolean passed = false;
+            processRequest(false); // blocks until response has been read
+            long stop = System.currentTimeMillis();
+            System.out.println(Thread.currentThread().getName()+" Request 
complete:"+(stop-start)+" ms.");
+            passed = (this.readLine()==null);
+            // Close the connection
+            disconnect();
+            reset();
+            assertTrue(passed);
+        }
+        
+        private void doHttp11Request() throws Exception {
+            Tomcat tomcat = getTomcatInstance();
+            init();
+            tomcat.start();
+            // Open connection
+            connect();
+            
+            // Send request in two parts
+            String[] request = new String[1];
+            request[0] =
+                "GET /test HTTP/1.1" + CRLF + 
+                "Host: localhost" + CRLF +
+                "Connection: Keep-Alive" + CRLF+
+                "Keep-Alive: 300"+ CRLF+ CRLF;
+            
+            setRequest(request);
+            
+            for (int i=0; i<5; i++) {
+                processRequest(false); // blocks until response has been read
+                assertTrue(getResponseLine()!=null && 
getResponseLine().trim().startsWith("HTTP/1.1 200"));
+            }
+            boolean passed = (this.readLine()==null);
+            // Close the connection
+            disconnect();
+            reset();
+            tomcat.stop();
+            assertTrue(passed);
+        }
+        
+        @Override
+        public boolean isResponseBodyOK() {
+            return true;
+        }
+        
+    }
+    
+    
+    private static class SimpleServlet extends HttpServlet {
+
+        private static final long serialVersionUID = 1L;
+
+        @Override
+        protected void service(HttpServletRequest req, HttpServletResponse 
resp) throws ServletException, IOException {
+            try {
+                Thread.sleep(TestMaxConnections.soTimeout/2);
+            }catch (InterruptedException x) {
+                
+            }
+            resp.setContentLength(0);
+            resp.flushBuffer();
+        }
+        
+    }
+    
+}

Propchange: 
tomcat/trunk/test/org/apache/catalina/connector/TestMaxConnections.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: tomcat/trunk/test/org/apache/catalina/startup/SimpleHttpClient.java
URL: 
http://svn.apache.org/viewvc/tomcat/trunk/test/org/apache/catalina/startup/SimpleHttpClient.java?rev=1051202&r1=1051201&r2=1051202&view=diff
==============================================================================
--- tomcat/trunk/test/org/apache/catalina/startup/SimpleHttpClient.java 
(original)
+++ tomcat/trunk/test/org/apache/catalina/startup/SimpleHttpClient.java Mon Dec 
20 16:42:13 2010
@@ -25,7 +25,9 @@ import java.io.OutputStream;
 import java.io.OutputStreamWriter;
 import java.io.Reader;
 import java.io.Writer;
+import java.net.InetSocketAddress;
 import java.net.Socket;
+import java.net.SocketAddress;
 import java.net.UnknownHostException;
 import java.util.ArrayList;
 import java.util.List;
@@ -109,14 +111,20 @@ public abstract class SimpleHttpClient {
         return null;
     }
 
-    public void connect() throws UnknownHostException, IOException {
-        socket = new Socket("localhost", port);
+    public void connect(int connectTimeout, int soTimeout) throws 
UnknownHostException, IOException {
+        SocketAddress addr = new InetSocketAddress("localhost", port);
+        socket = new Socket();
+        socket.setSoTimeout(soTimeout);
+        socket.connect(addr,connectTimeout);
         OutputStream os = socket.getOutputStream();
         writer = new OutputStreamWriter(os);
         InputStream is = socket.getInputStream();
         Reader r = new InputStreamReader(is);
         reader = new BufferedReader(r);
     }
+    public void connect() throws UnknownHostException, IOException {
+        connect(0,0);
+    }
     
     public void processRequest() throws IOException, InterruptedException {
         processRequest(true);

Modified: tomcat/trunk/webapps/docs/config/http.xml
URL: 
http://svn.apache.org/viewvc/tomcat/trunk/webapps/docs/config/http.xml?rev=1051202&r1=1051201&r2=1051202&view=diff
==============================================================================
--- tomcat/trunk/webapps/docs/config/http.xml (original)
+++ tomcat/trunk/webapps/docs/config/http.xml Mon Dec 20 16:42:13 2010
@@ -361,6 +361,15 @@
       execute tasks using the executor rather than an internal thread pool.</p>
     </attribute>
 
+    <attribute name="maxConnections" required="false">
+      <p>The maximum number of connections that the server will accept and 
process
+      at any given time. When this number has been reached, the server will 
not accept any more
+      connections until the number of connections reach below this value. The 
operating system may still accept connections based 
+      on the <code>acceptCount</code> setting.
+      This setting is currently only applicable to the blocking Java 
connectors (AJP/HTTP).
+      Default value is <code>10000</code>.</p>
+    </attribute>
+
     <attribute name="maxTrailerSize" required="false">
       <p>Limits the total length of trailing headers in the last chunk of
       a chunked HTTP request. If the value is <code>-1</code>, no limit will be



---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org
For additional commands, e-mail: dev-h...@tomcat.apache.org

Reply via email to