Purge tombstones created by expired cells

Patch by Blake Eggleston; reviewed by Sylvain Lebresne for CASSANDRA-13643


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

Branch: refs/heads/cassandra-3.11
Commit: a033f51651e1a990adca795f92d683999c474151
Parents: 88d2ac4
Author: Blake Eggleston <bdeggles...@gmail.com>
Authored: Tue Jun 27 08:41:17 2017 -0700
Committer: Blake Eggleston <bdeggles...@gmail.com>
Committed: Fri Jul 14 10:02:07 2017 -0700

----------------------------------------------------------------------
 CHANGES.txt                                     |  1 +
 .../apache/cassandra/db/rows/BufferCell.java    |  2 +-
 test/unit/org/apache/cassandra/db/CellTest.java | 78 +++++++++++++++++++-
 3 files changed, 79 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cassandra/blob/a033f516/CHANGES.txt
----------------------------------------------------------------------
diff --git a/CHANGES.txt b/CHANGES.txt
index 4a823c9..9962f4b 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -1,4 +1,5 @@
 3.0.15
+ * Purge tombstones created by expired cells (CASSANDRA-13643)
  * Make concat work with iterators that have different subsets of columns 
(CASSANDRA-13482)
  * Set test.runners based on cores and memory size (CASSANDRA-13078)
  * Allow different NUMACTL_ARGS to be passed in (CASSANDRA-13557)

http://git-wip-us.apache.org/repos/asf/cassandra/blob/a033f516/src/java/org/apache/cassandra/db/rows/BufferCell.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/db/rows/BufferCell.java 
b/src/java/org/apache/cassandra/db/rows/BufferCell.java
index db0ded5..e4ad7e6 100644
--- a/src/java/org/apache/cassandra/db/rows/BufferCell.java
+++ b/src/java/org/apache/cassandra/db/rows/BufferCell.java
@@ -176,7 +176,7 @@ public class BufferCell extends AbstractCell
                 // Note that as long as the expiring column and the tombstone 
put together live longer than GC grace seconds,
                 // we'll fulfil our responsibility to repair. See discussion at
                 // 
http://cassandra-user-incubator-apache-org.3065146.n2.nabble.com/repair-compaction-and-tombstone-rows-td7583481.html
-                return BufferCell.tombstone(column, timestamp, 
localDeletionTime - ttl, path);
+                return BufferCell.tombstone(column, timestamp, 
localDeletionTime - ttl, path).purge(purger, nowInSec);
             }
         }
         return this;

http://git-wip-us.apache.org/repos/asf/cassandra/blob/a033f516/test/unit/org/apache/cassandra/db/CellTest.java
----------------------------------------------------------------------
diff --git a/test/unit/org/apache/cassandra/db/CellTest.java 
b/test/unit/org/apache/cassandra/db/CellTest.java
index 9072f98..cd6000f 100644
--- a/test/unit/org/apache/cassandra/db/CellTest.java
+++ b/test/unit/org/apache/cassandra/db/CellTest.java
@@ -174,6 +174,77 @@ public class CellTest
         Assert.assertEquals(-1, testExpiring("val", "b", 2, 1, null, "a", 
null, 2));
     }
 
+    class SimplePurger implements DeletionPurger
+    {
+        private final int gcBefore;
+
+        public SimplePurger(int gcBefore)
+        {
+            this.gcBefore = gcBefore;
+        }
+
+        public boolean shouldPurge(long timestamp, int localDeletionTime)
+        {
+            return localDeletionTime < gcBefore;
+        }
+    }
+
+    /**
+     * tombstones shouldn't be purged if localDeletionTime is greater than 
gcBefore
+     */
+    @Test
+    public void testNonPurgableTombstone()
+    {
+        int now = 100;
+        Cell cell = deleted(cfm, "val", now, now);
+        Cell purged = cell.purge(new SimplePurger(now - 1), now + 1);
+        Assert.assertEquals(cell, purged);
+    }
+
+    @Test
+    public void testPurgeableTombstone()
+    {
+        int now = 100;
+        Cell cell = deleted(cfm, "val", now, now);
+        Cell purged = cell.purge(new SimplePurger(now + 1), now + 1);
+        Assert.assertNull(purged);
+    }
+
+    @Test
+    public void testLiveExpiringCell()
+    {
+        int now = 100;
+        Cell cell = expiring(cfm, "val", "a", now, now + 10);
+        Cell purged = cell.purge(new SimplePurger(now), now + 1);
+        Assert.assertEquals(cell, purged);
+    }
+
+    /**
+     * cells that have expired should be converted to tombstones with an local 
deletion time
+     * of the cell's local expiration time, minus it's ttl
+     */
+    @Test
+    public void testExpiredTombstoneConversion()
+    {
+        int now = 100;
+        Cell cell = expiring(cfm, "val", "a", now, 10, now + 10);
+        Cell purged = cell.purge(new SimplePurger(now), now + 11);
+        Assert.assertEquals(deleted(cfm, "val", now, now), purged);
+    }
+
+    /**
+     * if the tombstone created by an expiring cell has a local deletion time 
less than gcBefore,
+     * it should be purged
+     */
+    @Test
+    public void testPurgeableExpiringCell()
+    {
+        int now = 100;
+        Cell cell = expiring(cfm, "val", "a", now, 10, now + 10);
+        Cell purged = cell.purge(new SimplePurger(now + 1), now + 11);
+        Assert.assertNull(purged);
+    }
+
     private static ByteBuffer bb(int i)
     {
         return ByteBufferUtil.bytes(i);
@@ -230,8 +301,13 @@ public class CellTest
 
     private Cell expiring(CFMetaData cfm, String columnName, String value, 
long timestamp, int localExpirationTime)
     {
+        return expiring(cfm, columnName, value, timestamp, 1, 
localExpirationTime);
+    }
+
+    private Cell expiring(CFMetaData cfm, String columnName, String value, 
long timestamp, int ttl, int localExpirationTime)
+    {
         ColumnDefinition cdef = 
cfm.getColumnDefinition(ByteBufferUtil.bytes(columnName));
-        return new BufferCell(cdef, timestamp, 1, localExpirationTime, 
ByteBufferUtil.bytes(value), null);
+        return new BufferCell(cdef, timestamp, ttl, localExpirationTime, 
ByteBufferUtil.bytes(value), null);
     }
 
     private Cell deleted(CFMetaData cfm, String columnName, int 
localDeletionTime, long timestamp)


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscr...@cassandra.apache.org
For additional commands, e-mail: commits-h...@cassandra.apache.org

Reply via email to