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