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); }