Author: remm
Date: Thu Nov 8 11:29:45 2018
New Revision: 1846131
URL: http://svn.apache.org/viewvc?rev=1846131&view=rev
Log:
Remove dedicated NIO2 acceptor thread.
Modified:
tomcat/trunk/java/org/apache/tomcat/util/net/Acceptor.java
tomcat/trunk/java/org/apache/tomcat/util/net/Nio2Endpoint.java
tomcat/trunk/webapps/docs/changelog.xml
Modified: tomcat/trunk/java/org/apache/tomcat/util/net/Acceptor.java
URL:
http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/util/net/Acceptor.java?rev=1846131&r1=1846130&r2=1846131&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/tomcat/util/net/Acceptor.java (original)
+++ tomcat/trunk/java/org/apache/tomcat/util/net/Acceptor.java Thu Nov 8
11:29:45 2018
@@ -151,7 +151,7 @@ public class Acceptor<U> implements Runn
* @param currentErrorDelay The current delay being applied on failure
* @return The delay to apply on the next failure
*/
- private int handleExceptionWithDelay(int currentErrorDelay) {
+ protected int handleExceptionWithDelay(int currentErrorDelay) {
// Don't delay on first exception
if (currentErrorDelay > 0) {
try {
Modified: tomcat/trunk/java/org/apache/tomcat/util/net/Nio2Endpoint.java
URL:
http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/util/net/Nio2Endpoint.java?rev=1846131&r1=1846130&r2=1846131&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/tomcat/util/net/Nio2Endpoint.java (original)
+++ tomcat/trunk/java/org/apache/tomcat/util/net/Nio2Endpoint.java Thu Nov 8
11:29:45 2018
@@ -32,6 +32,7 @@ import java.nio.channels.CompletionHandl
import java.nio.channels.FileChannel;
import java.nio.channels.NetworkChannel;
import java.nio.file.StandardOpenOption;
+import java.util.ArrayList;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
@@ -48,6 +49,7 @@ import org.apache.juli.logging.LogFactor
import org.apache.tomcat.util.ExceptionUtils;
import org.apache.tomcat.util.collections.SynchronizedStack;
import org.apache.tomcat.util.net.AbstractEndpoint.Handler.SocketState;
+import org.apache.tomcat.util.net.Acceptor.AcceptorState;
import org.apache.tomcat.util.net.jsse.JSSESupport;
/**
@@ -86,6 +88,7 @@ public class Nio2Endpoint extends Abstra
*/
private SynchronizedStack<Nio2Channel> nioChannels;
+ private Nio2Acceptor acceptor = null;
public Nio2Endpoint() {
// Override the defaults for NIO2
@@ -182,6 +185,28 @@ public class Nio2Endpoint extends Abstra
}
}
+ @Override
+ protected void startAcceptorThreads() {
+ // Instead of starting a real acceptor thread, this will instead call
+ // an asynchronous accept operation
+ if (acceptor == null) {
+ acceptors = new ArrayList<>(1);
+ acceptor = new Nio2Acceptor(this);
+ acceptor.setThreadName(getName() + "-Acceptor-0");
+ acceptors.add(acceptor);
+ }
+ acceptor.state = AcceptorState.RUNNING;
+ getExecutor().execute(acceptor);
+ }
+
+ @Override
+ public void resume() {
+ super.resume();
+ if (isRunning()) {
+ acceptor.state = AcceptorState.RUNNING;
+ getExecutor().execute(acceptor);
+ }
+ }
/**
* Stop the endpoint. This will cause all processing threads to stop.
@@ -193,6 +218,7 @@ public class Nio2Endpoint extends Abstra
}
if (running) {
running = false;
+ acceptor.state = AcceptorState.ENDED;
// Use the executor to avoid binding the main thread if something
bad
// occurs and unbind will also wait for a bit for it to complete
getExecutor().execute(new Runnable() {
@@ -305,7 +331,7 @@ public class Nio2Endpoint extends Abstra
socketWrapper.setKeepAliveLeft(Nio2Endpoint.this.getMaxKeepAliveRequests());
socketWrapper.setSecure(isSSLEnabled());
// Continue processing on another thread
- return processSocket(socketWrapper, SocketEvent.OPEN_READ, true);
+ return processSocket(socketWrapper, SocketEvent.OPEN_READ, false);
} catch (Throwable t) {
ExceptionUtils.handleThrowable(t);
log.error("",t);
@@ -394,6 +420,89 @@ public class Nio2Endpoint extends Abstra
}
}
+ protected class Nio2Acceptor extends Acceptor<AsynchronousSocketChannel>
+ implements CompletionHandler<AsynchronousSocketChannel, Void> {
+
+ protected int errorDelay = 0;
+
+ public Nio2Acceptor(AbstractEndpoint<?, AsynchronousSocketChannel>
endpoint) {
+ super(endpoint);
+ }
+
+ @Override
+ public void run() {
+ // The initial accept will be called in a separate utility thread
+ if (!isPaused()) {
+ //if we have reached max connections, wait
+ try {
+ countUpOrAwaitConnection();
+ } catch (InterruptedException e) {
+ // Ignore
+ }
+ if (!isPaused()) {
+ // Note: as a special behavior, the completion handler for
accept is
+ // always called in a separate thread.
+ serverSock.accept(null, this);
+ } else {
+ state = AcceptorState.PAUSED;
+ }
+ } else {
+ state = AcceptorState.PAUSED;
+ }
+ }
+
+ @Override
+ public void completed(AsynchronousSocketChannel socket,
+ Void attachment) {
+ // Successful accept, reset the error delay
+ errorDelay = 0;
+ // Continue processing the socket on the current thread
+ // Configure the socket
+ if (isRunning() && !isPaused()) {
+ if (getMaxConnections() == -1) {
+ serverSock.accept(null, this);
+ } else {
+ // Accept again on a new thread since
countUpOrAwaitConnection may block
+ getExecutor().execute(this);
+ }
+ if (!setSocketOptions(socket)) {
+ closeSocket(socket);
+ }
+ } else {
+ if (isRunning()) {
+ state = AcceptorState.PAUSED;
+ }
+ destroySocket(socket);
+ }
+ }
+
+ @Override
+ public void failed(Throwable t, Void attachment) {
+ if (isRunning()) {
+ if (!isPaused()) {
+ if (getMaxConnections() == -1) {
+ serverSock.accept(null, this);
+ } else {
+ // Accept again on a new thread since
countUpOrAwaitConnection may block
+ getExecutor().execute(this);
+ }
+ } else {
+ state = AcceptorState.PAUSED;
+ }
+ // We didn't get a socket
+ countDownConnection();
+ // Introduce delay if necessary
+ errorDelay = handleExceptionWithDelay(errorDelay);
+ ExceptionUtils.handleThrowable(t);
+ log.error(sm.getString("endpoint.accept.fail"), t);
+ } else {
+ // We didn't get a socket
+ countDownConnection();
+ }
+ }
+
+ }
+
public static class Nio2SocketWrapper extends
SocketWrapperBase<Nio2Channel> {
private static final ThreadLocal<AtomicInteger>
nestedWriteCompletionCount =
Modified: tomcat/trunk/webapps/docs/changelog.xml
URL:
http://svn.apache.org/viewvc/tomcat/trunk/webapps/docs/changelog.xml?rev=1846131&r1=1846130&r2=1846131&view=diff
==============================================================================
--- tomcat/trunk/webapps/docs/changelog.xml (original)
+++ tomcat/trunk/webapps/docs/changelog.xml Thu Nov 8 11:29:45 2018
@@ -83,6 +83,10 @@
Refactor connector async timeout threads using a scheduled executor.
(remm)
</update>
+ <update>
+ Avoid using a dedicated thread for accept on the NIO2 connector, it is
+ always less efficient. (remm)
+ </update>
</changelog>
</subsection>
<subsection name="Tribes">
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]