This is an automated email from the ASF dual-hosted git repository.

adelapena pushed a commit to branch cassandra-3.0
in repository https://gitbox.apache.org/repos/asf/cassandra.git


The following commit(s) were added to refs/heads/cassandra-3.0 by this push:
     new 865b67b  Fix ColumnFilter behaviour to prevent digest mitmatches 
during upgrades
865b67b is described below

commit 865b67b21d326728936f0b80681129c73a2e374a
Author: jacek-lewandowski <[email protected]>
AuthorDate: Mon Mar 1 12:24:28 2021 +0000

    Fix ColumnFilter behaviour to prevent digest mitmatches during upgrades
    
    patch by Jacek Lewandowski; reviewed by Andrés de la Peña and Yifan Cai for 
CASSANDRA-16415
---
 CHANGES.txt                                        |   1 +
 .../apache/cassandra/db/filter/ColumnFilter.java   |  82 +----
 .../test/ReadDigestConsistencyTest.java            | 113 +++++++
 .../cassandra/db/filter/ColumnFilterTest.java      | 354 +++++++++++++++++++--
 4 files changed, 459 insertions(+), 91 deletions(-)

diff --git a/CHANGES.txt b/CHANGES.txt
index 9f0a5a7..c174cd3 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -1,4 +1,5 @@
 3.0.25:
+ * Fix ColumnFilter behaviour to prevent digest mitmatches during upgrades 
(CASSANDRA-16415)
  * Update debian packaging for python3 (CASSANDRA-16396)
  * Avoid pushing schema mutations when setting up distributed system keyspaces 
locally (CASSANDRA-16387)
 Merged from 2.2:
diff --git a/src/java/org/apache/cassandra/db/filter/ColumnFilter.java 
b/src/java/org/apache/cassandra/db/filter/ColumnFilter.java
index 858c944..520c43c 100644
--- a/src/java/org/apache/cassandra/db/filter/ColumnFilter.java
+++ b/src/java/org/apache/cassandra/db/filter/ColumnFilter.java
@@ -26,7 +26,6 @@ import com.google.common.collect.TreeMultimap;
 import org.apache.cassandra.config.CFMetaData;
 import org.apache.cassandra.cql3.ColumnIdentifier;
 import org.apache.cassandra.db.*;
-import org.apache.cassandra.db.rows.Cell;
 import org.apache.cassandra.db.rows.CellPath;
 import org.apache.cassandra.config.ColumnDefinition;
 import org.apache.cassandra.io.util.DataInputPlus;
@@ -142,44 +141,6 @@ public class ColumnFilter
     }
 
     /**
-     * Whether the provided cell of a complex column is selected by this 
selection.
-     */
-    public boolean includes(Cell cell)
-    {
-        if (isFetchAll || subSelections == null || !cell.column().isComplex())
-            return true;
-
-        SortedSet<ColumnSubselection> s = 
subSelections.get(cell.column().name);
-        if (s.isEmpty())
-            return true;
-
-        for (ColumnSubselection subSel : s)
-            if (subSel.compareInclusionOf(cell.path()) == 0)
-                return true;
-
-        return false;
-    }
-
-    /**
-     * Whether we can skip the value of the cell of a complex column.
-     */
-    public boolean canSkipValue(ColumnDefinition column, CellPath path)
-    {
-        if (!isFetchAll || subSelections == null || !column.isComplex())
-            return false;
-
-        SortedSet<ColumnSubselection> s = subSelections.get(column.name);
-        if (s.isEmpty())
-            return false;
-
-        for (ColumnSubselection subSel : s)
-            if (subSel.compareInclusionOf(path) == 0)
-                return false;
-
-        return true;
-    }
-
-    /**
      * Creates a new {@code Tester} to efficiently test the inclusion of cells 
of complex column
      * {@code column}.
      */
@@ -340,44 +301,31 @@ public class ColumnFilter
                Objects.equals(otherCf.subSelections, this.subSelections);
 
     }
+
     @Override
     public String toString()
     {
+        String prefix = "";
+
         if (isFetchAll)
-            return "*";
+            return "*/*";
 
         if (queried.isEmpty())
-            return "";
-
-        Iterator<ColumnDefinition> defs = queried.selectOrderIterator();
-        if (!defs.hasNext())
-            return "<none>";
+            return prefix + "[]";
 
-        StringBuilder sb = new StringBuilder();
-        appendColumnDef(sb, defs.next());
-        while (defs.hasNext())
-            appendColumnDef(sb.append(", "), defs.next());
-        return sb.toString();
-    }
-
-    private void appendColumnDef(StringBuilder sb, ColumnDefinition column)
-    {
-        if (subSelections == null)
+        StringJoiner joiner = new StringJoiner(", ", "[", "]");
+        Iterator<ColumnDefinition> it = queried.selectOrderIterator();
+        while (it.hasNext())
         {
-            sb.append(column.name);
-            return;
-        }
+            ColumnDefinition column = it.next();
+            SortedSet<ColumnSubselection> s = subSelections != null ? 
subSelections.get(column.name) : Collections.emptySortedSet();
 
-        SortedSet<ColumnSubselection> s = subSelections.get(column.name);
-        if (s.isEmpty())
-        {
-            sb.append(column.name);
-            return;
+            if (s.isEmpty())
+                joiner.add(String.valueOf(column.name));
+            else
+                s.forEach(subSel -> joiner.add(String.format("%s%s", 
column.name, subSel)));
         }
-
-        int i = 0;
-        for (ColumnSubselection subSel : s)
-            sb.append(i++ == 0 ? "" : ", ").append(column.name).append(subSel);
+        return prefix + joiner.toString();
     }
 
     public static class Serializer
diff --git 
a/test/distributed/org/apache/cassandra/distributed/test/ReadDigestConsistencyTest.java
 
b/test/distributed/org/apache/cassandra/distributed/test/ReadDigestConsistencyTest.java
new file mode 100644
index 0000000..8071eea
--- /dev/null
+++ 
b/test/distributed/org/apache/cassandra/distributed/test/ReadDigestConsistencyTest.java
@@ -0,0 +1,113 @@
+/*
+ * 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.distributed.test;
+
+import java.util.Arrays;
+import java.util.UUID;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import org.apache.cassandra.distributed.Cluster;
+import org.apache.cassandra.distributed.api.ConsistencyLevel;
+import org.apache.cassandra.distributed.api.ICoordinator;
+
+public class ReadDigestConsistencyTest extends TestBaseImpl
+{
+    public static final String TABLE_NAME = "tbl";
+    public static final String CREATE_TABLE = String.format("CREATE TABLE 
%s.%s (" +
+                                                            "   k int, " +
+                                                            "   c int, " +
+                                                            "   s1 int static, 
" +
+                                                            "   s2 set<int> 
static, " +
+                                                            "   v1 int, " +
+                                                            "   v2 set<int>, " 
+
+                                                            "   PRIMARY KEY 
(k, c))", KEYSPACE, TABLE_NAME);
+
+    public static final String INSERT = String.format("INSERT INTO %s.%s (k, 
c, s1, s2, v1, v2) VALUES (?, ?, ?, ?, ?, ?)", KEYSPACE, TABLE_NAME);
+
+
+    public static final String SELECT_TRACE = "SELECT activity FROM 
system_traces.events where session_id = ? and source = ? ALLOW FILTERING;";
+
+    @Test
+    public void testDigestConsistency() throws Exception
+    {
+        try (Cluster cluster = init(builder().withNodes(2).start()))
+        {
+            cluster.schemaChange(CREATE_TABLE);
+            insertData(cluster.coordinator(1));
+            testDigestConsistency(cluster.coordinator(1));
+            testDigestConsistency(cluster.coordinator(2));
+        }
+    }
+
+    public static void checkTraceForDigestMismatch(ICoordinator coordinator, 
String query, Object... boundValues)
+    {
+        UUID sessionId = UUID.randomUUID();
+        coordinator.executeWithTracing(sessionId, query, ConsistencyLevel.ALL, 
boundValues);
+        Object[][] results = coordinator.execute(SELECT_TRACE,
+                                                 ConsistencyLevel.ALL,
+                                                 sessionId,
+                                                 
coordinator.instance().broadcastAddress().getAddress());
+        for (Object[] result : results)
+        {
+            String activity = (String) result[0];
+            Assert.assertFalse(String.format("Found Digest Mismatch while 
executing query: %s with bound values %s on %s/%s",
+                                             query,
+                                             Arrays.toString(boundValues),
+                                             
coordinator.instance().broadcastAddress(),
+                                             
coordinator.instance().getReleaseVersionString()),
+                               activity.toLowerCase().contains("mismatch for 
key"));
+        }
+    }
+
+    public static void insertData(ICoordinator coordinator)
+    {
+        coordinator.execute(String.format("INSERT INTO %s.%s (k, c, s1, s2, 
v1, v2) VALUES (1, 1, 2, {1, 2, 3, 4, 5}, 3, {6, 7, 8, 9, 10})", KEYSPACE, 
TABLE_NAME), ConsistencyLevel.ALL);
+        coordinator.execute(String.format("INSERT INTO %s.%s (k, c, s1, s2, 
v1, v2) VALUES (1, 2, 3, {2, 3, 4, 5, 6}, 4, {7, 8, 9, 10, 11})", KEYSPACE, 
TABLE_NAME), ConsistencyLevel.ALL);
+    }
+
+    public static void testDigestConsistency(ICoordinator coordinator)
+    {
+        String queryPattern = "SELECT %s FROM %s.%s WHERE %s";
+        String[] columnss1 = {
+        "k, c",
+        "*",
+        "v1",
+        "v2",
+        "v1, s1",
+        "v1, s2"
+        };
+
+        String[] columnss2 = {
+        "s1",
+        "s2"
+        };
+
+        for (String columns : columnss1)
+        {
+            checkTraceForDigestMismatch(coordinator, 
String.format(queryPattern, columns, KEYSPACE, TABLE_NAME, "k = 1"));
+            checkTraceForDigestMismatch(coordinator, 
String.format(queryPattern, columns, KEYSPACE, TABLE_NAME, "k = 1 AND c = 2"));
+        }
+        for (String columns : columnss2)
+        {
+            checkTraceForDigestMismatch(coordinator, 
String.format(queryPattern, columns, KEYSPACE, TABLE_NAME, "k = 1"));
+        }
+    }
+}
diff --git a/test/unit/org/apache/cassandra/db/filter/ColumnFilterTest.java 
b/test/unit/org/apache/cassandra/db/filter/ColumnFilterTest.java
index aa56091..80c1e42 100644
--- a/test/unit/org/apache/cassandra/db/filter/ColumnFilterTest.java
+++ b/test/unit/org/apache/cassandra/db/filter/ColumnFilterTest.java
@@ -18,12 +18,19 @@
 
 package org.apache.cassandra.db.filter;
 
+import java.io.IOException;
+import java.util.function.Consumer;
+
+import com.google.common.base.Throwables;
+import org.junit.Assert;
 import org.junit.Test;
 
-import junit.framework.Assert;
 import org.apache.cassandra.config.CFMetaData;
 import org.apache.cassandra.config.ColumnDefinition;
+import org.apache.cassandra.db.PartitionColumns;
 import org.apache.cassandra.db.marshal.Int32Type;
+import org.apache.cassandra.db.marshal.SetType;
+import org.apache.cassandra.db.rows.CellPath;
 import org.apache.cassandra.dht.Murmur3Partitioner;
 import org.apache.cassandra.io.util.DataInputBuffer;
 import org.apache.cassandra.io.util.DataInputPlus;
@@ -31,40 +38,339 @@ import org.apache.cassandra.io.util.DataOutputBuffer;
 import org.apache.cassandra.net.MessagingService;
 import org.apache.cassandra.utils.ByteBufferUtil;
 
+import static org.junit.Assert.assertEquals;
+
 public class ColumnFilterTest
 {
-    final static ColumnFilter.Serializer serializer = new 
ColumnFilter.Serializer();
+    private static final ColumnFilter.Serializer serializer = new 
ColumnFilter.Serializer();
+
+    private final CFMetaData metadata = CFMetaData.Builder.create("ks", 
"table")
+                                                          
.withPartitioner(Murmur3Partitioner.instance)
+                                                          
.addPartitionKey("pk", Int32Type.instance)
+                                                          
.addClusteringColumn("ck", Int32Type.instance)
+                                                          
.addStaticColumn("s1", Int32Type.instance)
+                                                          
.addStaticColumn("s2", SetType.getInstance(Int32Type.instance, true))
+                                                          
.addRegularColumn("v1", Int32Type.instance)
+                                                          
.addRegularColumn("v2", SetType.getInstance(Int32Type.instance, true))
+                                                          .build();
+
+    private final ColumnDefinition s1 = 
metadata.getColumnDefinition(ByteBufferUtil.bytes("s1"));
+    private final ColumnDefinition s2 = 
metadata.getColumnDefinition(ByteBufferUtil.bytes("s2"));
+    private final ColumnDefinition v1 = 
metadata.getColumnDefinition(ByteBufferUtil.bytes("v1"));
+    private final ColumnDefinition v2 = 
metadata.getColumnDefinition(ByteBufferUtil.bytes("v2"));
+    private final CellPath path0 = CellPath.create(ByteBufferUtil.bytes(0));
+    private final CellPath path1 = CellPath.create(ByteBufferUtil.bytes(1));
+    private final CellPath path2 = CellPath.create(ByteBufferUtil.bytes(2));
+    private final CellPath path3 = CellPath.create(ByteBufferUtil.bytes(3));
+    private final CellPath path4 = CellPath.create(ByteBufferUtil.bytes(4));
+
+    // Select all
+
+    @Test
+    public void testSelectAll()
+    {
+        Consumer<ColumnFilter> check = filter -> {
+            testRoundTrips(filter);
+            assertEquals("*/*", filter.toString());
+            assertFetchedQueried(true, true, filter, v1, v2, s1, s2);
+            assertCellFetchedQueried(true, true, filter, v2, path0, path1, 
path2, path3, path4);
+            assertCellFetchedQueried(true, true, filter, s2, path0, path1, 
path2, path3, path4);
+        };
+
+        check.accept(ColumnFilter.all(metadata));
+        check.accept(ColumnFilter.allColumnsBuilder(metadata).build());
+    }
+
+    // Selections
+
+    @Test
+    public void testSelectNothing()
+    {
+        Consumer<ColumnFilter> check = filter -> {
+            testRoundTrips(filter);
+            assertEquals("[]", filter.toString());
+            assertFetchedQueried(false, false, filter, v1, v2, s1, s2);
+            assertCellFetchedQueried(false, false, filter, v2, path0, path1, 
path2, path3, path4);
+            assertCellFetchedQueried(false, false, filter, s2, path0, path1, 
path2, path3, path4);
+        };
+
+        check.accept(ColumnFilter.selection(PartitionColumns.NONE));
+        check.accept(ColumnFilter.selectionBuilder().build());
+    }
+
+    @Test
+    public void testSelectSimpleColumn()
+    {
+        Consumer<ColumnFilter> check = filter -> {
+            testRoundTrips(filter);
+            assertEquals("[v1]", filter.toString());
+            assertFetchedQueried(true, true, filter, v1);
+            assertFetchedQueried(false, false, filter, v2, s1, s2);
+            assertCellFetchedQueried(false, false, filter, v2, path0, path1, 
path2, path3, path4);
+            assertCellFetchedQueried(false, false, filter, s2, path0, path1, 
path2, path3, path4);
+        };
+
+        
check.accept(ColumnFilter.selection(PartitionColumns.builder().add(v1).build()));
+        check.accept(ColumnFilter.selectionBuilder().add(v1).build());
+    }
+
+    @Test
+    public void testSelectComplexColumn()
+    {
+        Consumer<ColumnFilter> check = filter -> {
+            testRoundTrips(filter);
+            assertEquals("[v2]", filter.toString());
+            assertFetchedQueried(true, true, filter, v2);
+            assertFetchedQueried(false, false, filter, v1, s1, s2);
+            assertCellFetchedQueried(true, true, filter, v2, path0, path1, 
path2, path3, path4);
+            assertCellFetchedQueried(false, false, filter, s2, path0, path1, 
path2, path3, path4);
+        };
+
+        
check.accept(ColumnFilter.selection(PartitionColumns.builder().add(v2).build()));
+        check.accept(ColumnFilter.selectionBuilder().add(v2).build());
+    }
 
     @Test
-    public void columnFilterSerialisationRoundTrip() throws Exception
+    public void testSelectStaticColumn()
     {
-        CFMetaData metadata = CFMetaData.Builder.create("ks", "table")
-                                                
.withPartitioner(Murmur3Partitioner.instance)
-                                                .addPartitionKey("pk", 
Int32Type.instance)
-                                                .addClusteringColumn("ck", 
Int32Type.instance)
-                                                .addRegularColumn("v1", 
Int32Type.instance)
-                                                .addRegularColumn("v2", 
Int32Type.instance)
-                                                .addRegularColumn("v3", 
Int32Type.instance)
-                                                .build();
+        Consumer<ColumnFilter> check = filter -> {
+            testRoundTrips(filter);
+            assertEquals("[s1]", filter.toString());
+            assertFetchedQueried(true, true, filter, s1);
+            assertFetchedQueried(false, false, filter, v1, v2, s2);
+            assertCellFetchedQueried(false, false, filter, v2, path0, path1, 
path2, path3, path4);
+            assertCellFetchedQueried(false, false, filter, s2, path0, path1, 
path2, path3, path4);
+        };
+
+        
check.accept(ColumnFilter.selection(PartitionColumns.builder().add(s1).build()));
+        check.accept(ColumnFilter.selectionBuilder().add(s1).build());
+    }
+
+    @Test
+    public void testSelectStaticComplexColumn()
+    {
+        Consumer<ColumnFilter> check = filter -> {
+            testRoundTrips(filter);
+            assertEquals("[s2]", filter.toString());
+            assertFetchedQueried(true, true, filter, s2);
+            assertFetchedQueried(false, false, filter, v1, v2, s1);
+            assertCellFetchedQueried(false, false, filter, v2, path0, path1, 
path2, path3, path4);
+            assertCellFetchedQueried(true, true, filter, s2, path0, path1, 
path2, path3, path4);
+        };
+
+        
check.accept(ColumnFilter.selection(PartitionColumns.builder().add(s2).build()));
+        check.accept(ColumnFilter.selectionBuilder().add(s2).build());
+    }
 
-        ColumnDefinition v1 = 
metadata.getColumnDefinition(ByteBufferUtil.bytes("v1"));
+    @Test
+    public void testSelectColumns()
+    {
+        Consumer<ColumnFilter> check = filter -> {
+            testRoundTrips(filter);
+            assertEquals("[s1, s2, v1, v2]", filter.toString());
+            assertFetchedQueried(true, true, filter, v1, v2, s1, s2);
+            assertCellFetchedQueried(true, true, filter, v2, path0, path1, 
path2, path3, path4);
+            assertCellFetchedQueried(true, true, filter, s2, path0, path1, 
path2, path3, path4);
+        };
 
-        testRoundTrip(ColumnFilter.all(metadata), metadata, 
MessagingService.VERSION_30);
-        testRoundTrip(ColumnFilter.all(metadata), metadata, 
MessagingService.VERSION_3014);
+        
check.accept(ColumnFilter.selection(PartitionColumns.builder().add(v1).add(v2).add(s1).add(s2).build()));
+        
check.accept(ColumnFilter.selectionBuilder().add(v1).add(v2).add(s1).add(s2).build());
+    }
 
-        
testRoundTrip(ColumnFilter.selection(metadata.partitionColumns().without(v1)), 
metadata, MessagingService.VERSION_30);
-        
testRoundTrip(ColumnFilter.selection(metadata.partitionColumns().without(v1)), 
metadata, MessagingService.VERSION_3014);
+    @Test
+    public void testSelectIndividualCells()
+    {
+        ColumnFilter filter = ColumnFilter.selectionBuilder().select(v2, 
path1).select(v2, path3).build();
+        testRoundTrips(filter);
+        assertEquals("[v2[1], v2[3]]", filter.toString());
+        assertFetchedQueried(true, true, filter, v2);
+        assertFetchedQueried(false, false, filter, v1, s1, s2);
+        assertCellFetchedQueried(true, true, filter, v2, path1, path3);
+        assertCellFetchedQueried(false, false, filter, v2, path0, path2, 
path4);
+        assertCellFetchedQueried(false, false, filter, s2, path0, path1, 
path2, path3, path4);
+    }
 
-        testRoundTrip(ColumnFilter.selection(metadata, 
metadata.partitionColumns().without(v1)), metadata, 
MessagingService.VERSION_30);
-        testRoundTrip(ColumnFilter.selection(metadata, 
metadata.partitionColumns().without(v1)), metadata, 
MessagingService.VERSION_3014);
+    @Test
+    public void testSelectIndividualCellsFromStatic()
+    {
+        ColumnFilter filter = ColumnFilter.selectionBuilder().select(s2, 
path1).select(s2, path3).build();
+        testRoundTrips(filter);
+        assertEquals("[s2[1], s2[3]]", filter.toString());
+        assertFetchedQueried(true, true, filter, s2);
+        assertFetchedQueried(false, false, filter, v1, v2, s1);
+        assertCellFetchedQueried(false, false, filter, v2, path0, path1, 
path2, path3, path4);
+        assertCellFetchedQueried(true, true, filter, s2, path1, path3);
+        assertCellFetchedQueried(false, false, filter, s2, path0, path2, 
path4);
     }
 
-    static void testRoundTrip(ColumnFilter columnFilter, CFMetaData metadata, 
int version) throws Exception
+    @Test
+    public void testSelectCellSlice()
     {
-        DataOutputBuffer output = new DataOutputBuffer();
-        serializer.serialize(columnFilter, output, version);
-        Assert.assertEquals(serializer.serializedSize(columnFilter, version), 
output.position());
-        DataInputPlus input = new DataInputBuffer(output.buffer(), false);
-        Assert.assertEquals(serializer.deserialize(input, version, metadata), 
columnFilter);
+        ColumnFilter filter = ColumnFilter.selectionBuilder().slice(v2, path1, 
path3).build();
+        testRoundTrips(filter);
+        assertEquals("[v2[1:3]]", filter.toString());
+        assertFetchedQueried(true, true, filter, v2);
+        assertFetchedQueried(false, false, filter, v1, s1, s2);
+        assertCellFetchedQueried(true, true, filter, v2, path1, path2, path3);
+        assertCellFetchedQueried(false, false, filter, v2, path0, path4);
+        assertCellFetchedQueried(false, false, filter, s2, path0, path1, 
path2, path3, path4);
+    }
+
+    @Test
+    public void testSelectCellSliceFromStatic()
+    {
+        ColumnFilter filter = ColumnFilter.selectionBuilder().slice(s2, path1, 
path3).build();
+        testRoundTrips(filter);
+        assertEquals("[s2[1:3]]", filter.toString());
+        assertFetchedQueried(true, true, filter, s2);
+        assertFetchedQueried(false, false, filter, v1, v2, s1);
+        assertCellFetchedQueried(false, false, filter, v2, path0, path1, 
path2, path3, path4);
+        assertCellFetchedQueried(true, true, filter, s2, path1, path2, path3);
+        assertCellFetchedQueried(false, false, filter, s2, path0, path4);
+    }
+
+    @Test
+    public void testSelectColumnsWithCellsAndSlices()
+    {
+        ColumnFilter filter = ColumnFilter.selectionBuilder()
+                                          .add(v1)
+                                          .add(s1)
+                                          .slice(v2, path0, path2)
+                                          .select(v2, path4)
+                                          .select(s2, path0)
+                                          .slice(s2, path2, path4)
+                                          .build();
+        testRoundTrips(filter);
+        assertEquals("[s1, s2[0], s2[2:4], v1, v2[0:2], v2[4]]", 
filter.toString());
+        assertFetchedQueried(true, true, filter, v1, v2, s1, s2);
+        assertCellFetchedQueried(true, true, filter, v2, path0, path1, path2, 
path4);
+        assertCellFetchedQueried(false, false, filter, v2, path3);
+        assertCellFetchedQueried(true, true, filter, s2, path0, path2, path3, 
path4);
+        assertCellFetchedQueried(false, false, filter, s2, path1);
+    }
+
+    // select with metadata
+
+    @Test
+    public void testSelectSimpleColumnWithMetadata()
+    {
+        Consumer<ColumnFilter> check = filter -> {
+            testRoundTrips(filter);
+            assertFetchedQueried(true, true, filter, v1);
+
+            assertEquals("*/*", filter.toString());
+            assertFetchedQueried(true, true, filter, s1, s2, v2);
+            assertCellFetchedQueried(true, true, filter, v2, path0, path1, 
path2, path3, path4);
+            assertCellFetchedQueried(true, true, filter, s2, path0, path1, 
path2, path3, path4);
+        };
+
+        check.accept(ColumnFilter.selection(metadata, 
PartitionColumns.builder().add(v1).build()));
+        check.accept(ColumnFilter.allColumnsBuilder(metadata).add(v1).build());
+    }
+
+    @Test
+    public void testSelectStaticColumnWithMetadata()
+    {
+        Consumer<ColumnFilter> check = filter -> {
+            testRoundTrips(filter);
+            assertFetchedQueried(true, true, filter, s1);
+
+            assertEquals("*/*", filter.toString());
+            assertFetchedQueried(true, true, filter, v1, v2, s2);
+            assertCellFetchedQueried(true, true, filter, v2, path0, path1, 
path2, path3, path4);
+            assertCellFetchedQueried(true, true, filter, s2, path0, path1, 
path2, path3, path4);
+        };
+
+        check.accept(ColumnFilter.selection(metadata, 
PartitionColumns.builder().add(s1).build()));
+        check.accept(ColumnFilter.allColumnsBuilder(metadata).add(s1).build());
+    }
+
+    @Test
+    public void testSelectCellWithMetadata()
+    {
+        ColumnFilter filter = 
ColumnFilter.allColumnsBuilder(metadata).select(v2, path1).build();
+        testRoundTrips(filter);
+        assertFetchedQueried(true, true, filter, v2);
+
+        assertEquals("*/*", filter.toString());
+        assertFetchedQueried(true, true, filter, s1, s2, v1);
+        assertCellFetchedQueried(true, true, filter, v2, path1);
+        assertCellFetchedQueried(true, false, filter, v2, path0, path2, path3, 
path4);
+        assertCellFetchedQueried(true, true, filter, s2, path0, path1, path2, 
path3, path4);
+    }
+
+    @Test
+    public void testSelectStaticColumnCellWithMetadata()
+    {
+        ColumnFilter filter = 
ColumnFilter.allColumnsBuilder(metadata).select(s2, path1).build();
+        testRoundTrips(filter);
+        assertFetchedQueried(true, true, filter, s2);
+
+        assertEquals("*/*", filter.toString());
+        assertFetchedQueried(true, true, filter, v1, v2, s1);
+        assertCellFetchedQueried(true, true, filter, v2, path0, path1, path2, 
path3, path4);
+        assertCellFetchedQueried(true, true, filter, s2, path1);
+        assertCellFetchedQueried(true, false, filter, s2, path0, path2, path3, 
path4);
+    }
+
+    private void testRoundTrips(ColumnFilter cf)
+    {
+        testRoundTrip(cf, MessagingService.VERSION_30);
+        testRoundTrip(cf, MessagingService.VERSION_3014);
+    }
+
+    private void testRoundTrip(ColumnFilter columnFilter, int version)
+    {
+        try
+        {
+            DataOutputBuffer output = new DataOutputBuffer();
+            serializer.serialize(columnFilter, output, version);
+            Assert.assertEquals(serializer.serializedSize(columnFilter, 
version), output.position());
+            DataInputPlus input = new DataInputBuffer(output.buffer(), false);
+            ColumnFilter deserialized = serializer.deserialize(input, version, 
metadata);
+            Assert.assertEquals(deserialized, columnFilter);
+        }
+        catch (IOException e)
+        {
+            throw Throwables.propagate(e);
+        }
+    }
+
+    private static void assertFetchedQueried(boolean expectedIncluded,
+                                             boolean expectedNotSkipped,
+                                             ColumnFilter filter,
+                                             ColumnDefinition... columns)
+    {
+        for (ColumnDefinition column : columns)
+        {
+            assertEquals(String.format("Expected includes(%s) to be %s", 
column.name, expectedIncluded),
+                         expectedIncluded, filter.includes(column));
+            if (expectedIncluded)
+                assertEquals(String.format("Expected canSkipValue(%s) to be 
%s", column.name, !expectedNotSkipped),
+                             !expectedNotSkipped, filter.canSkipValue(column));
+        }
+    }
+
+    private static void assertCellFetchedQueried(boolean expectedIncluded,
+                                                 boolean expectedNotSkipped,
+                                                 ColumnFilter filter,
+                                                 ColumnDefinition column,
+                                                 CellPath... paths)
+    {
+        ColumnFilter.Tester tester = filter.newTester(column);
+
+        for (CellPath path : paths)
+        {
+            int p = ByteBufferUtil.toInt(path.get(0));
+
+            if (tester != null)
+            {
+                assertEquals(String.format("Expected tester.includes(%s:%s) to 
be %s", column.name, p, expectedIncluded),
+                             expectedIncluded, tester.includes(path));
+                if (expectedIncluded)
+                    assertEquals(String.format("Expected 
tester.canSkipValue(%s:%s) to be %s", column.name, p, !expectedNotSkipped),
+                                 !expectedNotSkipped, 
tester.canSkipValue(path));
+            }
+        }
     }
 }


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to