You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tomcat.apache.org by ma...@apache.org on 2015/01/21 15:49:25 UTC
svn commit: r1653546 -
/tomcat/trunk/java/org/apache/el/lang/ExpressionBuilder.java
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-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org