I'm submitting this with mixed feelings since the recent discussion has
shown strong opinions about the utility of the SingleThreadModel.
I was already in the middle of doing the work when all that came about so I
went ahead and finished it. After reaping the benefits of Tomcat for a
couple of years I've been wanting to give something back. So after a recent
post about how to help, I went into bugzilla and found this issue. I don't
even use STM, but was somewhat familiar with the ServletHandler and figured
I could contribute here.
At a minimum, I had fun doing the work and was able to learn a bit more
about the code base.
Maybe it will be of some use to others.
Looking forward to more good stuff from this project!!
-David
--- ServletHandler.java.orig Thu Oct 4 15:57:50 2001
+++ ServletHandler.java Thu Oct 4 16:06:28 2001
@@ -59,7 +59,7 @@
package org.apache.tomcat.facade;
import org.apache.tomcat.core.*;
-import org.apache.tomcat.util.*;
+import org.apache.tomcat.util.collections.*;
import java.io.*;
import java.net.*;
import java.util.*;
@@ -106,11 +106,18 @@
public static final int STATE_READY=3;
// -------------------- Properties --------------------
+
+ public static final String STM_POOL_SIZE = "tomcat.stmpoolsize";
// extra informations - if the servlet is declared in web.xml
private ServletInfo sw;
private String servletClassName;
+
+ private SimplePool stmPool; // pool of SingleThreadModel instances
+ private int stmPoolSize;
+ private int stmInstances; // number of servlet instances already being pooled
+(we create them as needed)
+
protected Class servletClass;
protected Servlet servlet;
protected Context context;
@@ -153,7 +160,6 @@
return context;
}
-
public void setServletClassName( String servletClassName) {
servlet=null; // reset the servlet, if it was set
servletClass=null;
@@ -192,7 +198,6 @@
} catch( Exception ex ) {
log(context, "Error during destroy ", ex );
}
-
errorException=null;
}
@@ -330,6 +335,14 @@
}
servlet = (Servlet)servletClass.newInstance();
+
+ if (servlet instanceof SingleThreadModel) {
+ stmPoolSize = Integer.getInteger(STM_POOL_SIZE,
+SimplePool.DEFAULT_SIZE).intValue();
+ stmPool = new SimplePool(stmPoolSize);
+ stmPool.set(servlet);
+ stmInstances++;
+ }
+
return servlet;
}
@@ -348,7 +361,15 @@
log(context, "preServletDestroy", ex);
}
}
- servlet.destroy();
+
+ if (!(servlet instanceof SingleThreadModel)) {
+ servlet.destroy();
+ } else {
+ Servlet sl = null;
+ while ((sl = (Servlet)stmPool.get()) != null) {
+ sl.destroy();
+ }
+ }
for( int i=0; i< cI.length; i++ ) {
try {
@@ -432,6 +453,40 @@
super.service( req, res );
}
+ protected void doSTMService(HttpServletRequest reqF, HttpServletResponse resF)
+throws Exception {
+ Servlet sl = null;
+ try {
+ boolean newInstance = false;
+ if ((sl = (Servlet)stmPool.get()) == null) {
+ synchronized (this) {
+ if (stmInstances < stmPoolSize) {
+ stmInstances++;
+ newInstance = true;
+ }
+ }
+ if (newInstance) {
+ sl = (Servlet)servletClass.newInstance();
+ sl.init(getServletInfo().getServletConfig());
+ }
+
+ }
+
+ if (sl != null) {
+ sl.service(reqF, resF);
+ } else {
+ // The pool is full, just synchronize on the initial instance.
+ // Ideally, we would the pain across all pooled instances
+ // to avoid a bottleneck on a single instance.
+ synchronized(servlet) {
+ servlet.service(reqF, resF);
+ }
+ }
+ } finally {
+ if (sl != null) {
+ stmPool.put(sl);
+ }
+ }
+ }
protected void doService(Request req, Response res)
throws Exception
@@ -476,10 +531,8 @@
try {
// We are initialized and fine
- if (servlet instanceof SingleThreadModel) {
- synchronized(servlet) {
- servlet.service(reqF, resF);
- }
+ if ( servlet instanceof SingleThreadModel ) {
+ doSTMService(reqF, resF);
} else {
servlet.service(reqF, resF);
}