AMQ-2091: Add a cache to the jms selector parser for speed improvements

git-svn-id: https://svn.apache.org/repos/asf/activemq/trunk@740375 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Guillaume Nodet 2009-02-03 19:05:07 +00:00
parent 5e2eedcac0
commit 1ab76f775d
11 changed files with 50 additions and 22 deletions

View File

@ -57,6 +57,7 @@ import java.util.*;
import javax.jms.InvalidSelectorException; import javax.jms.InvalidSelectorException;
import org.apache.activemq.filter.*; import org.apache.activemq.filter.*;
import org.apache.activemq.util.LRUCache;
/** /**
* JMS Selector Parser generated by JavaCC * JMS Selector Parser generated by JavaCC
@ -65,20 +66,44 @@ import org.apache.activemq.filter.*;
*/ */
public class SelectorParser { public class SelectorParser {
public SelectorParser() { private static final LRUCache cache = new LRUCache(100);
this(new StringReader(""));
public static BooleanExpression parse(String sql) throws InvalidSelectorException {
Object result = cache.get(sql);
if (result instanceof InvalidSelectorException) {
throw (InvalidSelectorException) result;
} else if (result instanceof BooleanExpression) {
return (BooleanExpression) result;
} else {
try {
BooleanExpression e = new SelectorParser(sql).parse();
cache.put(sql, e);
return e;
} catch (InvalidSelectorException t) {
cache.put(sql, t);
throw t;
}
}
} }
public BooleanExpression parse(String sql) throws InvalidSelectorException { public static void clearCache() {
this.ReInit(new StringReader(sql)); cache.clear();
}
private String sql;
protected SelectorParser(String sql) {
this(new StringReader(sql));
this.sql = sql;
}
protected BooleanExpression parse() throws InvalidSelectorException {
try { try {
return this.JmsSelector(); return this.JmsSelector();
} }
catch (Throwable e) { catch (Throwable e) {
throw (InvalidSelectorException) new InvalidSelectorException(sql).initCause(e); throw (InvalidSelectorException) new InvalidSelectorException(sql).initCause(e);
} }
} }
private BooleanExpression asBooleanExpression(Expression value) throws ParseException { private BooleanExpression asBooleanExpression(Expression value) throws ParseException {

View File

@ -91,7 +91,7 @@ public class ActiveMQInputStream extends InputStream implements ActiveMQDispatch
selector = "JMSType='org.apache.activemq.Stream'"; selector = "JMSType='org.apache.activemq.Stream'";
} }
new SelectorParser().parse(selector); SelectorParser.parse(selector);
this.info.setSelector(selector); this.info.setSelector(selector);
this.info.setPrefetchSize(prefetch); this.info.setPrefetchSize(prefetch);

View File

@ -200,12 +200,12 @@ public class ActiveMQMessageConsumer implements MessageAvailableConsumer, StatsC
this.info.setBrowser(browser); this.info.setBrowser(browser);
if (selector != null && selector.trim().length() != 0) { if (selector != null && selector.trim().length() != 0) {
// Validate the selector // Validate the selector
new SelectorParser().parse(selector); SelectorParser.parse(selector);
this.info.setSelector(selector); this.info.setSelector(selector);
this.selector = selector; this.selector = selector;
} else if (info.getSelector() != null) { } else if (info.getSelector() != null) {
// Validate the selector // Validate the selector
new SelectorParser().parse(this.info.getSelector()); SelectorParser.parse(this.info.getSelector());
this.selector = this.info.getSelector(); this.selector = this.info.getSelector();
} else { } else {
this.selector = null; this.selector = null;

View File

@ -35,6 +35,7 @@ import javax.management.MalformedObjectNameException;
import javax.management.ObjectName; import javax.management.ObjectName;
import org.apache.activemq.ActiveMQConnectionMetaData; import org.apache.activemq.ActiveMQConnectionMetaData;
import org.apache.activemq.Service; import org.apache.activemq.Service;
import org.apache.activemq.selector.SelectorParser;
import org.apache.activemq.advisory.AdvisoryBroker; import org.apache.activemq.advisory.AdvisoryBroker;
import org.apache.activemq.broker.cluster.ConnectionSplitBroker; import org.apache.activemq.broker.cluster.ConnectionSplitBroker;
import org.apache.activemq.broker.ft.MasterConnector; import org.apache.activemq.broker.ft.MasterConnector;
@ -530,6 +531,8 @@ public class BrokerService implements Service {
} }
stopper.stop(getManagementContext()); stopper.stop(getManagementContext());
} }
// Clear SelectorParser cache to free memory
SelectorParser.clearCache();
stopped.set(true); stopped.set(true);
stoppedLatch.countDown(); stoppedLatch.countDown();
LOG.info("ActiveMQ JMS Message Broker (" + getBrokerName() + ", " + brokerId + ") stopped"); LOG.info("ActiveMQ JMS Message Broker (" + getBrokerName() + ", " + brokerId + ") stopped");

View File

@ -141,7 +141,7 @@ public class DestinationView implements DestinationViewMBean {
MessageEvaluationContext ctx = new MessageEvaluationContext(); MessageEvaluationContext ctx = new MessageEvaluationContext();
ctx.setDestination(destination.getActiveMQDestination()); ctx.setDestination(destination.getActiveMQDestination());
BooleanExpression selectorExpression = selector == null ? null : new SelectorParser().parse(selector); BooleanExpression selectorExpression = selector == null ? null : SelectorParser.parse(selector);
for (int i = 0; i < messages.length; i++) { for (int i = 0; i < messages.length; i++) {
try { try {
@ -186,7 +186,7 @@ public class DestinationView implements DestinationViewMBean {
MessageEvaluationContext ctx = new MessageEvaluationContext(); MessageEvaluationContext ctx = new MessageEvaluationContext();
ctx.setDestination(destination.getActiveMQDestination()); ctx.setDestination(destination.getActiveMQDestination());
BooleanExpression selectorExpression = selector == null ? null : new SelectorParser().parse(selector); BooleanExpression selectorExpression = selector == null ? null : SelectorParser.parse(selector);
for (int i = 0; i < messages.length; i++) { for (int i = 0; i < messages.length; i++) {
try { try {
@ -224,7 +224,7 @@ public class DestinationView implements DestinationViewMBean {
MessageEvaluationContext ctx = new MessageEvaluationContext(); MessageEvaluationContext ctx = new MessageEvaluationContext();
ctx.setDestination(destination.getActiveMQDestination()); ctx.setDestination(destination.getActiveMQDestination());
BooleanExpression selectorExpression = selector == null ? null : new SelectorParser().parse(selector); BooleanExpression selectorExpression = selector == null ? null : SelectorParser.parse(selector);
for (int i = 0; i < messages.length; i++) { for (int i = 0; i < messages.length; i++) {
try { try {

View File

@ -60,7 +60,7 @@ public abstract class AbstractSubscription implements Subscription {
private static BooleanExpression parseSelector(ConsumerInfo info) throws InvalidSelectorException { private static BooleanExpression parseSelector(ConsumerInfo info) throws InvalidSelectorException {
BooleanExpression rc = null; BooleanExpression rc = null;
if (info.getSelector() != null) { if (info.getSelector() != null) {
rc = new SelectorParser().parse(info.getSelector()); rc = SelectorParser.parse(info.getSelector());
} }
if (info.isNoLocal()) { if (info.isNoLocal()) {
if (rc == null) { if (rc == null) {

View File

@ -1105,7 +1105,7 @@ public class Queue extends BaseDestination implements Task {
} }
protected MessageReferenceFilter createSelectorFilter(String selector) throws InvalidSelectorException { protected MessageReferenceFilter createSelectorFilter(String selector) throws InvalidSelectorException {
final BooleanExpression selectorExpression = new SelectorParser().parse(selector); final BooleanExpression selectorExpression = SelectorParser.parse(selector);
return new MessageReferenceFilter() { return new MessageReferenceFilter() {
public boolean evaluate(ConnectionContext context, MessageReference r) throws JMSException { public boolean evaluate(ConnectionContext context, MessageReference r) throws JMSException {

View File

@ -66,7 +66,7 @@ public class FilteredDestination {
*/ */
public void setSelector(String selector) throws InvalidSelectorException { public void setSelector(String selector) throws InvalidSelectorException {
this.selector = selector; this.selector = selector;
setFilter(new SelectorParser().parse(selector)); setFilter(SelectorParser.parse(selector));
} }
public BooleanExpression getFilter() { public BooleanExpression getFilter() {

View File

@ -68,6 +68,6 @@ public class SelectorParserTest extends TestCase {
} }
protected BooleanExpression parse(String text) throws Exception { protected BooleanExpression parse(String text) throws Exception {
return new SelectorParser().parse(text); return SelectorParser.parse(text);
} }
} }

View File

@ -352,14 +352,14 @@ public class SelectorTest extends TestCase {
protected void assertInvalidSelector(Message message, String text) throws JMSException { protected void assertInvalidSelector(Message message, String text) throws JMSException {
try { try {
new SelectorParser().parse(text); SelectorParser.parse(text);
fail("Created a valid selector"); fail("Created a valid selector");
} catch (InvalidSelectorException e) { } catch (InvalidSelectorException e) {
} }
} }
protected void assertSelector(Message message, String text, boolean expected) throws JMSException { protected void assertSelector(Message message, String text, boolean expected) throws JMSException {
BooleanExpression selector = new SelectorParser().parse(text); BooleanExpression selector = SelectorParser.parse(text);
assertTrue("Created a valid selector", selector != null); assertTrue("Created a valid selector", selector != null);
MessageEvaluationContext context = new MessageEvaluationContext(); MessageEvaluationContext context = new MessageEvaluationContext();
context.setMessageReference((org.apache.activemq.command.Message)message); context.setMessageReference((org.apache.activemq.command.Message)message);

View File

@ -165,7 +165,7 @@ public class ActiveMQActivationSpec implements MessageActivationSpec, Serializab
public boolean isValidMessageSelector(List<String> errorMessages) { public boolean isValidMessageSelector(List<String> errorMessages) {
try { try {
if (!isEmpty(messageSelector)) { if (!isEmpty(messageSelector)) {
new SelectorParser().parse(messageSelector); SelectorParser.parse(messageSelector);
} }
return true; return true;
} catch (Throwable e) { } catch (Throwable e) {