svn commit: r1846131 - in /tomcat/trunk: java/org/apache/tomcat/util/net/Acceptor.java java/org/apache/tomcat/util/net/Nio2Endpoint.java webapps/docs/changelog.xml

classic Classic list List threaded Threaded
1 message Options
Reply | Threaded
Open this post in threaded view
|

svn commit: r1846131 - in /tomcat/trunk: java/org/apache/tomcat/util/net/Acceptor.java java/org/apache/tomcat/util/net/Nio2Endpoint.java webapps/docs/changelog.xml

Rémy Maucherat
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: [hidden email]
For additional commands, e-mail: [hidden email]