From 9f335fe482d49e84af8c5380df56d3e768a60be9 Mon Sep 17 00:00:00 2001 From: Carl Yeksigian Date: Thu, 17 Sep 2015 12:20:20 -0400 Subject: [PATCH] Issues with MVs caused by updateAffectsView and createForDeletionInfo patch by carlyeks; reviewed by slebresne for CASSANDRA-10362 --- CHANGES.txt | 1 + .../org/apache/cassandra/db/view/View.java | 17 +++-- .../org/apache/cassandra/cql3/ViewTest.java | 76 ++++++++++++++++++- 3 files changed, 85 insertions(+), 9 deletions(-) diff --git a/CHANGES.txt b/CHANGES.txt index afe7dcbc48..d6554e9a2d 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,4 +1,5 @@ 3.0.0-rc1 + * Fix minor bugs in MV handling (CASSANDRA-10362) * Allow custom indexes with 0,1 or multiple target columns (CASSANDRA-10124) * Improve MV schema representation (CASSANDRA-9921) * Add flag to enable/disable coordinator batchlog for MV writes (CASSANDRA-10230) diff --git a/src/java/org/apache/cassandra/db/view/View.java b/src/java/org/apache/cassandra/db/view/View.java index 7bcb59217f..fb34ca9651 100644 --- a/src/java/org/apache/cassandra/db/view/View.java +++ b/src/java/org/apache/cassandra/db/view/View.java @@ -36,6 +36,7 @@ import org.apache.cassandra.config.ColumnDefinition; import org.apache.cassandra.config.ViewDefinition; import org.apache.cassandra.config.Schema; import org.apache.cassandra.cql3.ColumnIdentifier; +import org.apache.cassandra.db.AbstractReadCommandBuilder; import org.apache.cassandra.db.AbstractReadCommandBuilder.SinglePartitionSliceBuilder; import org.apache.cassandra.db.CBuilder; import org.apache.cassandra.db.Clustering; @@ -62,6 +63,7 @@ import org.apache.cassandra.db.rows.Row; import org.apache.cassandra.db.rows.RowIterator; import org.apache.cassandra.schema.KeyspaceMetadata; import org.apache.cassandra.service.pager.QueryPager; +import org.apache.cassandra.utils.FBUtilities; /** * A View copies data from a base table into a view table which can be queried independently from the @@ -214,11 +216,12 @@ public class View // Check each row for deletion or update for (Row row : partition) { - if (row.hasComplexDeletion()) - return true; if (!row.deletion().isLive()) return true; + if (row.primaryKeyLivenessInfo().isLive(FBUtilities.nowInSeconds())) + return true; + for (ColumnData data : row) { if (definition.metadata.getColumnDefinition(data.column().name) != null) @@ -434,7 +437,11 @@ public class View // entire partition of data which is not distributed on a single partition node. DecoratedKey dk = rowSet.dk; - if (deletionInfo.hasRanges()) + if (!deletionInfo.getPartitionDeletion().isLive()) + { + command = SinglePartitionReadCommand.fullPartitionRead(baseCfs.metadata, rowSet.nowInSec, dk); + } + else { SinglePartitionSliceBuilder builder = new SinglePartitionSliceBuilder(baseCfs, dk); Iterator tombstones = deletionInfo.rangeIterator(false); @@ -447,10 +454,6 @@ public class View command = builder.build(); } - else - { - command = SinglePartitionReadCommand.fullPartitionRead(baseCfs.metadata, rowSet.nowInSec, dk); - } } if (command == null) diff --git a/test/unit/org/apache/cassandra/cql3/ViewTest.java b/test/unit/org/apache/cassandra/cql3/ViewTest.java index 95662e553e..43f7747bf9 100644 --- a/test/unit/org/apache/cassandra/cql3/ViewTest.java +++ b/test/unit/org/apache/cassandra/cql3/ViewTest.java @@ -186,6 +186,9 @@ public class ViewTest extends CQLTester "bigintval bigint, " + "PRIMARY KEY((k, asciival)))"); + execute("USE " + keyspace()); + executeNet(protocolVersion, "USE " + keyspace()); + // Must include "IS NOT NULL" for primary keys try { @@ -1335,8 +1338,8 @@ public class ViewTest extends CQLTester createView("mv3", "CREATE MATERIALIZED VIEW %s AS SELECT * FROM %%s WHERE b IS NOT NULL AND c IS NOT NULL PRIMARY KEY (a, b, c)"); createView("mv4", "CREATE MATERIALIZED VIEW %s AS SELECT * FROM %%s WHERE b IS NOT NULL AND c IS NOT NULL PRIMARY KEY (a, c, b) WITH CLUSTERING ORDER BY (c DESC)"); - updateView("INSERT INTO %s (a, b, c, d) VALUES (?, ?, ?, ?) USING TIMESTAMP 1", 1, 1, 1, 1); - updateView("INSERT INTO %s (a, b, c, d) VALUES (?, ?, ?, ?) USING TIMESTAMP 1", 1, 2, 2, 2); + updateView("INSERT INTO %s (a, b, c, d) VALUES (?, ?, ?, ?)", 1, 1, 1, 1); + updateView("INSERT INTO %s (a, b, c, d) VALUES (?, ?, ?, ?)", 1, 2, 2, 2); ResultSet mvRows = executeNet(protocolVersion, "SELECT b FROM mv1"); assertRowsNet(protocolVersion, mvRows, @@ -1384,4 +1387,73 @@ public class ViewTest extends CQLTester Assert.assertEquals("Cannot use DROP TABLE on Materialized View", e.getMessage()); } } + + @Test + public void testMultipleDeletes() throws Throwable + { + createTable("CREATE TABLE %s (" + + "a int," + + "b int," + + "PRIMARY KEY (a, b))"); + + executeNet(protocolVersion, "USE " + keyspace()); + + createView("mv1", "CREATE MATERIALIZED VIEW %s AS SELECT * FROM %%s WHERE b IS NOT NULL PRIMARY KEY (b, a)"); + + updateView("INSERT INTO %s (a, b) VALUES (?, ?)", 1, 1); + updateView("INSERT INTO %s (a, b) VALUES (?, ?)", 1, 2); + updateView("INSERT INTO %s (a, b) VALUES (?, ?)", 1, 3); + + ResultSet mvRows = executeNet(protocolVersion, "SELECT a, b FROM mv1"); + assertRowsNet(protocolVersion, mvRows, + row(1, 1), + row(1, 2), + row(1, 3)); + + updateView(String.format("BEGIN UNLOGGED BATCH " + + "DELETE FROM %s WHERE a = 1 AND b > 1 AND b < 3;" + + "DELETE FROM %s WHERE a = 1;" + + "APPLY BATCH", currentTable(), currentTable())); + + mvRows = executeNet(protocolVersion, "SELECT a, b FROM mv1"); + assertRowsNet(protocolVersion, mvRows); + } + + @Test + public void testPrimaryKeyOnlyTable() throws Throwable + { + createTable("CREATE TABLE %s (" + + "a int," + + "b int," + + "PRIMARY KEY (a, b))"); + + executeNet(protocolVersion, "USE " + keyspace()); + + // Cannot use SELECT *, as those are always handled by the includeAll shortcut in View.updateAffectsView + createView("mv1", "CREATE MATERIALIZED VIEW %s AS SELECT a, b FROM %%s WHERE b IS NOT NULL PRIMARY KEY (b, a)"); + + updateView("INSERT INTO %s (a, b) VALUES (?, ?)", 1, 1); + + ResultSet mvRows = executeNet(protocolVersion, "SELECT a, b FROM mv1"); + assertRowsNet(protocolVersion, mvRows, row(1, 1)); + } + + @Test + public void testPartitionKeyOnlyTable() throws Throwable + { + createTable("CREATE TABLE %s (" + + "a int," + + "b int," + + "PRIMARY KEY ((a, b)))"); + + executeNet(protocolVersion, "USE " + keyspace()); + + // Cannot use SELECT *, as those are always handled by the includeAll shortcut in View.updateAffectsView + createView("mv1", "CREATE MATERIALIZED VIEW %s AS SELECT a, b FROM %%s WHERE a IS NOT NULL AND b IS NOT NULL PRIMARY KEY (b, a)"); + + updateView("INSERT INTO %s (a, b) VALUES (?, ?)", 1, 1); + + ResultSet mvRows = executeNet(protocolVersion, "SELECT a, b FROM mv1"); + assertRowsNet(protocolVersion, mvRows, row(1, 1)); + } }