Author: fhanik Date: Tue Jul 7 17:21:15 2009 New Revision: 791914 URL: http://svn.apache.org/viewvc?rev=791914&view=rev Log: Improve shutdown time for NIO connectors, to block in a minimal fashion, yet leave the pollers time to close out their connections
Modified: tomcat/trunk/java/org/apache/tomcat/util/net/NioEndpoint.java tomcat/trunk/java/org/apache/tomcat/util/net/SocketProperties.java tomcat/trunk/webapps/docs/config/http.xml 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=791914&r1=791913&r2=791914&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/tomcat/util/net/NioEndpoint.java (original) +++ tomcat/trunk/java/org/apache/tomcat/util/net/NioEndpoint.java Tue Jul 7 17:21:15 2009 @@ -23,6 +23,8 @@ import java.net.InetAddress; import java.net.InetSocketAddress; import java.net.Socket; +import java.net.SocketAddress; +import java.net.SocketTimeoutException; import java.nio.ByteBuffer; import java.nio.channels.CancelledKeyException; import java.nio.channels.FileChannel; @@ -171,7 +173,10 @@ */ protected AtomicInteger activeSocketProcessors = new AtomicInteger(0); - + /** + * + */ + protected volatile CountDownLatch stopLatch = null; /** * Cache for SocketProcessor objects @@ -791,6 +796,7 @@ InetSocketAddress addr = (address!=null?new InetSocketAddress(address,port):new InetSocketAddress(port)); serverSock.socket().bind(addr,backlog); serverSock.configureBlocking(true); //mimic APR behavior + serverSock.socket().setSoTimeout(getSocketProperties().getSoTimeout()); // Initialize thread count defaults for acceptor, poller if (acceptorThreadCount == 0) { @@ -801,6 +807,7 @@ //minimum one poller thread pollerThreadCount = 1; } + stopLatch = new CountDownLatch(pollerThreadCount); // Initialize SSL if needed if (isSSLEnabled()) { @@ -933,6 +940,7 @@ pollers[i].destroy(); pollers[i] = null; } + try { stopLatch.await(selectorTimeout+100,TimeUnit.MILLISECONDS); } catch (InterruptedException ignore ) {} } eventCache.clear(); keyCache.clear(); @@ -942,7 +950,7 @@ if ( executor instanceof ThreadPoolExecutor ) { //this is our internal one, so we need to shut it down ThreadPoolExecutor tpe = (ThreadPoolExecutor) executor; - tpe.shutdown(); + tpe.shutdownNow(); TaskQueue queue = (TaskQueue) tpe.getQueue(); queue.setParent(null); } @@ -956,6 +964,9 @@ * Deallocate NIO memory pools, and close server socket. */ public void destroy() throws Exception { + if (log.isDebugEnabled()) { + log.debug("Destroy initiated for "+new InetSocketAddress(address,port)); + } if (running) { stop(); } @@ -967,6 +978,9 @@ initialized = false; releaseCaches(); selectorPool.close(); + if (log.isDebugEnabled()) { + log.debug("Destroy completed for "+new InetSocketAddress(address,port)); + } } @@ -1007,17 +1021,23 @@ */ protected void unlockAccept() { java.net.Socket s = null; + InetSocketAddress saddr = null; try { // Need to create a connection to unlock the accept(); if (address == null) { - s = new java.net.Socket("127.0.0.1", port); - s.setSoTimeout(2000); + saddr = new InetSocketAddress("127.0.0.1", port); } else { - s = new java.net.Socket(address, port); - s.setSoTimeout(2000); - // setting soLinger to a small value will help shutdown the - // connection quicker - s.setSoLinger(true, 0); + saddr = new InetSocketAddress(address,port); + } + s = new java.net.Socket(); + s.setSoTimeout(getSocketProperties().getSoTimeout()); + s.setSoLinger(getSocketProperties().getSoLingerOn(),getSocketProperties().getSoLingerTime()); + if (log.isDebugEnabled()) { + log.debug("About to unlock socket for:"+saddr); + } + s.connect(saddr,getSocketProperties().getUnlockTimeout()); + if (log.isDebugEnabled()) { + log.debug("Socket unlock completed for:"+saddr); } } catch(Exception e) { if (log.isDebugEnabled()) { @@ -1177,6 +1197,8 @@ } } } + }catch (SocketTimeoutException sx) { + //normal condition }catch ( IOException x ) { if ( running ) log.error(sm.getString("endpoint.accept.fail"), x); } catch (OutOfMemoryError oom) { @@ -1279,13 +1301,11 @@ protected Selector selector; protected ConcurrentLinkedQueue<Runnable> events = new ConcurrentLinkedQueue<Runnable>(); - protected boolean close = false; + protected volatile boolean close = false; protected long nextExpiration = 0;//optimize expiration handling protected AtomicLong wakeupCounter = new AtomicLong(0l); - protected CountDownLatch stopLatch = new CountDownLatch(1); - protected volatile int keyCount = 0; public Poller() throws IOException { @@ -1301,12 +1321,11 @@ */ protected void destroy() { // Wait for polltime before doing anything, so that the poller threads - // exit, otherwise parallel descturction of sockets which are still + // exit, otherwise parallel closure of sockets which are still // in the poller can cause problems close = true; events.clear(); selector.wakeup(); - try { stopLatch.await(5,TimeUnit.SECONDS); } catch (InterruptedException ignore ) {} } public void addEvent(Runnable event) { @@ -1420,7 +1439,7 @@ // Loop if endpoint is paused while (paused && (!close) ) { try { - Thread.sleep(500); + Thread.sleep(100); } catch (InterruptedException e) { // Ignore } @@ -1431,8 +1450,7 @@ // Time to terminate? if (close) { timeout(0, false); - stopLatch.countDown(); - return; + break; } int keyCount = 0; try { @@ -1450,9 +1468,8 @@ } if (close) { timeout(0, false); - stopLatch.countDown(); selector.close(); - return; + break; } } catch ( NullPointerException x ) { //sun bug 5076772 on windows JDK 1.5 Modified: tomcat/trunk/java/org/apache/tomcat/util/net/SocketProperties.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/util/net/SocketProperties.java?rev=791914&r1=791913&r2=791914&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/tomcat/util/net/SocketProperties.java (original) +++ tomcat/trunk/java/org/apache/tomcat/util/net/SocketProperties.java Tue Jul 7 17:21:15 2009 @@ -177,6 +177,11 @@ * poller going boinkers during high traffic */ protected long timeoutInterval = 1000; + + /** + * Timeout in milliseconds for an unlock to take place. + */ + protected int unlockTimeout = 250; public void setProperties(Socket socket) throws SocketException{ if (rxBufSize != null) @@ -407,4 +412,14 @@ this.bufferPool = directBufferPool; } + public int getUnlockTimeout() { + return unlockTimeout; + } + + public void setUnlockTimeout(int unlockTimeout) { + this.unlockTimeout = unlockTimeout; + } + + + } \ No newline at end of file Modified: tomcat/trunk/webapps/docs/config/http.xml URL: http://svn.apache.org/viewvc/tomcat/trunk/webapps/docs/config/http.xml?rev=791914&r1=791913&r2=791914&view=diff ============================================================================== --- tomcat/trunk/webapps/docs/config/http.xml (original) +++ tomcat/trunk/webapps/docs/config/http.xml Tue Jul 7 17:21:15 2009 @@ -452,7 +452,11 @@ <a href="http://java.sun.com/j2se/1.6.0/docs/api/java/net/Socket.html#setPerformancePreferences(int,%20int,%20int)">Socket Performance Options</a> All three performance attributes must be set else the JVM defaults will be used for all three.</p> - </attribute> + </attribute> + <attribute name="socket.unlockTimeout" required="false"> + <p>(int) The timeout for a socket unlock. When a connector is stopped, it will try to release the acceptor thread by opening a connector to itself. + The default value is <code>250</code> and the value is in milliseconds</p> + </attribute> </attributes> </subsection> --------------------------------------------------------------------- To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org For additional commands, e-mail: dev-h...@tomcat.apache.org