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