You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cassandra.apache.org by ty...@apache.org on 2014/10/08 01:00:41 UTC
git commit: Don't re-parse already prepared statements
Repository: cassandra
Updated Branches:
refs/heads/cassandra-2.1 ed1681a47 -> 24c181ff7
Don't re-parse already prepared statements
Patch by Benedict Elliot Smith and Tyler Hobbs; reviewed by Aleksey
Yeschenko for CASSANDRA-7923
Project: http://git-wip-us.apache.org/repos/asf/cassandra/repo
Commit: http://git-wip-us.apache.org/repos/asf/cassandra/commit/24c181ff
Tree: http://git-wip-us.apache.org/repos/asf/cassandra/tree/24c181ff
Diff: http://git-wip-us.apache.org/repos/asf/cassandra/diff/24c181ff
Branch: refs/heads/cassandra-2.1
Commit: 24c181ff754d629094f5210f5a53bcad1d0aa81d
Parents: ed1681a
Author: Tyler Hobbs <ty...@datastax.com>
Authored: Tue Oct 7 17:59:43 2014 -0500
Committer: Tyler Hobbs <ty...@datastax.com>
Committed: Tue Oct 7 17:59:43 2014 -0500
----------------------------------------------------------------------
CHANGES.txt | 1 +
.../org/apache/cassandra/cql3/QueryHandler.java | 2 +-
.../apache/cassandra/cql3/QueryProcessor.java | 70 ++++++++++++++------
.../cassandra/thrift/CassandraServer.java | 9 +--
4 files changed, 57 insertions(+), 25 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/cassandra/blob/24c181ff/CHANGES.txt
----------------------------------------------------------------------
diff --git a/CHANGES.txt b/CHANGES.txt
index 0595767..b6299c7 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -1,4 +1,5 @@
2.1.1
+ * Avoid re-parsing already prepared statements (CASSANDRA-7923)
* Fix some Thrift slice deletions and updates of COMPACT STORAGE
tables with some clustering columns omitted (CASSANDRA-7990)
* Fix filtering for CONTAINS on sets (CASSANDRA-8033)
http://git-wip-us.apache.org/repos/asf/cassandra/blob/24c181ff/src/java/org/apache/cassandra/cql3/QueryHandler.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/QueryHandler.java b/src/java/org/apache/cassandra/cql3/QueryHandler.java
index 2f28812..d42d90e 100644
--- a/src/java/org/apache/cassandra/cql3/QueryHandler.java
+++ b/src/java/org/apache/cassandra/cql3/QueryHandler.java
@@ -30,7 +30,7 @@ public interface QueryHandler
public ResultMessage process(String query, QueryState state, QueryOptions options) throws RequestExecutionException, RequestValidationException;
public ResultMessage.Prepared prepare(String query, QueryState state) throws RequestValidationException;
public ParsedStatement.Prepared getPrepared(MD5Digest id);
- public CQLStatement getPreparedForThrift(Integer id);
+ public ParsedStatement.Prepared getPreparedForThrift(Integer id);
public ResultMessage processPrepared(CQLStatement statement, QueryState state, QueryOptions options) throws RequestExecutionException, RequestValidationException;
public ResultMessage processBatch(BatchStatement statement, QueryState state, BatchQueryOptions options) throws RequestExecutionException, RequestValidationException;
}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/24c181ff/src/java/org/apache/cassandra/cql3/QueryProcessor.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/QueryProcessor.java b/src/java/org/apache/cassandra/cql3/QueryProcessor.java
index 0c75642..2818358 100644
--- a/src/java/org/apache/cassandra/cql3/QueryProcessor.java
+++ b/src/java/org/apache/cassandra/cql3/QueryProcessor.java
@@ -68,17 +68,17 @@ public class QueryProcessor implements QueryHandler
}
};
- private static EntryWeigher<Integer, CQLStatement> thriftMemoryUsageWeigher = new EntryWeigher<Integer, CQLStatement>()
+ private static EntryWeigher<Integer, ParsedStatement.Prepared> thriftMemoryUsageWeigher = new EntryWeigher<Integer, ParsedStatement.Prepared>()
{
@Override
- public int weightOf(Integer key, CQLStatement value)
+ public int weightOf(Integer key, ParsedStatement.Prepared value)
{
- return Ints.checkedCast(measure(key) + measure(value));
+ return Ints.checkedCast(measure(key) + measure(value.statement) + measure(value.boundNames));
}
};
private static final ConcurrentLinkedHashMap<MD5Digest, ParsedStatement.Prepared> preparedStatements;
- private static final ConcurrentLinkedHashMap<Integer, CQLStatement> thriftPreparedStatements;
+ private static final ConcurrentLinkedHashMap<Integer, ParsedStatement.Prepared> thriftPreparedStatements;
// A map for prepared statements used internally (which we don't want to mix with user statement, in particular we don't
// bother with expiration on those.
@@ -104,12 +104,12 @@ public class QueryProcessor implements QueryHandler
}
}).build();
- thriftPreparedStatements = new ConcurrentLinkedHashMap.Builder<Integer, CQLStatement>()
+ thriftPreparedStatements = new ConcurrentLinkedHashMap.Builder<Integer, ParsedStatement.Prepared>()
.maximumWeightedCapacity(MAX_CACHE_PREPARED_MEMORY)
.weigher(thriftMemoryUsageWeigher)
- .listener(new EvictionListener<Integer, CQLStatement>()
+ .listener(new EvictionListener<Integer, ParsedStatement.Prepared>()
{
- public void onEviction(Integer integer, CQLStatement cqlStatement)
+ public void onEviction(Integer integer, ParsedStatement.Prepared prepared)
{
metrics.preparedStatementsEvicted.inc();
lastMinuteEvictionsCount.incrementAndGet();
@@ -172,7 +172,7 @@ public class QueryProcessor implements QueryHandler
return preparedStatements.get(id);
}
- public CQLStatement getPreparedForThrift(Integer id)
+ public ParsedStatement.Prepared getPreparedForThrift(Integer id)
{
return thriftPreparedStatements.get(id);
}
@@ -392,6 +392,10 @@ public class QueryProcessor implements QueryHandler
public static ResultMessage.Prepared prepare(String queryString, ClientState clientState, boolean forThrift)
throws RequestValidationException
{
+ ResultMessage.Prepared existing = getStoredPreparedStatement(queryString, clientState.getRawKeyspace(), forThrift);
+ if (existing != null)
+ return existing;
+
ParsedStatement.Prepared prepared = getStatement(queryString, clientState);
int boundTerms = prepared.statement.getBoundTerms();
if (boundTerms > FBUtilities.MAX_UNSIGNED_SHORT)
@@ -401,12 +405,40 @@ public class QueryProcessor implements QueryHandler
return storePreparedStatement(queryString, clientState.getRawKeyspace(), prepared, forThrift);
}
+ private static MD5Digest computeId(String queryString, String keyspace)
+ {
+ String toHash = keyspace == null ? queryString : keyspace + queryString;
+ return MD5Digest.compute(toHash);
+ }
+
+ private static Integer computeThriftId(String queryString, String keyspace)
+ {
+ String toHash = keyspace == null ? queryString : keyspace + queryString;
+ return toHash.hashCode();
+ }
+
+ private static ResultMessage.Prepared getStoredPreparedStatement(String queryString, String keyspace, boolean forThrift)
+ throws InvalidRequestException
+ {
+ if (forThrift)
+ {
+ Integer thriftStatementId = computeThriftId(queryString, keyspace);
+ ParsedStatement.Prepared existing = thriftPreparedStatements.get(thriftStatementId);
+ return existing == null ? null : ResultMessage.Prepared.forThrift(thriftStatementId, existing.boundNames);
+ }
+ else
+ {
+ MD5Digest statementId = computeId(queryString, keyspace);
+ ParsedStatement.Prepared existing = preparedStatements.get(statementId);
+ return existing == null ? null : new ResultMessage.Prepared(statementId, existing);
+ }
+ }
+
private static ResultMessage.Prepared storePreparedStatement(String queryString, String keyspace, ParsedStatement.Prepared prepared, boolean forThrift)
throws InvalidRequestException
{
// Concatenate the current keyspace so we don't mix prepared statements between keyspace (#5352).
// (if the keyspace is null, queryString has to have a fully-qualified keyspace so it's fine.
- String toHash = keyspace == null ? queryString : keyspace + queryString;
long statementSize = measure(prepared.statement);
// don't execute the statement if it's bigger than the allowed threshold
if (statementSize > MAX_CACHE_PREPARED_MEMORY)
@@ -415,13 +447,13 @@ public class QueryProcessor implements QueryHandler
MAX_CACHE_PREPARED_MEMORY));
if (forThrift)
{
- int statementId = toHash.hashCode();
- thriftPreparedStatements.put(statementId, prepared.statement);
+ Integer statementId = computeThriftId(queryString, keyspace);
+ thriftPreparedStatements.put(statementId, prepared);
return ResultMessage.Prepared.forThrift(statementId, prepared.boundNames);
}
else
{
- MD5Digest statementId = MD5Digest.compute(toHash);
+ MD5Digest statementId = computeId(queryString, keyspace);
preparedStatements.put(statementId, prepared);
return new ResultMessage.Prepared(statementId, prepared);
}
@@ -521,19 +553,17 @@ public class QueryProcessor implements QueryHandler
{
private void removeInvalidPreparedStatements(String ksName, String cfName)
{
- Iterator<ParsedStatement.Prepared> iterator = preparedStatements.values().iterator();
+ removeInvalidPreparedStatements(preparedStatements.values().iterator(), ksName, cfName);
+ removeInvalidPreparedStatements(thriftPreparedStatements.values().iterator(), ksName, cfName);
+ }
+
+ private void removeInvalidPreparedStatements(Iterator<ParsedStatement.Prepared> iterator, String ksName, String cfName)
+ {
while (iterator.hasNext())
{
if (shouldInvalidate(ksName, cfName, iterator.next().statement))
iterator.remove();
}
-
- Iterator<CQLStatement> thriftIterator = thriftPreparedStatements.values().iterator();
- while (thriftIterator.hasNext())
- {
- if (shouldInvalidate(ksName, cfName, thriftIterator.next()))
- thriftIterator.remove();
- }
}
private boolean shouldInvalidate(String ksName, String cfName, CQLStatement statement)
http://git-wip-us.apache.org/repos/asf/cassandra/blob/24c181ff/src/java/org/apache/cassandra/thrift/CassandraServer.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/thrift/CassandraServer.java b/src/java/org/apache/cassandra/thrift/CassandraServer.java
index a4f25b8..2e76ee4 100644
--- a/src/java/org/apache/cassandra/thrift/CassandraServer.java
+++ b/src/java/org/apache/cassandra/thrift/CassandraServer.java
@@ -48,6 +48,7 @@ import org.apache.cassandra.config.Schema;
import org.apache.cassandra.cql.CQLStatement;
import org.apache.cassandra.cql.QueryProcessor;
import org.apache.cassandra.cql3.QueryOptions;
+import org.apache.cassandra.cql3.statements.ParsedStatement;
import org.apache.cassandra.db.*;
import org.apache.cassandra.db.composites.*;
import org.apache.cassandra.db.context.CounterContext;
@@ -2164,16 +2165,16 @@ public class CassandraServer implements Cassandra.Iface
try
{
ThriftClientState cState = state();
- org.apache.cassandra.cql3.CQLStatement statement = cState.getCQLQueryHandler().getPreparedForThrift(itemId);
+ ParsedStatement.Prepared prepared = cState.getCQLQueryHandler().getPreparedForThrift(itemId);
- if (statement == null)
+ if (prepared == null)
throw new InvalidRequestException(String.format("Prepared query with ID %d not found" +
" (either the query was not prepared on this host (maybe the host has been restarted?)" +
" or you have prepared too many queries and it has been evicted from the internal cache)",
itemId));
- logger.trace("Retrieved prepared statement #{} with {} bind markers", itemId, statement.getBoundTerms());
+ logger.trace("Retrieved prepared statement #{} with {} bind markers", itemId, prepared.statement.getBoundTerms());
- return cState.getCQLQueryHandler().processPrepared(statement,
+ return cState.getCQLQueryHandler().processPrepared(prepared.statement,
cState.getQueryState(),
QueryOptions.fromProtocolV2(ThriftConversion.fromThrift(cLevel), bindVariables)).toThriftResult();
}