From df1935c49913418e2045e57b267f19769626f2b5 Mon Sep 17 00:00:00 2001
From: fhanik
Date: Tue, 7 Jul 2009 17:21:15 +0000
Subject: [PATCH] Improve shutdown time for NIO connectors, to block in a
minimal fashion, yet leave the pollers time to close out their connections
git-svn-id: https://svn.apache.org/repos/asf/tomcat/trunk@791914 13f79535-47bb-0310-9956-ffa450edef68
---
java/org/apache/tomcat/util/net/NioEndpoint.java | 55 ++++++++++++++--------
.../apache/tomcat/util/net/SocketProperties.java | 15 ++++++
webapps/docs/config/http.xml | 6 ++-
3 files changed, 56 insertions(+), 20 deletions(-)
diff --git a/java/org/apache/tomcat/util/net/NioEndpoint.java b/java/org/apache/tomcat/util/net/NioEndpoint.java
index 82f1fb542..7efa1256f 100644
--- a/java/org/apache/tomcat/util/net/NioEndpoint.java
+++ b/java/org/apache/tomcat/util/net/NioEndpoint.java
@@ -23,6 +23,8 @@ import java.io.IOException;
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 @@ public class NioEndpoint {
*/
protected AtomicInteger activeSocketProcessors = new AtomicInteger(0);
-
+ /**
+ *
+ */
+ protected volatile CountDownLatch stopLatch = null;
/**
* Cache for SocketProcessor objects
@@ -791,6 +796,7 @@ public class NioEndpoint {
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 @@ public class NioEndpoint {
//minimum one poller thread
pollerThreadCount = 1;
}
+ stopLatch = new CountDownLatch(pollerThreadCount);
// Initialize SSL if needed
if (isSSLEnabled()) {
@@ -933,6 +940,7 @@ public class NioEndpoint {
pollers[i].destroy();
pollers[i] = null;
}
+ try { stopLatch.await(selectorTimeout+100,TimeUnit.MILLISECONDS); } catch (InterruptedException ignore ) {}
}
eventCache.clear();
keyCache.clear();
@@ -942,7 +950,7 @@ public class NioEndpoint {
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 @@ public class NioEndpoint {
* 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 @@ public class NioEndpoint {
initialized = false;
releaseCaches();
selectorPool.close();
+ if (log.isDebugEnabled()) {
+ log.debug("Destroy completed for "+new InetSocketAddress(address,port));
+ }
}
@@ -1007,17 +1021,23 @@ public class NioEndpoint {
*/
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 @@ public class NioEndpoint {
}
}
}
+ }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 @@ public class NioEndpoint {
protected Selector selector;
protected ConcurrentLinkedQueue events = new ConcurrentLinkedQueue();
- 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 @@ public class NioEndpoint {
*/
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 @@ public class NioEndpoint {
// Loop if endpoint is paused
while (paused && (!close) ) {
try {
- Thread.sleep(500);
+ Thread.sleep(100);
} catch (InterruptedException e) {
// Ignore
}
@@ -1431,8 +1450,7 @@ public class NioEndpoint {
// Time to terminate?
if (close) {
timeout(0, false);
- stopLatch.countDown();
- return;
+ break;
}
int keyCount = 0;
try {
@@ -1450,9 +1468,8 @@ public class NioEndpoint {
}
if (close) {
timeout(0, false);
- stopLatch.countDown();
selector.close();
- return;
+ break;
}
} catch ( NullPointerException x ) {
//sun bug 5076772 on windows JDK 1.5
diff --git a/java/org/apache/tomcat/util/net/SocketProperties.java b/java/org/apache/tomcat/util/net/SocketProperties.java
index 2e6564b45..e17f5cd0f 100644
--- a/java/org/apache/tomcat/util/net/SocketProperties.java
+++ b/java/org/apache/tomcat/util/net/SocketProperties.java
@@ -177,6 +177,11 @@ public class SocketProperties {
* 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 @@ public class SocketProperties {
this.bufferPool = directBufferPool;
}
+ public int getUnlockTimeout() {
+ return unlockTimeout;
+ }
+
+ public void setUnlockTimeout(int unlockTimeout) {
+ this.unlockTimeout = unlockTimeout;
+ }
+
+
+
}
\ No newline at end of file
diff --git a/webapps/docs/config/http.xml b/webapps/docs/config/http.xml
index e787588e0..ed6a21030 100644
--- a/webapps/docs/config/http.xml
+++ b/webapps/docs/config/http.xml
@@ -452,7 +452,11 @@
Socket Performance Options
All three performance attributes must be set else the JVM defaults will
be used for all three.
-
+
+
+ (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 250 and the value is in milliseconds
+
--
2.11.0