Merge branch 'cassandra-2.2' into cassandra-3.0

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

Branch: refs/heads/cassandra-3.7
Commit: a3d055662fe80115c0fbca71f09312910ae55498
Parents: 716f02e 63efa07
Author: Marcus Eriksson <marc...@apache.org>
Authored: Thu May 26 09:20:47 2016 +0200
Committer: Marcus Eriksson <marc...@apache.org>
Committed: Thu May 26 09:20:47 2016 +0200

----------------------------------------------------------------------
 .../compaction/AbstractCompactionStrategy.java  |   2 +-
 .../db/compaction/CompactionController.java     |  22 +++-
 .../cassandra/db/compaction/NeverPurgeTest.java | 132 +++++++++++++++++++
 3 files changed, 152 insertions(+), 4 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cassandra/blob/a3d05566/src/java/org/apache/cassandra/db/compaction/AbstractCompactionStrategy.java
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/cassandra/blob/a3d05566/src/java/org/apache/cassandra/db/compaction/CompactionController.java
----------------------------------------------------------------------
diff --cc src/java/org/apache/cassandra/db/compaction/CompactionController.java
index 5cb60c5,699bc55..a5b8308
--- a/src/java/org/apache/cassandra/db/compaction/CompactionController.java
+++ b/src/java/org/apache/cassandra/db/compaction/CompactionController.java
@@@ -44,11 -41,14 +44,15 @@@ import static org.apache.cassandra.db.l
  public class CompactionController implements AutoCloseable
  {
      private static final Logger logger = 
LoggerFactory.getLogger(CompactionController.class);
+     static final boolean NEVER_PURGE_TOMBSTONES = 
Boolean.getBoolean("cassandra.never_purge_tombstones");
  
      public final ColumnFamilyStore cfs;
 +    private final boolean compactingRepaired;
+     // note that overlapIterator and overlappingSSTables will be null if 
NEVER_PURGE_TOMBSTONES is set - this is a
+     // good thing so that noone starts using them and thinks that if 
overlappingSSTables is empty, there
+     // is no overlap.
      private Refs<SSTableReader> overlappingSSTables;
 -    private OverlapIterator<RowPosition, SSTableReader> overlapIterator;
 +    private OverlapIterator<PartitionPosition, SSTableReader> overlapIterator;
      private final Iterable<SSTableReader> compacting;
  
      public final int gcBefore;
@@@ -64,12 -64,19 +68,20 @@@
          this.cfs = cfs;
          this.gcBefore = gcBefore;
          this.compacting = compacting;
 +        compactingRepaired = compacting != null && 
compacting.stream().allMatch(SSTableReader::isRepaired);
          refreshOverlaps();
+         if (NEVER_PURGE_TOMBSTONES)
+             logger.warn("You are running with 
-Dcassandra.never_purge_tombstones=true, this is dangerous!");
      }
  
 -    void maybeRefreshOverlaps()
 +    public void maybeRefreshOverlaps()
      {
+         if (NEVER_PURGE_TOMBSTONES)
+         {
+             logger.debug("not refreshing overlaps - running with 
-Dcassandra.never_purge_tombstones=true");
+             return;
+         }
+ 
          for (SSTableReader reader : overlappingSSTables)
          {
              if (reader.isMarkedCompacted())
@@@ -117,12 -127,9 +132,12 @@@
      {
          logger.trace("Checking droppable sstables in {}", cfStore);
  
-         if (compacting == null)
+         if (compacting == null || NEVER_PURGE_TOMBSTONES)
              return Collections.<SSTableReader>emptySet();
  
 +        if 
(cfStore.getCompactionStrategyManager().onlyPurgeRepairedTombstones() && 
!Iterables.all(compacting, SSTableReader::isRepaired))
 +            return Collections.emptySet();
 +
          List<SSTableReader> candidates = new ArrayList<>();
  
          long minTimestamp = Long.MAX_VALUE;
@@@ -187,7 -194,7 +202,7 @@@
       */
      public long maxPurgeableTimestamp(DecoratedKey key)
      {
-         if (!compactingRepaired())
 -        if (NEVER_PURGE_TOMBSTONES)
++        if (!compactingRepaired() || NEVER_PURGE_TOMBSTONES)
              return Long.MIN_VALUE;
  
          long min = Long.MAX_VALUE;
@@@ -213,12 -220,8 +228,13 @@@
  
      public void close()
      {
-         overlappingSSTables.release();
+         if (overlappingSSTables != null)
+             overlappingSSTables.release();
      }
  
 +    public boolean compactingRepaired()
 +    {
 +        return 
!cfs.getCompactionStrategyManager().onlyPurgeRepairedTombstones() || 
compactingRepaired;
 +    }
 +
  }

http://git-wip-us.apache.org/repos/asf/cassandra/blob/a3d05566/test/unit/org/apache/cassandra/db/compaction/NeverPurgeTest.java
----------------------------------------------------------------------
diff --cc test/unit/org/apache/cassandra/db/compaction/NeverPurgeTest.java
index 0000000,5211065..96e6ad6
mode 000000,100644..100644
--- a/test/unit/org/apache/cassandra/db/compaction/NeverPurgeTest.java
+++ b/test/unit/org/apache/cassandra/db/compaction/NeverPurgeTest.java
@@@ -1,0 -1,125 +1,132 @@@
+ /*
+  * Licensed to the Apache Software Foundation (ASF) under one
+  * or more contributor license agreements.  See the NOTICE file
+  * distributed with this work for additional information
+  * regarding copyright ownership.  The ASF licenses this file
+  * to you under the Apache License, Version 2.0 (the
+  * "License"); you may not use this file except in compliance
+  * with the License.  You may obtain a copy of the License at
+  *
+  *     http://www.apache.org/licenses/LICENSE-2.0
+  *
+  * Unless required by applicable law or agreed to in writing, software
+  * distributed under the License is distributed on an "AS IS" BASIS,
+  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  * See the License for the specific language governing permissions and
+  * limitations under the License.
+  */
+ 
+ package org.apache.cassandra.db.compaction;
+ 
+ import java.util.Collection;
+ 
+ import org.junit.Test;
+ 
+ import org.apache.cassandra.cql3.CQLTester;
+ import org.apache.cassandra.db.ColumnFamilyStore;
 -import org.apache.cassandra.db.DeletedCell;
+ import org.apache.cassandra.db.Keyspace;
 -import org.apache.cassandra.db.OnDiskAtom;
 -import org.apache.cassandra.db.RangeTombstone;
 -import org.apache.cassandra.db.columniterator.OnDiskAtomIterator;
++import org.apache.cassandra.db.rows.Cell;
++import org.apache.cassandra.db.rows.Row;
++import org.apache.cassandra.db.rows.Unfiltered;
++import org.apache.cassandra.db.rows.UnfilteredRowIterator;
+ import org.apache.cassandra.io.sstable.ISSTableScanner;
+ import org.apache.cassandra.io.sstable.format.SSTableReader;
+ 
+ import static org.junit.Assert.assertEquals;
+ import static org.junit.Assert.assertTrue;
+ 
+ public class NeverPurgeTest extends CQLTester
+ {
+     static
+     {
+         System.setProperty("cassandra.never_purge_tombstones", "true");
+     }
+ 
+     @Test
+     public void neverPurgeCellTombstoneTest() throws Throwable
+     {
+         testHelper("UPDATE %s SET c = null WHERE a=1 AND b=2");
+     }
+ 
+     @Test
 -    public void neverPurgeRangeTombstoneTest() throws Throwable
++    public void neverPurgeRowTombstoneTest() throws Throwable
+     {
+         testHelper("DELETE FROM %s WHERE a=1 AND b=2");
+     }
+ 
+     @Test
+     public void neverPurgePartitionTombstoneTest() throws Throwable
+     {
+         testHelper("DELETE FROM %s WHERE a=1");
+     }
+ 
+     @Test
+     public void minorNeverPurgeTombstonesTest() throws Throwable
+     {
+         createTable("CREATE TABLE %s (a int, b int, c text, PRIMARY KEY (a, 
b)) WITH gc_grace_seconds = 0");
+         ColumnFamilyStore cfs = 
Keyspace.open(keyspace()).getColumnFamilyStore(currentTable());
+         cfs.disableAutoCompaction();
+         for (int i = 0; i < 4; i++)
+         {
+             for (int j = 0; j < 1000; j++)
+             {
+                 execute("INSERT INTO %s (a, b, c) VALUES (" + j + ", 2, 
'3')");
+             }
+             cfs.forceBlockingFlush();
+         }
+ 
+         execute("UPDATE %s SET c = null WHERE a=1 AND b=2");
+         execute("DELETE FROM %s WHERE a=2 AND b=2");
+         execute("DELETE FROM %s WHERE a=3");
+         cfs.forceBlockingFlush();
+         cfs.enableAutoCompaction();
+         while (cfs.getSSTables().size() > 1)
+             Thread.sleep(100);
+         verifyContainsTombstones(cfs.getSSTables(), 3);
+     }
+ 
+     private void testHelper(String deletionStatement) throws Throwable
+     {
+         createTable("CREATE TABLE %s (a int, b int, c text, PRIMARY KEY (a, 
b)) WITH gc_grace_seconds = 0");
+         ColumnFamilyStore cfs = 
Keyspace.open(keyspace()).getColumnFamilyStore(currentTable());
+         execute("INSERT INTO %s (a, b, c) VALUES (1, 2, '3')");
+         execute(deletionStatement);
+         Thread.sleep(1000);
+         cfs.forceBlockingFlush();
+         cfs.forceMajorCompaction();
+         verifyContainsTombstones(cfs.getSSTables(), 1);
+     }
+ 
+     private void verifyContainsTombstones(Collection<SSTableReader> sstables, 
int expectedTombstoneCount) throws Exception
+     {
+         assertTrue(sstables.size() == 1); // always run a major compaction 
before calling this
+         SSTableReader sstable = sstables.iterator().next();
+         int tombstoneCount = 0;
+         try (ISSTableScanner scanner = sstable.getScanner())
+         {
+             while (scanner.hasNext())
+             {
 -                try (OnDiskAtomIterator iter = scanner.next())
++                try (UnfilteredRowIterator iter = scanner.next())
+                 {
 -                    if 
(iter.getColumnFamily().deletionInfo().getTopLevelDeletion().localDeletionTime 
< Integer.MAX_VALUE)
++                    if (!iter.partitionLevelDeletion().isLive())
+                         tombstoneCount++;
+ 
+                     while (iter.hasNext())
+                     {
 -                        OnDiskAtom atom = iter.next();
 -                        if (atom instanceof DeletedCell || atom instanceof 
RangeTombstone)
 -                            tombstoneCount++;
++                        Unfiltered atom = iter.next();
++                        if (atom.isRow())
++                        {
++                            Row r = (Row)atom;
++                            if (!r.deletion().isLive())
++                                tombstoneCount++;
++                            for (Cell c : r.cells())
++                                if (c.isTombstone())
++                                    tombstoneCount++;
++                        }
+                     }
+                 }
+             }
+         }
+         assertEquals(tombstoneCount, expectedTombstoneCount);
+     }
+ }

Reply via email to