Repository: cassandra Updated Branches: refs/heads/trunk d8ad0f0f2 -> 334fbad7b
Preserve deletion info when notifying 2ary index of row update Patch by Tyler Hobbs; reviewed by Sam Tunnicliffe for CASSANDRA-10694 Project: http://git-wip-us.apache.org/repos/asf/cassandra/repo Commit: http://git-wip-us.apache.org/repos/asf/cassandra/commit/c2320c92 Tree: http://git-wip-us.apache.org/repos/asf/cassandra/tree/c2320c92 Diff: http://git-wip-us.apache.org/repos/asf/cassandra/diff/c2320c92 Branch: refs/heads/trunk Commit: c2320c92fdae6815b8952ba98b1e8e5239b5be2a Parents: 5730e7b Author: Tyler Hobbs <[email protected]> Authored: Fri Nov 13 15:35:40 2015 -0600 Committer: Tyler Hobbs <[email protected]> Committed: Fri Nov 13 15:35:40 2015 -0600 ---------------------------------------------------------------------- CHANGES.txt | 2 + .../cassandra/index/SecondaryIndexManager.java | 6 ++- .../validation/entities/SecondaryIndexTest.java | 55 ++++++++++++++++++++ 3 files changed, 61 insertions(+), 2 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/cassandra/blob/c2320c92/CHANGES.txt ---------------------------------------------------------------------- diff --git a/CHANGES.txt b/CHANGES.txt index f214200..8bb67e1 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,4 +1,6 @@ 3.0.1 + * Correctly preserve deletion info on updated rows when notifying indexers + of single-row deletions (CASSANDRA-10694) * Notify indexers of partition delete during cleanup (CASSANDRA-10685) * Keep the file open in trySkipCache (CASSANDRA-10669) * Updated trigger example (CASSANDRA-10257) http://git-wip-us.apache.org/repos/asf/cassandra/blob/c2320c92/src/java/org/apache/cassandra/index/SecondaryIndexManager.java ---------------------------------------------------------------------- diff --git a/src/java/org/apache/cassandra/index/SecondaryIndexManager.java b/src/java/org/apache/cassandra/index/SecondaryIndexManager.java index db53c25..df8e38d 100644 --- a/src/java/org/apache/cassandra/index/SecondaryIndexManager.java +++ b/src/java/org/apache/cassandra/index/SecondaryIndexManager.java @@ -273,7 +273,7 @@ public class SecondaryIndexManager implements IndexRegistry /** * Checks if the specified {@link ColumnFamilyStore} is the one secondary index. * - * @param cfs the name of the <code>ColumnFamilyStore</code> to check. + * @param cfName the name of the <code>ColumnFamilyStore</code> to check. * @return <code>true</code> if the specified <code>ColumnFamilyStore</code> is a secondary index, * <code>false</code> otherwise. */ @@ -309,7 +309,7 @@ public class SecondaryIndexManager implements IndexRegistry /** * Returns the index name * - * @param cfName the <code>ColumnFamilyStore</code> name + * @param cfs the <code>ColumnFamilyStore</code> * @return the index name */ public static String getIndexName(ColumnFamilyStore cfs) @@ -775,9 +775,11 @@ public class SecondaryIndexManager implements IndexRegistry final Row.Builder toRemove = BTreeRow.sortedBuilder(); toRemove.newRow(existing.clustering()); toRemove.addPrimaryKeyLivenessInfo(existing.primaryKeyLivenessInfo()); + toRemove.addRowDeletion(existing.deletion()); final Row.Builder toInsert = BTreeRow.sortedBuilder(); toInsert.newRow(updated.clustering()); toInsert.addPrimaryKeyLivenessInfo(updated.primaryKeyLivenessInfo()); + toInsert.addRowDeletion(updated.deletion()); // diff listener collates the columns to be added & removed from the indexes RowDiffListener diffListener = new RowDiffListener() { http://git-wip-us.apache.org/repos/asf/cassandra/blob/c2320c92/test/unit/org/apache/cassandra/cql3/validation/entities/SecondaryIndexTest.java ---------------------------------------------------------------------- diff --git a/test/unit/org/apache/cassandra/cql3/validation/entities/SecondaryIndexTest.java b/test/unit/org/apache/cassandra/cql3/validation/entities/SecondaryIndexTest.java index 9cba01a..225e197 100644 --- a/test/unit/org/apache/cassandra/cql3/validation/entities/SecondaryIndexTest.java +++ b/test/unit/org/apache/cassandra/cql3/validation/entities/SecondaryIndexTest.java @@ -20,6 +20,8 @@ package org.apache.cassandra.cql3.validation.entities; import java.nio.ByteBuffer; import java.util.*; +import org.apache.cassandra.db.DeletionTime; +import org.apache.cassandra.utils.Pair; import org.apache.commons.lang3.StringUtils; import org.junit.Test; @@ -785,6 +787,59 @@ public class SecondaryIndexTest extends CQLTester } @Test + public void testDeletions() throws Throwable + { + // Test for bugs like CASSANDRA-10694. These may not be readily visible with the built-in secondary index + // implementation because of the stale entry handling. + + String indexClassName = StubIndex.class.getName(); + createTable("CREATE TABLE %s (a int, b int, c int, PRIMARY KEY ((a), b))"); + createIndex(String.format("CREATE CUSTOM INDEX c_idx ON %%s(c) USING '%s'", indexClassName)); + + ColumnFamilyStore cfs = getCurrentColumnFamilyStore(); + CFMetaData cfm = cfs.metadata; + StubIndex index1 = (StubIndex) cfs.indexManager.getIndex(cfm.getIndexes() + .get("c_idx") + .orElseThrow(throwAssert("index not found"))); + + execute("INSERT INTO %s (a, b, c) VALUES (?, ?, ?) USING TIMESTAMP 1", 0, 0, 0); + assertEquals(1, index1.rowsInserted.size()); + + execute("DELETE FROM %s USING TIMESTAMP 2 WHERE a = ? AND b = ?", 0, 0); + assertEquals(1, index1.rowsUpdated.size()); + Pair<Row, Row> update = index1.rowsUpdated.get(0); + Row existingRow = update.left; + Row newRow = update.right; + + // check the existing row from the update call + assertTrue(existingRow.deletion().isLive()); + assertEquals(DeletionTime.LIVE, existingRow.deletion().time()); + assertEquals(1L, existingRow.primaryKeyLivenessInfo().timestamp()); + + // check the new row from the update call + assertFalse(newRow.deletion().isLive()); + assertEquals(2L, newRow.deletion().time().markedForDeleteAt()); + assertFalse(newRow.cells().iterator().hasNext()); + + // delete the same row again + execute("DELETE FROM %s USING TIMESTAMP 3 WHERE a = ? AND b = ?", 0, 0); + assertEquals(2, index1.rowsUpdated.size()); + update = index1.rowsUpdated.get(1); + existingRow = update.left; + newRow = update.right; + + // check the new row from the update call + assertFalse(existingRow.deletion().isLive()); + assertEquals(2L, existingRow.deletion().time().markedForDeleteAt()); + assertFalse(existingRow.cells().iterator().hasNext()); + + // check the new row from the update call + assertFalse(newRow.deletion().isLive()); + assertEquals(3L, newRow.deletion().time().markedForDeleteAt()); + assertFalse(newRow.cells().iterator().hasNext()); + } + + @Test public void testUpdatesToMemtableData() throws Throwable { // verify the contract specified by Index.Indexer::updateRow(oldRowData, newRowData),
