cassandra-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From tylerho...@apache.org
Subject git commit: Don't re-parse already prepared statements
Date Tue, 07 Oct 2014 23:00:41 GMT
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 <tyler@datastax.com>
Authored: Tue Oct 7 17:59:43 2014 -0500
Committer: Tyler Hobbs <tyler@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();
         }


Mime
View raw message