cassandra-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From slebre...@apache.org
Subject git commit: Lost row marker after TTL expires
Date Mon, 22 Jul 2013 12:02:53 GMT
Updated Branches:
  refs/heads/cassandra-1.2 86a077a19 -> b0f7bab7d


Lost row marker after TTL expires

patch by slebresne; reviewed by iamaleksy for CASSANDRA-5762


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

Branch: refs/heads/cassandra-1.2
Commit: b0f7bab7da7511b8b26332a3b436967ae75cecca
Parents: 86a077a
Author: Sylvain Lebresne <sylvain@datastax.com>
Authored: Mon Jul 22 11:30:25 2013 +0200
Committer: Sylvain Lebresne <sylvain@datastax.com>
Committed: Mon Jul 22 11:30:25 2013 +0200

----------------------------------------------------------------------
 CHANGES.txt                                     |  2 +
 .../cql3/statements/SelectStatement.java        | 98 ++++++++++++++------
 2 files changed, 71 insertions(+), 29 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cassandra/blob/b0f7bab7/CHANGES.txt
----------------------------------------------------------------------
diff --git a/CHANGES.txt b/CHANGES.txt
index 23f19d4..5d74d67 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -23,6 +23,8 @@
  * cqlsh: handle disabled compression in DESCRIBE output (CASSANDRA-5766)
  * Ensure all UP events are notified on the native protocol (CASSANDRA-5769)
  * Fix formatting of sstable2json with multiple -k arguments (CASSANDRA-5781)
+ * Don't rely on row marker for queries in general to hide lost markers
+   after TTL expires (CASSANDRA-5762)
 
 
 1.2.6

http://git-wip-us.apache.org/repos/asf/cassandra/blob/b0f7bab7/src/java/org/apache/cassandra/cql3/statements/SelectStatement.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/statements/SelectStatement.java b/src/java/org/apache/cassandra/cql3/statements/SelectStatement.java
index 6224af6..2a2b33a 100644
--- a/src/java/org/apache/cassandra/cql3/statements/SelectStatement.java
+++ b/src/java/org/apache/cassandra/cql3/statements/SelectStatement.java
@@ -327,13 +327,40 @@ public class SelectStatement implements CQLStatement
             // But we must preserve backward compatibility too (for mixed version cluster
that is).
             int multiplier = cfDef.isCompact ? 1 : (cfDef.metadata.size() + 1);
             int toGroup = cfDef.isCompact ? -1 : cfDef.columns.size();
-            ColumnSlice slice = new ColumnSlice(getRequestedBound(Bound.START, variables),
-                                                getRequestedBound(Bound.END, variables));
+            List<ByteBuffer> startBounds = getRequestedBound(Bound.START, variables);
+            List<ByteBuffer> endBounds = getRequestedBound(Bound.END, variables);
+            assert startBounds.size() == endBounds.size();
 
-            if (slice.isAlwaysEmpty(cfDef.cfm.comparator, isReversed))
-                return null;
+            // The case where startBounds == 1 is common enough that it's worth optimizing
+            ColumnSlice[] slices;
+            if (startBounds.size() == 1)
+            {
+                ColumnSlice slice = new ColumnSlice(startBounds.get(0), endBounds.get(0));
+                if (slice.isAlwaysEmpty(cfDef.cfm.comparator, isReversed))
+                    return null;
+                slices = new ColumnSlice[]{slice};
+            }
+            else
+            {
+                // The IN query might not have listed the values in comparator order, so
we need to re-sort
+                // the bounds lists to make sure the slices works correctly
+                Comparator<ByteBuffer> cmp = isReversed ? cfDef.cfm.comparator.reverseComparator
: cfDef.cfm.comparator;
+                Collections.sort(startBounds, cmp);
+                Collections.sort(endBounds, cmp);
+
+                List<ColumnSlice> l = new ArrayList<ColumnSlice>(startBounds.size());
+                for (int i = 0; i < startBounds.size(); i++)
+                {
+                    ColumnSlice slice = new ColumnSlice(startBounds.get(i), endBounds.get(i));
+                    if (!slice.isAlwaysEmpty(cfDef.cfm.comparator, isReversed))
+                        l.add(slice);
+                }
+                if (l.isEmpty())
+                    return null;
+                slices = l.toArray(new ColumnSlice[l.size()]);
+            }
 
-            SliceQueryFilter filter = new SliceQueryFilter(new ColumnSlice[]{slice},
+            SliceQueryFilter filter = new SliceQueryFilter(slices,
                                                            isReversed,
                                                            getLimit(),
                                                            toGroup,
@@ -390,7 +417,8 @@ public class SelectStatement implements CQLStatement
 
     private ByteBuffer getKeyBound(Bound b, List<ByteBuffer> variables) throws InvalidRequestException
     {
-        return buildBound(b, cfDef.keys.values(), keyRestrictions, false, cfDef.getKeyNameBuilder(),
variables);
+        // We deal with IN queries for keys in other places, so we know buildBound will return
only one result
+        return buildBound(b, cfDef.keys.values(), keyRestrictions, false, cfDef.getKeyNameBuilder(),
variables).get(0);
     }
 
     private Token getTokenBound(Bound b, List<ByteBuffer> variables, IPartitioner<?>
p) throws InvalidRequestException
@@ -426,16 +454,13 @@ public class SelectStatement implements CQLStatement
 
     private boolean isColumnRange()
     {
-        // Static CF never entails a column slice
-        if (!cfDef.isCompact && !cfDef.isComposite)
-            return false;
-
-        // However, collections always entails one
-        if (selectACollection())
-            return true;
+        // Due to CASSANDRA-5762, we always do a slice for CQL3 tables (not compact, composite).
+        // Static CF (non compact but non composite) never entails a column slice however
+        if (!cfDef.isCompact)
+            return cfDef.isComposite;
 
-        // Otherwise, it is a range query if it has at least one the column alias
-        // for which no relation is defined or is not EQ.
+        // Otherwise (i.e. for compact table where we don't have a row marker anyway and
thus don't care about CASSANDRA-5762),
+        // it is a range query if it has at least one the column alias for which no relation
is defined or is not EQ.
         for (Restriction r : columnRestrictions)
         {
             if (r == null || !r.isEquality())
@@ -544,12 +569,12 @@ public class SelectStatement implements CQLStatement
         return false;
     }
 
-    private static ByteBuffer buildBound(Bound bound,
-                                         Collection<CFDefinition.Name> names,
-                                         Restriction[] restrictions,
-                                         boolean isReversed,
-                                         ColumnNameBuilder builder,
-                                         List<ByteBuffer> variables) throws InvalidRequestException
+    private static List<ByteBuffer> buildBound(Bound bound,
+                                               Collection<CFDefinition.Name> names,
+                                               Restriction[] restrictions,
+                                               boolean isReversed,
+                                               ColumnNameBuilder builder,
+                                               List<ByteBuffer> variables) throws InvalidRequestException
     {
         // The end-of-component of composite doesn't depend on whether the
         // component type is reversed or not (i.e. the ReversedType is applied
@@ -568,15 +593,30 @@ public class SelectStatement implements CQLStatement
                 // There wasn't any non EQ relation on that key, we select all records having
the preceding component as prefix.
                 // For composites, if there was preceding component and we're computing the
end, we must change the last component
                 // End-Of-Component, otherwise we would be selecting only one record.
-                if (builder.componentCount() > 0 && eocBound == Bound.END)
-                    return builder.buildAsEndOfRange();
-                else
-                    return builder.build();
+                return Collections.singletonList(builder.componentCount() > 0 &&
eocBound == Bound.END
+                                                 ? builder.buildAsEndOfRange()
+                                                 : builder.build());
             }
 
             if (r.isEquality())
             {
-                assert r.eqValues.size() == 1;
+                if (r.eqValues.size() > 1)
+                {
+                    // IN query, we only support it on the clustering column
+                    assert name.position == names.size() - 1;
+                    List<ByteBuffer> l = new ArrayList<ByteBuffer>(r.eqValues.size());
+                    for (Term t : r.eqValues)
+                    {
+                        ByteBuffer val = t.bindAndGet(variables);
+                        if (val == null)
+                            throw new InvalidRequestException(String.format("Invalid null
clustering key part %s", name));
+                        ColumnNameBuilder copy = builder.copy().add(val);
+                        // See below for why this
+                        l.add((bound == Bound.END && copy.remainingCount() > 0)
? copy.buildAsEndOfRange() : copy.build());
+                    }
+                    return l;
+                }
+
                 ByteBuffer val = r.eqValues.get(0).bindAndGet(variables);
                 if (val == null)
                     throw new InvalidRequestException(String.format("Invalid null clustering
key part %s", name));
@@ -589,7 +629,7 @@ public class SelectStatement implements CQLStatement
                 ByteBuffer val = t.bindAndGet(variables);
                 if (val == null)
                     throw new InvalidRequestException(String.format("Invalid null clustering
key part %s", name));
-                return builder.add(val, r.getRelation(eocBound, b)).build();
+                return Collections.singletonList(builder.add(val, r.getRelation(eocBound,
b)).build());
             }
         }
         // Means no relation at all or everything was an equal
@@ -598,10 +638,10 @@ public class SelectStatement implements CQLStatement
         // with 2ndary index is done, and with the the partition provided with an EQ, we'll
end up here, and in that
         // case using the eoc would be bad, since for the random partitioner we have no guarantee
that
         // builder.buildAsEndOfRange() will sort after builder.build() (see #5240).
-        return (bound == Bound.END && builder.remainingCount() > 0) ? builder.buildAsEndOfRange()
: builder.build();
+        return Collections.singletonList((bound == Bound.END && builder.remainingCount()
> 0) ? builder.buildAsEndOfRange() : builder.build());
     }
 
-    private ByteBuffer getRequestedBound(Bound b, List<ByteBuffer> variables) throws
InvalidRequestException
+    private List<ByteBuffer> getRequestedBound(Bound b, List<ByteBuffer> variables)
throws InvalidRequestException
     {
         assert isColumnRange();
         return buildBound(b, cfDef.columns.values(), columnRestrictions, isReversed, cfDef.getColumnNameBuilder(),
variables);


Mime
View raw message