Author: fhanik Date: Mon Dec 20 21:01:37 2010 New Revision: 1051291 URL: http://svn.apache.org/viewvc?rev=1051291&view=rev Log: Implement maxConnections for NIO connector
Modified: tomcat/trunk/java/org/apache/tomcat/util/net/AbstractEndpoint.java tomcat/trunk/java/org/apache/tomcat/util/net/JIoEndpoint.java tomcat/trunk/java/org/apache/tomcat/util/net/NioEndpoint.java tomcat/trunk/test/org/apache/catalina/connector/TestMaxConnections.java Modified: tomcat/trunk/java/org/apache/tomcat/util/net/AbstractEndpoint.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/util/net/AbstractEndpoint.java?rev=1051291&r1=1051290&r2=1051291&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/tomcat/util/net/AbstractEndpoint.java (original) +++ tomcat/trunk/java/org/apache/tomcat/util/net/AbstractEndpoint.java Mon Dec 20 21:01:37 2010 @@ -32,6 +32,7 @@ import org.apache.juli.logging.Log; import org.apache.tomcat.util.IntrospectionUtils; import org.apache.tomcat.util.net.jsse.JSSESocketFactory; import org.apache.tomcat.util.res.StringManager; +import org.apache.tomcat.util.threads.CounterLatch; import org.apache.tomcat.util.threads.ResizableExecutor; import org.apache.tomcat.util.threads.TaskQueue; import org.apache.tomcat.util.threads.TaskThreadFactory; @@ -123,6 +124,11 @@ public abstract class AbstractEndpoint { protected volatile boolean internalExecutor = false; /** + * counter for nr of connections handled by an endpoint + */ + protected volatile CounterLatch connectionCounterLatch = null; + + /** * Socket properties */ protected SocketProperties socketProperties = new SocketProperties(); 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=1051291&r1=1051290&r2=1051291&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 21:01:37 2010 @@ -109,7 +109,7 @@ public class JIoEndpoint extends Abstrac return false; } - protected CounterLatch connectionCounterLatch = null; + // ------------------------------------------------ Handler Inner Interface Modified: tomcat/trunk/java/org/apache/tomcat/util/net/NioEndpoint.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/util/net/NioEndpoint.java?rev=1051291&r1=1051290&r2=1051291&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/tomcat/util/net/NioEndpoint.java (original) +++ tomcat/trunk/java/org/apache/tomcat/util/net/NioEndpoint.java Mon Dec 20 21:01:37 2010 @@ -57,6 +57,7 @@ import org.apache.tomcat.util.net.Abstra import org.apache.tomcat.util.net.SecureNioChannel.ApplicationBufferHandler; import org.apache.tomcat.util.net.jsse.JSSESocketFactory; import org.apache.tomcat.util.net.jsse.NioX509KeyManager; +import org.apache.tomcat.util.threads.CounterLatch; /** * NIO tailored thread pool, providing the following services: @@ -567,6 +568,7 @@ public class NioEndpoint extends Abstrac running = true; paused = false; + connectionCounterLatch = new CounterLatch(0, getMaxConnections()); // Create worker collection if ( getExecutor() == null ) { createExecutor(); @@ -598,6 +600,8 @@ public class NioEndpoint extends Abstrac */ @Override public void stopInternal() { + connectionCounterLatch.releaseAll(); + connectionCounterLatch = null; if (!paused) { pause(); } @@ -808,6 +812,8 @@ public class NioEndpoint extends Abstrac break; } try { + //if we have reached max connections, wait + connectionCounterLatch.await(); // Accept the next incoming connection from the server socket SocketChannel socket = serverSock.accept(); // Hand this socket off to an appropriate processor @@ -824,7 +830,9 @@ public class NioEndpoint extends Abstrac if (log.isDebugEnabled()) log.debug("", ix); } - } + } else { + connectionCounterLatch.countUp(); + } } } catch (SocketTimeoutException sx) { //normal condition @@ -1056,7 +1064,12 @@ public class NioEndpoint extends Abstrac if (key.channel().isOpen()) try {key.channel().close();}catch (Exception ignore){} try {if (ka!=null) ka.getSocket().close(true);}catch (Exception ignore){} try {if (ka!=null && ka.getSendfileData()!=null && ka.getSendfileData().fchannel!=null && ka.getSendfileData().fchannel.isOpen()) ka.getSendfileData().fchannel.close();}catch (Exception ignore){} - if (ka!=null) ka.reset(); + if (ka!=null) { + ka.reset(); + if (connectionCounterLatch.countDown()<0) { + log.warn("Incorrect connection count, multiple cancel called on the same key?" ); + } + } } catch (Throwable e) { ExceptionUtils.handleThrowable(e); if ( log.isDebugEnabled() ) log.error("",e); Modified: 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=1051291&r1=1051290&r2=1051291&view=diff ============================================================================== --- tomcat/trunk/test/org/apache/catalina/connector/TestMaxConnections.java (original) +++ tomcat/trunk/test/org/apache/catalina/connector/TestMaxConnections.java Mon Dec 20 21:01:37 2010 @@ -27,16 +27,21 @@ import org.apache.catalina.Context; import org.apache.catalina.startup.SimpleHttpClient; import org.apache.catalina.startup.Tomcat; import org.apache.catalina.startup.TomcatBaseTest; +import org.apache.coyote.http11.Http11NioProtocol; +import org.apache.coyote.http11.Http11Protocol; public class TestMaxConnections extends TomcatBaseTest{ - Tomcat tomcat = null; static int soTimeout = 3000; static int connectTimeout = 1000; - public void test1() throws Exception { - init(); - start(); + @Override + public void setUp() throws Exception { + //do nothing + } + + public void testBio() throws Exception { + init(Http11Protocol.class.getName()); ConnectThread[] t = new ConnectThread[10]; int passcount = 0; int connectfail = 0; @@ -52,54 +57,62 @@ public class TestMaxConnections extends } 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(); } + public void testNio() throws Exception { + init(Http11NioProtocol.class.getName()); + 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++; + } + + assertTrue("The number of successful requests should have been 4-5, actual "+passcount,4==passcount || 5==passcount); + + } private class ConnectThread extends Thread { public boolean passed = true; public boolean connectfailed = false; public void run() { try { - TestKeepAliveClient client = new TestKeepAliveClient(); + TestClient client = new TestClient(); client.doHttp10Request(); }catch (Exception x) { passed = false; System.err.println(Thread.currentThread().getName()+" Error:"+x.getMessage()); - connectfailed = "connect timed out".equals(x.getMessage()); + connectfailed = "connect timed out".equals(x.getMessage()) || "Connection refused: connect".equals(x.getMessage()); } } } - private boolean init; - private synchronized void init() { - if (init) return; - + private synchronized void init(String protocol) throws Exception { + System.setProperty("tomcat.test.protocol", protocol); + super.setUp(); 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("maxKeepAliveRequests", "1"); 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(); + Thread.sleep(5000); } - - private synchronized void stop() throws Exception { - tomcat.stop(); - } - - private class TestKeepAliveClient extends SimpleHttpClient { + + private class TestClient extends SimpleHttpClient { private void doHttp10Request() throws Exception { @@ -123,35 +136,6 @@ public class TestMaxConnections extends 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; --------------------------------------------------------------------- To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org For additional commands, e-mail: dev-h...@tomcat.apache.org