Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.annotation.concurrent.ThreadSafe;

import com.github.benmanes.caffeine.cache.Cache;
import com.github.benmanes.caffeine.cache.Caffeine;
import org.antlr.v4.runtime.ANTLRInputStream;
import org.antlr.v4.runtime.BailErrorStrategy;
import org.antlr.v4.runtime.BaseErrorListener;
Expand Down Expand Up @@ -73,6 +76,13 @@ public class Pql2Compiler implements AbstractCompiler {
public static String ENABLE_DISTINCT_KEY = "pinot.distinct.enabled";
public static boolean ENABLE_DISTINCT = Boolean.valueOf(System.getProperty(ENABLE_DISTINCT_KEY, "true"));

private static final int REQUEST_CACHE_SIZE = 1_000;
private static final int TRANSFORM_CACHE_SIZE = 1_000;

private static final Cache<String, BrokerRequest> _brokerRequestCache = Caffeine.newBuilder().maximumSize(REQUEST_CACHE_SIZE).build();
private static final Cache<String, BrokerRequest> _brokerRequestCacheWithPinotQuery = Caffeine.newBuilder().maximumSize(REQUEST_CACHE_SIZE).build();
private static final Cache<String, TransformExpressionTree> _expressionTreeCache = Caffeine.newBuilder().maximumSize(TRANSFORM_CACHE_SIZE).build();

private static class ErrorListener extends BaseErrorListener {

@Override
Expand All @@ -84,6 +94,14 @@ public void syntaxError(@Nonnull Recognizer<?, ?> recognizer, @Nullable Object o

private static final ErrorListener ERROR_LISTENER = new ErrorListener();

private static Cache<String, BrokerRequest> getBrokerRequestCache() {
if (ENABLE_PINOT_QUERY) {
return _brokerRequestCacheWithPinotQuery;
}

return _brokerRequestCache;
}

/**
* Compile the given expression into {@link BrokerRequest}.
*
Expand All @@ -94,7 +112,13 @@ public void syntaxError(@Nonnull Recognizer<?, ?> recognizer, @Nullable Object o
public BrokerRequest compileToBrokerRequest(String expression)
throws Pql2CompilationException {
try {
//
// Try to load previously cached result
BrokerRequest cached = getBrokerRequestCache().getIfPresent(expression);
if (cached != null) {
return cached.deepCopy();
}

// Initialize
CharStream charStream = new ANTLRInputStream(expression);
PQL2Lexer lexer = new PQL2Lexer(charStream);
lexer.setTokenFactory(new CommonTokenFactory(true));
Expand Down Expand Up @@ -144,7 +168,11 @@ public BrokerRequest compileToBrokerRequest(String expression)
}
}
}
return brokerRequest;

// Cache parsed broker request for reuse
getBrokerRequestCache().put(expression, brokerRequest);

return brokerRequest.deepCopy();
} catch (Pql2CompilationException e) {
throw e;
} catch (Exception e) {
Expand All @@ -153,6 +181,13 @@ public BrokerRequest compileToBrokerRequest(String expression)
}

public TransformExpressionTree compileToExpressionTree(String expression) {
// Check for cached expression tree
TransformExpressionTree transformExpressionTree = _expressionTreeCache.getIfPresent(expression);
if (transformExpressionTree != null) {
return transformExpressionTree;
}

// Initialize
CharStream charStream = new ANTLRInputStream(expression);
PQL2Lexer lexer = new PQL2Lexer(charStream);
lexer.setTokenFactory(new CommonTokenFactory(true));
Expand All @@ -167,7 +202,11 @@ public TransformExpressionTree compileToExpressionTree(String expression) {
Pql2AstListener listener = new Pql2AstListener(expression);
walker.walk(listener, parseTree);

return new TransformExpressionTree(listener.getRootNode());
// Cache result for future reuse
transformExpressionTree = new TransformExpressionTree(listener.getRootNode());
_expressionTreeCache.put(expression, transformExpressionTree);

return transformExpressionTree;
}

private void validateHavingClause(AstNode rootNode) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@
import org.testng.Assert;
import org.testng.annotations.Test;

import static junit.framework.Assert.*;


/**
* Some tests for the PQL 2 compiler.
Expand Down Expand Up @@ -476,4 +478,34 @@ private void testOrderBy(String pql, List<String> orderBys, List<Boolean> isAscs
Assert.assertEquals(orderBy.isIsAsc(), isAscs.get(i).booleanValue());
}
}

/**
* Test that ensures we are properly caching requests for performance reasons
*/
@Test
public void testQueryCaching() {
final String PQL = "select * from table order by d2 asc, d3 desc";
final String PQL1 = "select * from table order by d2, d3 desc";
final String EXP = "`a.b.c`";
final String EXP1 = "`a.b.d`";

BrokerRequest brokerRequest = COMPILER.compileToBrokerRequest(PQL);
BrokerRequest secondBrokerRequest = COMPILER.compileToBrokerRequest(PQL1);
BrokerRequest redoBrokerRequest = COMPILER.compileToBrokerRequest(PQL);

assertEquals(brokerRequest, redoBrokerRequest);
// This is completely different Broker Request
assertFalse(brokerRequest == secondBrokerRequest);
// Identity equality won't work because we do deepCopy since broker request options are mutable
assertFalse(brokerRequest == redoBrokerRequest);

TransformExpressionTree expTree = COMPILER.compileToExpressionTree(EXP);
TransformExpressionTree secondExpTree = COMPILER.compileToExpressionTree(EXP1);
TransformExpressionTree redoExpTree = COMPILER.compileToExpressionTree(EXP);

// This is completely different Broker Request
assertFalse(expTree == secondExpTree);
// Identity equality should work because we have cached the previous request
assertTrue(expTree == redoExpTree);
}
}