You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cassandra.apache.org by sl...@apache.org on 2016/09/13 08:53:00 UTC

[5/8] cassandra git commit: Separate static conditions in CQL3CasRequest and use name queries when we can

Separate static conditions in CQL3CasRequest and use name queries when we can


Project: http://git-wip-us.apache.org/repos/asf/cassandra/repo
Commit: http://git-wip-us.apache.org/repos/asf/cassandra/commit/578450b9
Tree: http://git-wip-us.apache.org/repos/asf/cassandra/tree/578450b9
Diff: http://git-wip-us.apache.org/repos/asf/cassandra/diff/578450b9

Branch: refs/heads/12060-3.0-v2
Commit: 578450b9bb6b285241448686f402fd262fe56f10
Parents: 28d4e8e
Author: Sylvain Lebresne <sy...@datastax.com>
Authored: Fri Sep 2 10:58:59 2016 +0200
Committer: Sylvain Lebresne <sy...@datastax.com>
Committed: Mon Sep 12 11:50:21 2016 +0200

----------------------------------------------------------------------
 .../cql3/statements/CQL3CasRequest.java         | 101 ++++++++++++-------
 1 file changed, 62 insertions(+), 39 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cassandra/blob/578450b9/src/java/org/apache/cassandra/cql3/statements/CQL3CasRequest.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/statements/CQL3CasRequest.java b/src/java/org/apache/cassandra/cql3/statements/CQL3CasRequest.java
index f556580..6ce05f3 100644
--- a/src/java/org/apache/cassandra/cql3/statements/CQL3CasRequest.java
+++ b/src/java/org/apache/cassandra/cql3/statements/CQL3CasRequest.java
@@ -26,10 +26,7 @@ import com.google.common.collect.Multimap;
 import org.apache.cassandra.config.CFMetaData;
 import org.apache.cassandra.cql3.*;
 import org.apache.cassandra.db.*;
-import org.apache.cassandra.db.filter.ClusteringIndexSliceFilter;
-import org.apache.cassandra.db.filter.ColumnFilter;
-import org.apache.cassandra.db.filter.DataLimits;
-import org.apache.cassandra.db.filter.RowFilter;
+import org.apache.cassandra.db.filter.*;
 import org.apache.cassandra.db.partitions.FilteredPartition;
 import org.apache.cassandra.db.partitions.Partition;
 import org.apache.cassandra.db.partitions.PartitionUpdate;
@@ -50,10 +47,13 @@ public class CQL3CasRequest implements CASRequest
     private final boolean updatesStaticRow;
     private boolean hasExists; // whether we have an exist or if not exist condition
 
+    // Conditions on the static row. We keep it separate from 'conditions' as most things related to the static row are
+    // special cases anyway.
+    private RowCondition staticConditions;
     // We index RowCondition by the clustering of the row they applied to for 2 reasons:
-    //   1) this allows to keep things sorted to build the ColumnSlice array below
+    //   1) this allows to keep things sorted to build the read command below
     //   2) this allows to detect when contradictory conditions are set (not exists with some other conditions on the same row)
-    private final SortedMap<Clustering, RowCondition> conditions;
+    private final TreeMap<Clustering, RowCondition> conditions;
 
     private final List<RowUpdate> updates = new ArrayList<>();
 
@@ -80,34 +80,37 @@ public class CQL3CasRequest implements CASRequest
 
     public void addNotExist(Clustering clustering) throws InvalidRequestException
     {
-        RowCondition previous = conditions.put(clustering, new NotExistCondition(clustering));
-        if (previous != null && !(previous instanceof NotExistCondition))
-        {
-            // these should be prevented by the parser, but it doesn't hurt to check
-            if (previous instanceof ExistCondition)
-                throw new InvalidRequestException("Cannot mix IF EXISTS and IF NOT EXISTS conditions for the same row");
-            else
-                throw new InvalidRequestException("Cannot mix IF conditions and IF NOT EXISTS for the same row");
-        }
-        hasExists = true;
+        addExistsCondition(clustering, new NotExistCondition(clustering), true);
     }
 
     public void addExist(Clustering clustering) throws InvalidRequestException
     {
-        RowCondition previous = conditions.put(clustering, new ExistCondition(clustering));
-        // this should be prevented by the parser, but it doesn't hurt to check
-        if (previous instanceof NotExistCondition)
-            throw new InvalidRequestException("Cannot mix IF EXISTS and IF NOT EXISTS conditions for the same row");
+        addExistsCondition(clustering, new ExistCondition(clustering), false);
+    }
+
+    private void addExistsCondition(Clustering clustering, RowCondition condition, boolean isNotExist)
+    {
+        assert condition instanceof ExistCondition || condition instanceof NotExistCondition;
+        RowCondition previous = getConditionsForRow(clustering);
+        if (previous != null && !(previous.getClass().equals(condition.getClass())))
+        {
+            // these should be prevented by the parser, but it doesn't hurt to check
+            throw (previous instanceof NotExistCondition || previous instanceof ExistCondition)
+                ? new InvalidRequestException("Cannot mix IF EXISTS and IF NOT EXISTS conditions for the same row")
+                : new InvalidRequestException("Cannot mix IF conditions and IF " + (isNotExist ? "NOT " : "") + "EXISTS for the same row");
+        }
+
+        setConditionsForRow(clustering, condition);
         hasExists = true;
     }
 
     public void addConditions(Clustering clustering, Collection<ColumnCondition> conds, QueryOptions options) throws InvalidRequestException
     {
-        RowCondition condition = conditions.get(clustering);
+        RowCondition condition = getConditionsForRow(clustering);
         if (condition == null)
         {
             condition = new ColumnsConditions(clustering);
-            conditions.put(clustering, condition);
+            setConditionsForRow(clustering, condition);
         }
         else if (!(condition instanceof ColumnsConditions))
         {
@@ -116,6 +119,25 @@ public class CQL3CasRequest implements CASRequest
         ((ColumnsConditions)condition).addConditions(conds, options);
     }
 
+    private RowCondition getConditionsForRow(Clustering clustering)
+    {
+        return clustering == Clustering.STATIC_CLUSTERING ? staticConditions : conditions.get(clustering);
+    }
+
+    private void setConditionsForRow(Clustering clustering, RowCondition condition)
+    {
+        if (clustering == Clustering.STATIC_CLUSTERING)
+        {
+            assert staticConditions == null;
+            staticConditions = condition;
+        }
+        else
+        {
+            RowCondition previous = conditions.put(clustering, condition);
+            assert previous == null;
+        }
+    }
+
     private PartitionColumns columnsToRead()
     {
         // If all our conditions are columns conditions (IF x = ?), then it's enough to query
@@ -137,27 +159,28 @@ public class CQL3CasRequest implements CASRequest
 
     public SinglePartitionReadCommand readCommand(int nowInSec)
     {
-        assert !conditions.isEmpty();
-        Slices.Builder builder = new Slices.Builder(cfm.comparator, conditions.size());
-        // We always read CQL rows entirely as on CAS failure we want to be able to distinguish between "row exists
-        // but all values for which there were conditions are null" and "row doesn't exists", and we can't rely on the
-        // row marker for that (see #6623)
-        for (Clustering clustering : conditions.keySet())
-        {
-            if (clustering != Clustering.STATIC_CLUSTERING)
-                builder.add(Slice.make(clustering));
-            // In order to make distinction between non-existing partition and partition without statics on static condition,
-            // we have to read at least one row (see #12060).
-            else if (conditions.size() == 1)
-                builder.add(Slice.ALL);
-        }
-
-        ClusteringIndexSliceFilter filter = new ClusteringIndexSliceFilter(builder.build(), false);
-        return SinglePartitionReadCommand.create(false, cfm, nowInSec, ColumnFilter.selection(columnsToRead()), RowFilter.NONE, DataLimits.cqlLimits(conditions.size()), key, filter);
+        assert staticConditions != null || !conditions.isEmpty();
+
+        // With only a static condition, we still want to make the distinction between a non-existing partition and one
+        // that exists (has some live data) but has not static content. So we query the first live row of the partition.
+        if (conditions.isEmpty())
+            return SinglePartitionReadCommand.create(cfm,
+                                                     nowInSec,
+                                                     ColumnFilter.selection(columnsToRead()),
+                                                     RowFilter.NONE,
+                                                     DataLimits.cqlLimits(1),
+                                                     key,
+                                                     new ClusteringIndexSliceFilter(Slices.ALL, false));
+
+        ClusteringIndexNamesFilter filter = new ClusteringIndexNamesFilter(conditions.navigableKeySet(), false);
+        return SinglePartitionReadCommand.create(cfm, nowInSec, key, ColumnFilter.selection(columnsToRead()), filter);
     }
 
     public boolean appliesTo(FilteredPartition current) throws InvalidRequestException
     {
+        if (staticConditions != null && !staticConditions.appliesTo(current))
+            return false;
+
         for (RowCondition condition : conditions.values())
         {
             if (!condition.appliesTo(current))