Author: jbellis
Date: Mon Aug 24 21:48:20 2009
New Revision: 807395

URL: http://svn.apache.org/viewvc?rev=807395&view=rev
Log:
need to include column container's deletion status when determining whether to 
include a column in the live count.
patch by jbellis; reviewed by Jun Rao for CASSANDRA-386

Modified:
    incubator/cassandra/trunk/src/java/org/apache/cassandra/db/Column.java
    incubator/cassandra/trunk/src/java/org/apache/cassandra/db/IColumn.java
    
incubator/cassandra/trunk/src/java/org/apache/cassandra/db/IColumnContainer.java
    incubator/cassandra/trunk/src/java/org/apache/cassandra/db/SuperColumn.java
    
incubator/cassandra/trunk/src/java/org/apache/cassandra/db/filter/SliceQueryFilter.java
    incubator/cassandra/trunk/test/system/test_server.py

Modified: incubator/cassandra/trunk/src/java/org/apache/cassandra/db/Column.java
URL: 
http://svn.apache.org/viewvc/incubator/cassandra/trunk/src/java/org/apache/cassandra/db/Column.java?rev=807395&r1=807394&r2=807395&view=diff
==============================================================================
--- incubator/cassandra/trunk/src/java/org/apache/cassandra/db/Column.java 
(original)
+++ incubator/cassandra/trunk/src/java/org/apache/cassandra/db/Column.java Mon 
Aug 24 21:48:20 2009
@@ -125,6 +125,11 @@
         return timestamp;
     }
 
+    public long mostRecentChangeAt()
+    {
+        return timestamp;
+    }
+
     public int size()
     {
         /*

Modified: 
incubator/cassandra/trunk/src/java/org/apache/cassandra/db/IColumn.java
URL: 
http://svn.apache.org/viewvc/incubator/cassandra/trunk/src/java/org/apache/cassandra/db/IColumn.java?rev=807395&r1=807394&r2=807395&view=diff
==============================================================================
--- incubator/cassandra/trunk/src/java/org/apache/cassandra/db/IColumn.java 
(original)
+++ incubator/cassandra/trunk/src/java/org/apache/cassandra/db/IColumn.java Mon 
Aug 24 21:48:20 2009
@@ -27,6 +27,7 @@
     public static short UtfPrefix_ = 2;
     public boolean isMarkedForDelete();
     public long getMarkedForDeleteAt();
+    public long mostRecentChangeAt();
     public byte[] name();
     public int size();
     public int serializedSize();

Modified: 
incubator/cassandra/trunk/src/java/org/apache/cassandra/db/IColumnContainer.java
URL: 
http://svn.apache.org/viewvc/incubator/cassandra/trunk/src/java/org/apache/cassandra/db/IColumnContainer.java?rev=807395&r1=807394&r2=807395&view=diff
==============================================================================
--- 
incubator/cassandra/trunk/src/java/org/apache/cassandra/db/IColumnContainer.java
 (original)
+++ 
incubator/cassandra/trunk/src/java/org/apache/cassandra/db/IColumnContainer.java
 Mon Aug 24 21:48:20 2009
@@ -27,5 +27,8 @@
 {
     public void addColumn(IColumn column);
 
+    public boolean isMarkedForDelete();
+    public long getMarkedForDeleteAt();
+
     public AbstractType getComparator();
 }

Modified: 
incubator/cassandra/trunk/src/java/org/apache/cassandra/db/SuperColumn.java
URL: 
http://svn.apache.org/viewvc/incubator/cassandra/trunk/src/java/org/apache/cassandra/db/SuperColumn.java?rev=807395&r1=807394&r2=807395&view=diff
==============================================================================
--- incubator/cassandra/trunk/src/java/org/apache/cassandra/db/SuperColumn.java 
(original)
+++ incubator/cassandra/trunk/src/java/org/apache/cassandra/db/SuperColumn.java 
Mon Aug 24 21:48:20 2009
@@ -139,13 +139,25 @@
     public long timestamp(byte[] columnName)
     {
        IColumn column = columns_.get(columnName);
-       if ( column instanceof SuperColumn )
-               throw new UnsupportedOperationException("A super column cannot 
hold other super columns.");
+       assert column instanceof Column;
        if ( column != null )
                return column.timestamp();
        throw new IllegalArgumentException("Timestamp was requested for a 
column that does not exist.");
     }
 
+    public long mostRecentChangeAt()
+    {
+        long max = Long.MIN_VALUE;
+        for (IColumn column : columns_.values())
+        {
+            if (column.mostRecentChangeAt() > max)
+            {
+                max = column.mostRecentChangeAt();
+            }
+        }
+        return max;
+    }
+
     public byte[] value()
     {
        throw new UnsupportedOperationException("This operation is not 
supported for Super Columns.");

Modified: 
incubator/cassandra/trunk/src/java/org/apache/cassandra/db/filter/SliceQueryFilter.java
URL: 
http://svn.apache.org/viewvc/incubator/cassandra/trunk/src/java/org/apache/cassandra/db/filter/SliceQueryFilter.java?rev=807395&r1=807394&r2=807395&view=diff
==============================================================================
--- 
incubator/cassandra/trunk/src/java/org/apache/cassandra/db/filter/SliceQueryFilter.java
 (original)
+++ 
incubator/cassandra/trunk/src/java/org/apache/cassandra/db/filter/SliceQueryFilter.java
 Mon Aug 24 21:48:20 2009
@@ -27,6 +27,7 @@
 import java.util.ArrayList;
 import java.util.List;
 
+import org.apache.log4j.Logger;
 import org.apache.commons.collections.comparators.ReverseComparator;
 import org.apache.commons.collections.iterators.ReverseListIterator;
 import org.apache.commons.collections.IteratorUtils;
@@ -38,6 +39,8 @@
 
 public class SliceQueryFilter extends QueryFilter
 {
+    private static Logger logger = Logger.getLogger(SliceQueryFilter.class);
+
     public final byte[] start, finish;
     public final boolean reversed;
     public final int count;
@@ -104,19 +107,35 @@
 
         while (reducedColumns.hasNext())
         {
-            IColumn column = reducedColumns.next();
             if (liveColumns >= count)
                 break;
+
+            IColumn column = reducedColumns.next();
+            if (logger.isDebugEnabled())
+                logger.debug("collecting " + column.getString(comparator));
+
             if (finish.length > 0
                 && ((!reversed && comparator.compare(column.name(), finish) > 
0))
                     || (reversed && comparator.compare(column.name(), finish) 
< 0))
                 break;
 
-            if (!column.isMarkedForDelete())
+            // only count live columns towards the `count` criteria
+            if (!column.isMarkedForDelete()
+                && (!container.isMarkedForDelete()
+                    || column.mostRecentChangeAt() > 
container.getMarkedForDeleteAt()))
+            {
                 liveColumns++;
+            }
 
-            if (!column.isMarkedForDelete() || column.getLocalDeletionTime() > 
gcBefore)
+            // but we need to add all non-gc-able columns to the result for 
read repair:
+            // the column itself must be not gc-able, (1)
+            // and if its container is deleted, the column must be changed 
more recently than the container tombstone (2)
+            // (since otherwise, the only thing repair cares about is the 
container tombstone)
+            if ((!column.isMarkedForDelete() || column.getLocalDeletionTime() 
> gcBefore) // (1)
+                && (!container.isMarkedForDelete() || 
column.mostRecentChangeAt() > container.getMarkedForDeleteAt())) // (2)
+            {
                 container.addColumn(column);
+            }
         }
     }
 }

Modified: incubator/cassandra/trunk/test/system/test_server.py
URL: 
http://svn.apache.org/viewvc/incubator/cassandra/trunk/test/system/test_server.py?rev=807395&r1=807394&r2=807395&view=diff
==============================================================================
--- incubator/cassandra/trunk/test/system/test_server.py (original)
+++ incubator/cassandra/trunk/test/system/test_server.py Mon Aug 24 21:48:20 
2009
@@ -235,6 +235,23 @@
                  for result in client.get_slice('Keyspace2', 'key1', 
column_parent, p, ConsistencyLevel.ONE)]
         assert slice == [Column(L[2].bytes, 'value2', 2)], slice
         
+    def test_long_remove(self):
+        column_parent = ColumnParent('StandardLong1')
+        sp = SlicePredicate(slice_range=SliceRange('', '', False, 1))
+
+        for i in xrange(10):
+            path = ColumnPath('StandardLong1', column=_i64(i))
+
+            client.insert('Keyspace1', 'key1', path, 'value1', 10 * i, 
ConsistencyLevel.ONE)
+            client.remove('Keyspace1', 'key1', ColumnPath('StandardLong1'), 10 
* i + 1, ConsistencyLevel.ONE)
+            slice = client.get_slice('Keyspace1', 'key1', column_parent, sp, 
ConsistencyLevel.ONE)
+            assert slice == [], slice
+            # resurrect
+            client.insert('Keyspace1', 'key1', path, 'value2', 10 * i + 2, 
ConsistencyLevel.ONE)
+            slice = [result.column
+                     for result in client.get_slice('Keyspace1', 'key1', 
column_parent, sp, ConsistencyLevel.ONE)]
+            assert slice == [Column(_i64(i), 'value2', 10 * i + 2)], (slice, i)
+        
     def test_batch_insert(self):
         _insert_batch(False)
         time.sleep(0.1)


Reply via email to