Author: markt Date: Wed Jan 21 14:49:25 2015 New Revision: 1653546 URL: http://svn.apache.org/r1653546 Log: Add an ELParser cache to the ExpressionBuilder. Re-using ELParser instances is measureably more efficient.
Modified: tomcat/trunk/java/org/apache/el/lang/ExpressionBuilder.java Modified: tomcat/trunk/java/org/apache/el/lang/ExpressionBuilder.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/el/lang/ExpressionBuilder.java?rev=1653546&r1=1653545&r2=1653546&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/el/lang/ExpressionBuilder.java (original) +++ tomcat/trunk/java/org/apache/el/lang/ExpressionBuilder.java Wed Jan 21 14:49:25 2015 @@ -14,7 +14,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package org.apache.el.lang; import java.io.StringReader; @@ -49,6 +48,8 @@ import org.apache.el.util.MessageFactory */ public final class ExpressionBuilder implements NodeVisitor { + private static final SynchronizedStack<ELParser> parserCache = new SynchronizedStack<>(); + private static final int CACHE_SIZE; private static final String CACHE_SIZE_PROP = "org.apache.el.ExpressionBuilder.CACHE_SIZE"; @@ -70,7 +71,7 @@ public final class ExpressionBuilder imp } } - private static final ConcurrentCache<String, Node> cache = + private static final ConcurrentCache<String, Node> expressionCache = new ConcurrentCache<>(CACHE_SIZE); private FunctionMapper fnMapper; @@ -105,11 +106,16 @@ public final class ExpressionBuilder imp throw new ELException(MessageFactory.get("error.null")); } - Node n = cache.get(expr); + Node n = expressionCache.get(expr); if (n == null) { + ELParser parser = parserCache.pop(); try { - n = (new ELParser(new StringReader(expr))) - .CompositeExpression(); + if (parser == null) { + parser = new ELParser(new StringReader(expr)); + } else { + parser.ReInit(new StringReader(expr)); + } + n = parser.CompositeExpression(); // validate composite expression int numChildren = n.jjtGetNumChildren(); @@ -137,10 +143,14 @@ public final class ExpressionBuilder imp || n instanceof AstDynamicExpression) { n = n.jjtGetChild(0); } - cache.put(expr, n); + expressionCache.put(expr, n); } catch (Exception e) { throw new ELException( MessageFactory.get("error.parseFail", expr), e); + } finally { + if (parser != null) { + parserCache.push(parser); + } } } return n; @@ -252,4 +262,76 @@ public final class ExpressionBuilder imp + expression); } } + + /* + * Copied from org.apache.tomcat.util.collections.SynchronizedStack since + * we don't want the EL implementation to depend on the JAR where that + * class resides. + */ + private static class SynchronizedStack<T> { + + public static final int DEFAULT_SIZE = 128; + private static final int DEFAULT_LIMIT = -1; + + private int size; + private final int limit; + + /* + * Points to the next available object in the stack + */ + private int index = -1; + + private Object[] stack; + + + public SynchronizedStack() { + this(DEFAULT_SIZE, DEFAULT_LIMIT); + } + + public SynchronizedStack(int size, int limit) { + this.size = size; + this.limit = limit; + stack = new Object[size]; + } + + + public synchronized boolean push(T obj) { + index++; + if (index == size) { + if (limit == -1 || size < limit) { + expand(); + } else { + index--; + return false; + } + } + stack[index] = obj; + return true; + } + + @SuppressWarnings("unchecked") + public synchronized T pop() { + if (index == -1) { + return null; + } + T result = (T) stack[index]; + stack[index--] = null; + return result; + } + + private void expand() { + int newSize = size * 2; + if (limit != -1 && newSize > limit) { + newSize = limit; + } + Object[] newStack = new Object[newSize]; + System.arraycopy(stack, 0, newStack, 0, size); + // This is the only point where garbage is created by throwing away the + // old array. Note it is only the array, not the contents, that becomes + // garbage. + stack = newStack; + size = newSize; + } + } + } --------------------------------------------------------------------- To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org For additional commands, e-mail: dev-h...@tomcat.apache.org