You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tomcat.apache.org by sh...@il.ibm.com on 2000/02/15 15:12:58 UTC

[PATCH] Thread pool for the TCP connectors



I added a thread pool to the TcpEndpointConnector and TcpEndpoint, so now you
can write something like

<Connector className="org.apache.tomcat.service.TcpEndpointConnector">
    <Parameter name="handler"
value="org.apache.tomcat.service.http.HttpConnectionHandler"/>
    <Parameter name="port" value="8080"/>
    <Parameter name="max_threads" value="80"/>
    <Parameter name="max_spare_threads" value="50"/>
    <Parameter name="min_spare_threads" value="10"/>
</Connector>

in server.xml and the Connector will use a thread pool with a maximum of 80
threads, toleration of up to 50 spare threads and a minimum of 10 spare
threads (as long as max_threads is ok with this)

The changes had to go into:
TcpConnection.java
TcpEndpoint.java
TcpEndpointConnector.java

So I am adding the diffs of these files (I also attach them, it will be
easier).

I also added a new (attached) utility class (called ThreadPool) to the util
package.

 Can someone *please* check this in?

    Gal Shachor

cvs diff -u -w -B TcpConnection.java

Index: TcpConnection.java
===================================================================
RCS file:
/home/cvspublic/jakarta-tomcat/src/share/org/apache/tomcat/service/TcpConnection.java,v
retrieving revision 1.1.1.1
diff -u -w -B -r1.1.1.1 TcpConnection.java
--- TcpConnection.java   1999/10/09 00:20:48  1.1.1.1
+++ TcpConnection.java   2000/02/15 13:58:44
@@ -1,5 +1,5 @@
 /*
- * $Header:
/home/cvspublic/jakarta-tomcat/src/share/org/apache/tomcat/service/TcpConnection.java,v

1.1.1.1 1999/10/09 00:20:48 duncan Exp $
+ * $Header:
/home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/service/TcpConnection.java,v

1.1.1.1 1999/10/09 00:20:48 duncan Exp $
  * $Revision: 1.1.1.1 $
  * $Date: 1999/10/09 00:20:48 $
  *
@@ -99,6 +99,10 @@
     return socket;
     }

+    public void recycle() {
+        endpoint = null;
+        socket = null;
+    }
 }

*********************

cvs diff -u -w -B TcpEndpoint.java

Index: TcpEndpoint.java
===================================================================
RCS file:
/home/cvspublic/jakarta-tomcat/src/share/org/apache/tomcat/service/TcpEndpoint.java,v
retrieving revision 1.7
diff -u -w -B -r1.7 TcpEndpoint.java
--- TcpEndpoint.java     2000/02/09 01:18:39  1.7
+++ TcpEndpoint.java     2000/02/15 14:00:06
@@ -90,20 +90,20 @@
  * @author Jason Hunter [jch@eng.sun.com]
  * @author James Todd [gonzo@eng.sun.com]
  * @author Costin@eng.sun.com
+ * @author Gal Shachor [shachor@il.ibm.com]
  */
 public class TcpEndpoint  { // implements Endpoint {

     private StringManager sm
=StringManager.getManager("org.apache.tomcat.service");

-    private static final int BACKLOG = 50;
+    private static final int BACKLOG = 100;
     private static final int TIMEOUT = 1000;

+    private boolean isPool = true;
+
     private int backlog = BACKLOG;
     private int timeout = TIMEOUT;

-    //    private EndpointManager manager;
-
-    String handlerClassName;
     TcpConnectionHandler handler;

     private InetAddress inet;
@@ -112,17 +112,48 @@
     private ServerSocketFactory factory;
     private ServerSocket serverSocket;

-    TcpListenerThread listener;
+    Runnable listener;
     boolean running = true;

+    ThreadPool tp;
+
     public TcpEndpoint() {
+        tp = new ThreadPool();
     }

     // -------------------- Configuration --------------------
+
+    public void setPoolOn(boolean isPool) {
+        this.isPool = isPool;
+    }
+
+    public boolean isPoolOn() {
+        return isPool;
+    }
+
+    public void setMaxThreads(int maxThreads) {
+        tp.setMaxThreads(maxThreads);
+    }
+
+    public int getMaxThreads() {
+        return tp.getMaxThreads();
+    }
+
+    public void setMaxSpareThreads(int maxThreads) {
+        tp.setMaxSpareThreads(maxThreads);
+    }
+
+    public int getMaxSpareThreads() {
+        return tp.getMaxSpareThreads();
+    }

-//     public void setEndpointManager( EndpointManager manager ) {
-//  this.manager=manager;
-//     }
+    public void setMinSpareThreads(int minThreads) {
+        tp.setMinSpareThreads(minThreads);
+    }
+
+    public int getMinSpareThreads() {
+        return tp.getMinSpareThreads();
+    }

     public int getPort() {
     return port;
@@ -148,10 +179,6 @@
     this.factory=factory;
     }

-    public void setConnectionHandlerClassName( String classN ) {
-
-    }
-
     public void setConnectionHandler( TcpConnectionHandler handler ) {
     this.handler=handler;
     }
@@ -163,12 +190,16 @@
     /**
      * Allows the server developer to specify the backlog that
      * should be used for server sockets. By default, this value
-     * is 50.
+     * is 100.
      */
     public void setBacklog(int backlog) {
     this.backlog = backlog;
     }

+    public int getBacklog() {
+        return backlog;
+    }
+
     /**
      * Sets the timeout in ms of the server sockets created by this
      * server. This method allows the developer to make servers
@@ -194,6 +225,9 @@
              serverSocket = factory.createSocket(port, backlog, inet);
          }
         }
+            if(isPool) {
+                 tp.start();
+             }
     } catch( IOException ex ) {
         // throw?
         // ex.printStackTrace();
@@ -209,13 +243,18 @@
     }
     running=true;
     System.out.println("Starting tcp endpoint on " + port + " with " +
handler.getClass().getName());
+        if(isPool) {
+             listener = new TcpWorkerThread(this);
+            tp.runIt(listener);
+        } else {
     listener=new TcpListenerThread( this );
     Thread thread = new Thread(listener);
     thread.start();
     }
-
+    }

     public void stopEndpoint() {
+        tp.shutdown();
     running=false;
     try {
         serverSocket.close(); // XXX?
@@ -222,15 +261,11 @@
     } catch(Exception e) {();
     }
     serverSocket = null;
-
     }

-
-
     // -------------------- Private methods

-    void processSocket( Socket s )
-    throws IOException
+    void processSocket(Socket s) throws IOException
     {
     // XXX reuse, pools, etc

@@ -253,12 +288,34 @@
          return;

         if( null!= serverSocket) {
-         Socket socket = serverSocket.accept();
+              Socket socket = acceptSocket();
+              if(running != false) {
+                  processSocket(socket);
+              }
+             }
+         } catch(Throwable e) {(socket);et();OExceptionort
+             running = false;
+             String msg = sm.getString("endpoint.err.fatal",
+                                          serverSocket, e);
+             e.printStackTrace(); // something very wrong happened - better
know what
+             System.err.println(msg);
+         }
+    }
+
+    Socket acceptSocket() {(msg);something
+        Socket accepted = null;
+         try {
+             if(running == true) {
+             if(null!= serverSocket) {
+                   accepted = serverSocket.accept();
          if (running == false) {
-             socket.close();  // rude, but unlikely!
+                       if(null != accepted) {
+                          accepted.close();  // rude, but unlikely!
+                          accepted = null;
          }
-         processSocket(socket);
         }
+                 }
+             }
     } catch (InterruptedIOException iioe) {
         // normal part -- should happen regularly so
         // that the endpoint can release if the server
@@ -275,15 +332,16 @@
          e.printStackTrace(); // something very wrong happened - better know
what
          System.err.println(msg);
         }
-    } catch (Exception e) {
+         } catch(Throwable e) {
         running = false;
         String msg = sm.getString("endpoint.err.fatal",
                          serverSocket, e);
         e.printStackTrace(); // something very wrong happened - better know
what
         System.err.println(msg);
     }
-    }

+         return accepted;
+    }
 }

 // -------------------- Threads --------------------
@@ -291,6 +349,61 @@

 // Keep the thread model in one place !

+/*
+ * I switched the threading model here.
+ *
+ * We used to have a "listener" thread and a "connection"
+ * thread, this results in code simplicity but also a needless
+ * thread switch.
+ *
+ * Instead I am now using a pool of threads, all the threads are
+ * simmetric in their execution and no thread switch is needed.
+ */
+class TcpWorkerThread implements Runnable {
+    TcpEndpoint endpoint;
+    Vector connectionCache;
+
+    public TcpWorkerThread(TcpEndpoint endpoint) {
+        this.endpoint = endpoint;
+        connectionCache = new Vector(endpoint.getMaxThreads());
+        for(int i = 0 ; i < endpoint.getMaxThreads()/2 ; i++) {
+            connectionCache.addElement(new TcpConnection());
+        }
+    }
+
+    public void run() {
+        while(endpoint.running) {
+            Socket s = endpoint.acceptSocket();
+            if(null != s) {
+                // Continue accepting on another thread...
+                endpoint.tp.runIt(this);
+
+                TcpConnection con = null;
+                try {
+                   // XXX set socket options
+                   //   s.setSoLinger( true, 100);
+                   //   s.setSoTimeout( 1000 );
+                    try {
+                        con = (TcpConnection)connectionCache.lastElement();
+                        connectionCache.removeElementAt(connectionCache.size()
- 1);
+                    } catch(Throwable t) {
+                        con = new TcpConnection();
+                    }
+
+                   con.setEndpoint(endpoint);
+                   con.setSocket(s);
+                   endpoint.getConnectionHandler().processConnection(con,
null);
+                } finally {
+                    con.recycle();
+                    connectionCache.addElement(con);
+                }
+
+                break;
+            }
+        }
+    }
+}
+
 // Listener thread
 class TcpListenerThread implements Runnable {
     TcpEndpoint endpoint;
@@ -323,5 +436,3 @@
     handler.processConnection(connection, null);
     }
 }
-
-

*********************

cvs diff -u -w -B TcpEndpointConnector.java
Index: TcpEndpointConnector.java
===================================================================
RCS file:
/home/cvspublic/jakarta-tomcat/src/share/org/apache/tomcat/service/TcpEndpointConnector.java,v
retrieving revision 1.3
diff -u -w -B -r1.3 TcpEndpointConnector.java
--- TcpEndpointConnector.java 2000/02/09 23:26:28  1.3
+++ TcpEndpointConnector.java 2000/02/15 14:01:30
@@ -87,6 +87,7 @@
  * the TCP connection handler
  *
  * @author costin@eng.sun.com
+ * @author Gal Shachor [shachor@il.ibm.com]
  */
 public class TcpEndpointConnector  implements ServerConnector {
     // Attributes we accept ( to support the old model of
@@ -99,6 +100,19 @@
     public static final String VHOST_ADDRESS="vhost_address";
     public static final String SOCKET_FACTORY="socketFactory";

+
+    public static final String PORT = "port";
+    public static final String HANDLER = "handler";
+
+    /*
+     * Threading and mod_mpm style properties.
+     */
+    public static final String THREAD_POOL = "thread_pool";
+    public static final String MAX_THREADS = "max_threads";
+    public static final String MAX_SPARE_THREADS = "max_spare_threads";
+    public static final String MIN_SPARE_THREADS = "min_spare_threads";
+    public static final String BACKLOG = "backlog";
+
     // XXX define ConnectorException
     // XXX replace strings with sm.get...
     // XXX replace static strings with constants
@@ -111,6 +125,12 @@
     private InetAddress address;
     private int port;

+    private int backlog = -1;
+    private boolean usePools = true;
+    private int maxThreads = -1;
+    private int maxSpareThreads = -1;
+    private int minSpareThreads = -1;
+
     int vport;

     private ServerSocketFactory socketFactory;
@@ -123,9 +143,25 @@
     }

     public void start() throws Exception {
-    if( con==null) throw new Exception( "Invalid ConnectionHandler");
+         if(con==null)
+             throw new Exception( "Invalid ConnectionHandler");
+
     con.setAttribute("context.manager",cm );
     ep.setPort(port);
+         ep.setPoolOn(usePools);
+         if(backlog > 0) {
+             ep.setBacklog(backlog);
+         }
+         if(maxThreads > 0) {
+             ep.setMaxThreads(maxThreads);
+         }
+         if(maxSpareThreads > 0) {
+             ep.setMaxSpareThreads(maxSpareThreads);
+         }
+         if(minSpareThreads > 0)
{(maxSpareThreads);nHandler");dler");ads";vice/TcpEndpointConnector.java,v
+             ep.setMinSpareThreads(minSpareThreads);
+         }
+
     if( socketFactory != null) {
         ep.setServerSocketFactory( socketFactory );
     }
@@ -162,17 +198,27 @@
     }

     public void setProperty( String prop, String value) {
-    if("port".equals(prop) ) {(
+         if(PORT.equals(prop) ) {
         setPort( value );
-    }
-    if("handler".equals(prop)) {
+         } else if(HANDLER.equals(prop)) {
         try {
          Class chC=Class.forName( value );
          con=(TcpConnectionHandler)chC.newInstance();
         } catch( Exception ex) {
          ex.printStackTrace();
         }
-
+         } else if(THREAD_POOL.equals(prop)) {
+             if(value.equalsIgnoreCase("off")) {
+                 usePools = false;
+             }
+         } else if(MAX_THREADS.equals(prop)) {
+             maxThreads = string2Int(value);
+         } else if(MAX_SPARE_THREADS.equals(prop)) {
+             maxSpareThreads = string2Int(value);
+         } else if(MIN_SPARE_THREADS.equals(prop)) {
+             minSpareThreads = string2Int(value);
+         } else if(BACKLOG.equals(prop)) {
+             backlog = string2Int(value);
     }
     }

@@ -180,18 +226,13 @@
     public void setAttribute( String prop, Object value) {
     if(VHOST_NAME.equals(prop) ) {
         //vhost=(String)value;
-    }
-    if(VHOST_PORT.equals(prop) ) {
+        } else if(VHOST_PORT.equals(prop) ) {
         vport=((Integer)value).intValue();
-    }
-
-    if(VHOST_ADDRESS.equals(prop)) {
+        } else if(VHOST_ADDRESS.equals(prop)) {
         address=(InetAddress)value;
-    }
-    if(SERVER.equals(prop)) {
+        } else if(SERVER.equals(prop)) {
         //server=(HttpServer)value;
-    }
-    if(SOCKET_FACTORY.equals(prop)) {
+        } else if(SOCKET_FACTORY.equals(prop)) {
         socketFactory=(ServerSocketFactory)value;
     }
     }
@@ -207,9 +248,4 @@
         return 0;
     }
     }
-
-
-
 }
-
-

*********************

(See attached file: TcpConnection.java)(See attached file: TcpEndpoint.java)(See
attached file: TcpEndpointConnector.java)(See attached file: ThreadPool.java)
-------------------------------
Gal Shachor
IBM Research, Haifa Lab.
Email: shachor@il.ibm.com
Notes: Gal Shachor/Haifa/IBM@IBMIL
Phone: +972-4-8296164
Fax: +972-4-8550070
Address: IBM Haifa Research Lab, Matam, Haifa 31905, Israel

Re: [PATCH] Thread pool for the TCP connectors

Posted by "Anil K. Vijendran" <An...@eng.sun.com>.
Gal,

I'm trying to commit it and it seems like some lines (like below) are garbled. Can you please
resend files as attachments?

Thanks.

shachor@il.ibm.com wrote:

> +         } catch(Throwable e) {(socket);et();OExceptionort
>
> +    Socket acceptSocket() {(msg);something
>
> {(maxSpareThreads);nHandler");dler");ads";vice/TcpEndpointConnector.java,v

--
Peace, Anil +<:-)



Re: Vote: CVS committer - Re: [PATCH] Thread pool for the TCP connectors

Posted by Danno Ferrin <sh...@earthlink.net>.
+1

costin@eng.sun.com wrote:
> 
> Hi,
> 
> Please, a quick vote for Gal Shachor (shachor@il.ibm.com)- I don't think I
> have to list all the contributions ( my favorites are the NS, IIS and JNI
> connectors ).
> 
> Costin
> 
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: tomcat-dev-unsubscribe@jakarta.apache.org
> For additional commands, e-mail: tomcat-dev-help@jakarta.apache.org

Re: Vote: CVS committer - Re: [PATCH] Thread pool for the TCP connectors

Posted by "Anil K. Vijendran" <An...@eng.sun.com>.
+1 from me. I'll send an email to Brian.

"Craig R. McClanahan" wrote:

> +1 for Gal
>
> Craig
>
> costin@eng.sun.com wrote:
>
> > Hi,
> >
> > Please, a quick vote for Gal Shachor (shachor@il.ibm.com)- I don't think I
> > have to list all the contributions ( my favorites are the NS, IIS and JNI
> > connectors ).
> >
> > Costin
> >
> > ---------------------------------------------------------------------
> > To unsubscribe, e-mail: tomcat-dev-unsubscribe@jakarta.apache.org
> > For additional commands, e-mail: tomcat-dev-help@jakarta.apache.org
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: tomcat-dev-unsubscribe@jakarta.apache.org
> For additional commands, e-mail: tomcat-dev-help@jakarta.apache.org

--
Peace, Anil +<:-)



Re: Vote: CVS committer - Re: [PATCH] Thread pool for the TCP connectors

Posted by "Craig R. McClanahan" <cm...@mytownnet.com>.
+1 for Gal

Craig


costin@eng.sun.com wrote:

> Hi,
>
> Please, a quick vote for Gal Shachor (shachor@il.ibm.com)- I don't think I
> have to list all the contributions ( my favorites are the NS, IIS and JNI
> connectors ).
>
> Costin
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: tomcat-dev-unsubscribe@jakarta.apache.org
> For additional commands, e-mail: tomcat-dev-help@jakarta.apache.org


Vote: CVS committer - Re: [PATCH] Thread pool for the TCP connectors

Posted by co...@eng.sun.com.
Hi,

Please, a quick vote for Gal Shachor (shachor@il.ibm.com)- I don't think I
have to list all the contributions ( my favorites are the NS, IIS and JNI 
connectors ). 

Costin