Merge branch 'cassandra-3.0' into cassandra-3.11

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

Branch: refs/heads/cassandra-3.11
Commit: c34a0f5207d228a2b78f6295cd4ab3e0755e56c2
Parents: 4d3f5a3 d496dca
Author: Aleksey Yeshchenko <alek...@apple.com>
Authored: Tue Sep 25 17:41:10 2018 +0100
Committer: Aleksey Yeshchenko <alek...@apple.com>
Committed: Tue Sep 25 17:41:10 2018 +0100

----------------------------------------------------------------------
 CHANGES.txt                                     |   1 +
 .../db/rows/RangeTombstoneBoundaryMarker.java   |   4 +-
 .../db/partitions/PurgeFunctionTest.java        | 297 +++++++++++++++++++
 3 files changed, 300 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cassandra/blob/c34a0f52/CHANGES.txt
----------------------------------------------------------------------
diff --cc CHANGES.txt
index a4fa705,2c2f4f5..20cec87
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@@ -1,5 -1,5 +1,6 @@@
 -3.0.18
 +3.11.4
 +Merged from 3.0:
+  * Fix purging semi-expired RT boundaries in reversed iterators 
(CASSANDRA-14672)
   * DESC order reads can fail to return the last Unfiltered in the partition 
(CASSANDRA-14766)
   * Fix corrupted collection deletions for dropped columns in 3.0 <-> 2.{1,2} 
messages (CASSANDRA-14568)
   * Fix corrupted static collection deletions in 3.0 <-> 2.{1,2} messages 
(CASSANDRA-14568)

http://git-wip-us.apache.org/repos/asf/cassandra/blob/c34a0f52/src/java/org/apache/cassandra/db/rows/RangeTombstoneBoundaryMarker.java
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/cassandra/blob/c34a0f52/test/unit/org/apache/cassandra/db/partitions/PurgeFunctionTest.java
----------------------------------------------------------------------
diff --cc test/unit/org/apache/cassandra/db/partitions/PurgeFunctionTest.java
index 0000000,1dea7f3..7f85aea
mode 000000,100644..100644
--- a/test/unit/org/apache/cassandra/db/partitions/PurgeFunctionTest.java
+++ b/test/unit/org/apache/cassandra/db/partitions/PurgeFunctionTest.java
@@@ -1,0 -1,294 +1,297 @@@
+ /*
+  * 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.partitions;
+ 
+ import java.nio.ByteBuffer;
+ import java.util.Iterator;
+ import java.util.function.Predicate;
+ 
+ import com.google.common.collect.Iterators;
+ import org.junit.Before;
+ import org.junit.Test;
+ 
+ import org.apache.cassandra.config.CFMetaData;
++import org.apache.cassandra.config.DatabaseDescriptor;
+ import org.apache.cassandra.db.ClusteringPrefix.Kind;
+ import org.apache.cassandra.db.*;
+ import org.apache.cassandra.db.marshal.AbstractType;
+ import org.apache.cassandra.db.marshal.UTF8Type;
+ import org.apache.cassandra.db.rows.*;
+ import org.apache.cassandra.db.transform.Transformation;
+ import org.apache.cassandra.dht.Murmur3Partitioner;
+ import org.apache.cassandra.utils.FBUtilities;
+ 
+ import static org.junit.Assert.assertEquals;
+ import static org.junit.Assert.assertTrue;
+ 
+ import static org.apache.cassandra.utils.ByteBufferUtil.bytes;
+ 
+ public final class PurgeFunctionTest
+ {
+     private static final String KEYSPACE = "PurgeFunctionTest";
+     private static final String TABLE = "table";
+ 
+     private CFMetaData metadata;
+     private DecoratedKey key;
+ 
+     private static UnfilteredPartitionIterator 
withoutPurgeableTombstones(UnfilteredPartitionIterator iterator, int gcBefore)
+     {
+         class WithoutPurgeableTombstones extends PurgeFunction
+         {
+             private WithoutPurgeableTombstones()
+             {
+                 super(iterator.isForThrift(), FBUtilities.nowInSeconds(), 
gcBefore, Integer.MAX_VALUE, false, false);
+             }
+ 
+             protected Predicate<Long> getPurgeEvaluator()
+             {
+                 return time -> true;
+             }
+         }
+ 
+         return Transformation.apply(iterator, new 
WithoutPurgeableTombstones());
+     }
+ 
+     @Before
+     public void setUp()
+     {
++        DatabaseDescriptor.setPartitionerUnsafe(Murmur3Partitioner.instance);
++
+         metadata =
+             CFMetaData.Builder
+                       .create(KEYSPACE, TABLE)
+                       .addPartitionKey("pk", UTF8Type.instance)
+                       .addClusteringColumn("ck", UTF8Type.instance)
+                       .build();
+         key = Murmur3Partitioner.instance.decorateKey(bytes("key"));
+     }
+ 
+     @Test
+     public void testNothingIsPurgeableASC()
+     {
+         UnfilteredPartitionIterator original = iter(false
+         , bound(Kind.INCL_START_BOUND, 0L, 0, "a")
+         , boundary(Kind.EXCL_END_INCL_START_BOUNDARY, 0L, 0, 1L, 1, "b")
+         , bound(Kind.INCL_END_BOUND, 1L, 1, "c")
+         );
+         UnfilteredPartitionIterator purged = 
withoutPurgeableTombstones(original, 0);
+ 
+         UnfilteredPartitionIterator expected = iter(false
+         , bound(Kind.INCL_START_BOUND, 0L, 0, "a")
+         , boundary(Kind.EXCL_END_INCL_START_BOUNDARY, 0L, 0, 1L, 1, "b")
+         , bound(Kind.INCL_END_BOUND, 1L, 1, "c")
+         );
+         assertIteratorsEqual(expected, purged);
+     }
+ 
+     @Test
+     public void testNothingIsPurgeableDESC()
+     {
+         UnfilteredPartitionIterator original = iter(true
+         , bound(Kind.INCL_END_BOUND, 1L, 1, "c")
+         , boundary(Kind.EXCL_END_INCL_START_BOUNDARY, 0L, 0, 1L, 1, "b")
+         , bound(Kind.INCL_START_BOUND, 0L, 0, "a")
+         );
+         UnfilteredPartitionIterator purged = 
withoutPurgeableTombstones(original, 0);
+ 
+         UnfilteredPartitionIterator expected = iter(true
+         , bound(Kind.INCL_END_BOUND, 1L, 1, "c")
+         , boundary(Kind.EXCL_END_INCL_START_BOUNDARY, 0L, 0, 1L, 1, "b")
+         , bound(Kind.INCL_START_BOUND, 0L, 0, "a")
+         );
+         assertIteratorsEqual(expected, purged);
+     }
+ 
+     @Test
+     public void testEverythingIsPurgeableASC()
+     {
+         UnfilteredPartitionIterator original = iter(false
+         , bound(Kind.INCL_START_BOUND, 0L, 0, "a")
+         , boundary(Kind.EXCL_END_INCL_START_BOUNDARY, 0L, 0, 1L, 1, "b")
+         , bound(Kind.INCL_END_BOUND, 1L, 1, "c")
+         );
+         UnfilteredPartitionIterator purged = 
withoutPurgeableTombstones(original, 2);
+ 
+         assertTrue(!purged.hasNext());
+     }
+ 
+     @Test
+     public void testEverythingIsPurgeableDESC()
+     {
+         UnfilteredPartitionIterator original = iter(false
+         , bound(Kind.INCL_END_BOUND, 1L, 1, "c")
+         , boundary(Kind.EXCL_END_INCL_START_BOUNDARY, 0L, 0, 1L, 1, "b")
+         , bound(Kind.INCL_START_BOUND, 0L, 0, "a")
+         );
+         UnfilteredPartitionIterator purged = 
withoutPurgeableTombstones(original, 2);
+ 
+         assertTrue(!purged.hasNext());
+     }
+ 
+     @Test
+     public void testFirstHalfIsPurgeableASC()
+     {
+         UnfilteredPartitionIterator original = iter(false
+         , bound(Kind.INCL_START_BOUND, 0L, 0, "a")
+         , boundary(Kind.EXCL_END_INCL_START_BOUNDARY, 0L, 0, 1L, 1, "b")
+         , bound(Kind.INCL_END_BOUND, 1L, 1, "c")
+         );
+         UnfilteredPartitionIterator purged = 
withoutPurgeableTombstones(original, 1);
+ 
+         UnfilteredPartitionIterator expected = iter(false
+         , bound(Kind.INCL_START_BOUND, 1L, 1, "b")
+         , bound(Kind.INCL_END_BOUND, 1L, 1, "c")
+         );
+         assertIteratorsEqual(expected, purged);
+     }
+ 
+     @Test
+     public void testFirstHalfIsPurgeableDESC()
+     {
+         UnfilteredPartitionIterator original = iter(true
+         , bound(Kind.INCL_END_BOUND, 1L, 1, "c")
+         , boundary(Kind.EXCL_END_INCL_START_BOUNDARY, 0L, 0, 1L, 1, "b")
+         , bound(Kind.INCL_START_BOUND, 0L, 0, "a")
+         );
+         UnfilteredPartitionIterator purged = 
withoutPurgeableTombstones(original, 1);
+ 
+         UnfilteredPartitionIterator expected = iter(false
+         , bound(Kind.INCL_END_BOUND, 1L, 1, "c")
+         , bound(Kind.INCL_START_BOUND, 1L, 1, "b")
+         );
+         assertIteratorsEqual(expected, purged);
+     }
+ 
+     @Test
+     public void testSecondHalfIsPurgeableASC()
+     {
+         UnfilteredPartitionIterator original = iter(false
+         , bound(Kind.INCL_START_BOUND, 1L, 1, "a")
+         , boundary(Kind.EXCL_END_INCL_START_BOUNDARY, 1L, 1, 0L, 0, "b")
+         , bound(Kind.INCL_END_BOUND, 0L, 0, "c")
+         );
+         UnfilteredPartitionIterator purged = 
withoutPurgeableTombstones(original, 1);
+ 
+         UnfilteredPartitionIterator expected = iter(false
+         , bound(Kind.INCL_START_BOUND, 1L, 1, "a")
+         , bound(Kind.EXCL_END_BOUND, 1L, 1, "b")
+         );
+         assertIteratorsEqual(expected, purged);
+     }
+ 
+     @Test
+     public void testSecondHalfIsPurgeableDESC()
+     {
+         UnfilteredPartitionIterator original = iter(true
+         , bound(Kind.INCL_END_BOUND, 0L, 0, "c")
+         , boundary(Kind.EXCL_END_INCL_START_BOUNDARY, 1L, 1, 0L, 0, "b")
+         , bound(Kind.INCL_START_BOUND, 1L, 1, "a")
+         );
+         UnfilteredPartitionIterator purged = 
withoutPurgeableTombstones(original, 1);
+ 
+         UnfilteredPartitionIterator expected = iter(true
+         , bound(Kind.EXCL_END_BOUND, 1L, 1, "b")
+         , bound(Kind.INCL_START_BOUND, 1L, 1, "a")
+         );
+         assertIteratorsEqual(expected, purged);
+     }
+ 
+     private UnfilteredPartitionIterator iter(boolean isReversedOrder, 
Unfiltered... unfiltereds)
+     {
+         Iterator<Unfiltered> iterator = Iterators.forArray(unfiltereds);
+ 
+         UnfilteredRowIterator rowIter =
+             new AbstractUnfilteredRowIterator(metadata,
+                                               key,
+                                               DeletionTime.LIVE,
+                                               metadata.partitionColumns(),
+                                               Rows.EMPTY_STATIC_ROW,
+                                               isReversedOrder,
+                                               EncodingStats.NO_STATS)
+         {
+             protected Unfiltered computeNext()
+             {
+                 return iterator.hasNext() ? iterator.next() : endOfData();
+             }
+         };
+ 
+         return new SingletonUnfilteredPartitionIterator(rowIter, false);
+     }
+ 
+     private RangeTombstoneBoundMarker bound(ClusteringPrefix.Kind kind,
+                                             long timestamp,
+                                             int localDeletionTime,
+                                             Object clusteringValue)
+     {
+         ByteBuffer[] clusteringByteBuffers =
+             new ByteBuffer[] { 
decompose(metadata.clusteringColumns().get(0).type, clusteringValue) };
+ 
 -        return new RangeTombstoneBoundMarker(new RangeTombstone.Bound(kind, 
clusteringByteBuffers),
++        return new RangeTombstoneBoundMarker(ClusteringBound.create(kind, 
clusteringByteBuffers),
+                                              new DeletionTime(timestamp, 
localDeletionTime));
+     }
+ 
+     private RangeTombstoneBoundaryMarker boundary(ClusteringPrefix.Kind kind,
+                                                   long closeTimestamp,
+                                                   int closeLocalDeletionTime,
+                                                   long openTimestamp,
+                                                   int openDeletionTime,
+                                                   Object clusteringValue)
+     {
+         ByteBuffer[] clusteringByteBuffers =
+             new ByteBuffer[] { 
decompose(metadata.clusteringColumns().get(0).type, clusteringValue) };
+ 
 -        return new RangeTombstoneBoundaryMarker(new 
RangeTombstone.Bound(kind, clusteringByteBuffers),
++        return new 
RangeTombstoneBoundaryMarker(ClusteringBoundary.create(kind, 
clusteringByteBuffers),
+                                                 new 
DeletionTime(closeTimestamp, closeLocalDeletionTime),
+                                                 new 
DeletionTime(openTimestamp, openDeletionTime));
+     }
+ 
+     @SuppressWarnings("unchecked")
+     private static <T> ByteBuffer decompose(AbstractType<?> type, T value)
+     {
+         return ((AbstractType<T>) type).decompose(value);
+     }
+ 
+     private void assertIteratorsEqual(UnfilteredPartitionIterator iter1, 
UnfilteredPartitionIterator iter2)
+     {
+         while (iter1.hasNext())
+         {
+             assertTrue(iter2.hasNext());
+ 
+             try (UnfilteredRowIterator partition1 = iter1.next())
+             {
+                 try (UnfilteredRowIterator partition2 = iter2.next())
+                 {
+                     assertIteratorsEqual(partition1, partition2);
+                 }
+             }
+         }
+ 
+         assertTrue(!iter2.hasNext());
+     }
+ 
+     private void assertIteratorsEqual(UnfilteredRowIterator iter1, 
UnfilteredRowIterator iter2)
+     {
+         while (iter1.hasNext())
+         {
+             assertTrue(iter2.hasNext());
+ 
+             assertEquals(iter1.next(), iter2.next());
+         }
+         assertTrue(!iter2.hasNext());
+     }
+ }


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

Reply via email to