On 20 December 2010 16:42, <fha...@apache.org> wrote: > 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;
Could this be private? > > > // ------------------------------------------------ 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 > > --------------------------------------------------------------------- To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org For additional commands, e-mail: dev-h...@tomcat.apache.org