You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cassandra.apache.org by jb...@apache.org on 2012/08/30 16:08:03 UTC

[2/2] redesign KEYS indexes to avoid read-before-write patch by Sam Tunnicliffe, jbellis, and Philip Jenvey for CASSANDRA-2897

http://git-wip-us.apache.org/repos/asf/cassandra/blob/8a1b93d7/test/unit/org/apache/cassandra/db/ColumnFamilyStoreTest.java
----------------------------------------------------------------------
diff --git a/test/unit/org/apache/cassandra/db/ColumnFamilyStoreTest.java b/test/unit/org/apache/cassandra/db/ColumnFamilyStoreTest.java
index 8fd5807..090aad3 100644
--- a/test/unit/org/apache/cassandra/db/ColumnFamilyStoreTest.java
+++ b/test/unit/org/apache/cassandra/db/ColumnFamilyStoreTest.java
@@ -60,6 +60,7 @@ import org.apache.cassandra.config.ConfigurationException;
 import org.apache.cassandra.db.columniterator.IdentityQueryFilter;
 import org.apache.cassandra.db.filter.*;
 import org.apache.cassandra.db.index.SecondaryIndex;
+import org.apache.cassandra.db.marshal.CompositeType;
 import org.apache.cassandra.db.marshal.LexicalUUIDType;
 import org.apache.cassandra.db.marshal.LongType;
 import org.apache.cassandra.dht.Bounds;
@@ -424,6 +425,143 @@ public class ColumnFamilyStoreTest extends SchemaLoader
         assert "k1".equals( key );
 
     }
+    
+    @Test
+    public void testDeleteOfInconsistentValuesInKeysIndex() throws Exception
+    {
+        String keySpace = "Keyspace2";
+        String cfName = "Indexed1";
+
+        Table table = Table.open(keySpace);
+        ColumnFamilyStore cfs = table.getColumnFamilyStore(cfName);
+        cfs.truncate().get();
+
+        ByteBuffer rowKey = ByteBufferUtil.bytes("k1");
+        ByteBuffer colName = ByteBufferUtil.bytes("birthdate"); 
+        ByteBuffer val1 = ByteBufferUtil.bytes(1L);
+        ByteBuffer val2 = ByteBufferUtil.bytes(2L);
+
+        // create a row and update the "birthdate" value, test that the index query fetches this version
+        RowMutation rm;
+        rm = new RowMutation(keySpace, rowKey);
+        rm.add(new QueryPath(cfName, null, colName), val1, 0);
+        rm.apply();
+        IndexExpression expr = new IndexExpression(colName, IndexOperator.EQ, val1);
+        List<IndexExpression> clause = Arrays.asList(expr);
+        IFilter filter = new IdentityQueryFilter();
+        Range<RowPosition> range = Util.range("", "");
+        List<Row> rows = table.getColumnFamilyStore(cfName).search(clause, range, 100, filter);
+        assertEquals(1, rows.size());
+
+        // force a flush, so our index isn't being read from a memtable
+        table.getColumnFamilyStore(cfName).forceBlockingFlush();
+
+        // now apply another update, but force the index update to be skipped
+        rm = new RowMutation(keySpace, rowKey);
+        rm.add(new QueryPath(cfName, null, colName), val2, 1);
+        table.apply(rm, true, false);
+
+        // Now searching the index for either the old or new value should return 0 rows
+        // because the new value was not indexed and the old value should be ignored 
+        // (and in fact purged from the index cf).
+        // first check for the old value
+        rows = table.getColumnFamilyStore(cfName).search(clause, range, 100, filter);
+        assertEquals(0, rows.size());
+        // now check for the updated value
+        expr = new IndexExpression(colName, IndexOperator.EQ, val2);
+        clause = Arrays.asList(expr);
+        filter = new IdentityQueryFilter();
+        range = Util.range("", "");
+        rows = table.getColumnFamilyStore(cfName).search(clause, range, 100, filter);
+        assertEquals(0, rows.size());
+
+        // now, reset back to the original value, still skipping the index update, to
+        // make sure the value was expunged from the index when it was discovered to be inconsistent
+        rm = new RowMutation(keySpace, rowKey);
+        rm.add(new QueryPath(cfName, null, colName), ByteBufferUtil.bytes(1L), 3);
+        table.apply(rm, true, false);
+
+        expr = new IndexExpression(colName, IndexOperator.EQ, ByteBufferUtil.bytes(1L));
+        clause = Arrays.asList(expr);
+        filter = new IdentityQueryFilter();
+        range = Util.range("", "");
+        rows = table.getColumnFamilyStore(cfName).search(clause, range, 100, filter);
+        assertEquals(0, rows.size());
+    }
+
+    @Test
+    public void testDeleteOfInconsistentValuesFromCompositeIndex() throws Exception
+    {
+        String keySpace = "Keyspace2";
+        String cfName = "Indexed2";
+
+        Table table = Table.open(keySpace);
+        ColumnFamilyStore cfs = table.getColumnFamilyStore(cfName);
+        cfs.truncate().get();
+
+        ByteBuffer rowKey = ByteBufferUtil.bytes("k1");
+        ByteBuffer clusterKey = ByteBufferUtil.bytes("ck1");
+        ByteBuffer colName = ByteBufferUtil.bytes("col1"); 
+        CompositeType baseComparator = (CompositeType)cfs.getComparator();
+        CompositeType.Builder builder = baseComparator.builder();
+        builder.add(clusterKey);
+        builder.add(colName);
+        ByteBuffer compositeName = builder.build();
+
+        ByteBuffer val1 = ByteBufferUtil.bytes("v1");
+        ByteBuffer val2 = ByteBufferUtil.bytes("v2");
+
+        // create a row and update the author value
+        RowMutation rm;
+        rm = new RowMutation(keySpace, rowKey);
+        rm.add(new QueryPath(cfName, null , compositeName), val1, 0);
+        rm.apply();
+
+        // test that the index query fetches this version
+        IndexExpression expr = new IndexExpression(colName, IndexOperator.EQ, val1);
+        List<IndexExpression> clause = Arrays.asList(expr);
+        IFilter filter = new IdentityQueryFilter();
+        Range<RowPosition> range = Util.range("", "");
+        List<Row> rows = table.getColumnFamilyStore(cfName).search(clause, range, 100, filter);
+        assertEquals(1, rows.size());
+
+        // force a flush and retry the query, so our index isn't being read from a memtable
+        table.getColumnFamilyStore(cfName).forceBlockingFlush();
+        rows = table.getColumnFamilyStore(cfName).search(clause, range, 100, filter);
+        assertEquals(1, rows.size());
+
+        // now apply another update, but force the index update to be skipped
+        rm = new RowMutation(keySpace, rowKey);
+        rm.add(new QueryPath(cfName, null, compositeName), val2, 1);
+        table.apply(rm, true, false);
+
+        // Now searching the index for either the old or new value should return 0 rows
+        // because the new value was not indexed and the old value should be ignored 
+        // (and in fact purged from the index cf).
+        // first check for the old value
+        rows = table.getColumnFamilyStore(cfName).search(clause, range, 100, filter);
+        assertEquals(0, rows.size());
+        // now check for the updated value
+        expr = new IndexExpression(colName, IndexOperator.EQ, val2);
+        clause = Arrays.asList(expr);
+        filter = new IdentityQueryFilter();
+        range = Util.range("", "");
+        rows = table.getColumnFamilyStore(cfName).search(clause, range, 100, filter);
+        assertEquals(0, rows.size());
+
+        // now, reset back to the original value, still skipping the index update, to
+        // make sure the value was expunged from the index when it was discovered to be inconsistent
+        rm = new RowMutation(keySpace, rowKey);
+        rm.add(new QueryPath(cfName, null , compositeName), val1, 2);
+        table.apply(rm, true, false);
+
+        expr = new IndexExpression(colName, IndexOperator.EQ, val1);
+        clause = Arrays.asList(expr);
+        filter = new IdentityQueryFilter();
+        range = Util.range("", "");
+        rows = table.getColumnFamilyStore(cfName).search(clause, range, 100, filter);
+        assertEquals(0, rows.size());
+    }
 
     // See CASSANDRA-2628
     @Test

http://git-wip-us.apache.org/repos/asf/cassandra/blob/8a1b93d7/test/unit/org/apache/cassandra/db/SecondaryIndexColumnSizeTest.java
----------------------------------------------------------------------
diff --git a/test/unit/org/apache/cassandra/db/SecondaryIndexColumnSizeTest.java b/test/unit/org/apache/cassandra/db/SecondaryIndexColumnSizeTest.java
index cc52f3c..00bd779 100644
--- a/test/unit/org/apache/cassandra/db/SecondaryIndexColumnSizeTest.java
+++ b/test/unit/org/apache/cassandra/db/SecondaryIndexColumnSizeTest.java
@@ -18,7 +18,6 @@
 */
 package org.apache.cassandra.db;
 
-import java.io.IOException;
 import java.nio.ByteBuffer;
 import java.util.List;
 import java.util.Set;
@@ -75,11 +74,6 @@ public class SecondaryIndexColumnSizeTest
     private class MockRowIndex extends PerRowSecondaryIndex
     {
         @Override
-        public void applyIndexUpdates(ByteBuffer rowKey, ColumnFamily cf, SortedSet<ByteBuffer> mutatedIndexedColumns, ColumnFamily oldIndexedColumns)
-        {
-        }
-
-        @Override
         public void init()
         {
         }
@@ -133,11 +127,17 @@ public class SecondaryIndexColumnSizeTest
         {
         }
 
-        @Override
-        public void deleteFromIndex(DecoratedKey key, List<IColumn> indexedColumnsInRow)
+        public void index(ByteBuffer rowKey, ColumnFamily cf)
         {
         }
 
+        public void index(ByteBuffer rowKey)
+        {
+        }
+
+        public void delete(DecoratedKey key)
+        {
+        }
     }
 
 
@@ -198,17 +198,17 @@ public class SecondaryIndexColumnSizeTest
         }
 
         @Override
-        public void deleteColumn(DecoratedKey valueKey, ByteBuffer rowKey, IColumn col)
+        public void delete(ByteBuffer rowKey, IColumn col)
         {
         }
 
         @Override
-        public void insertColumn(DecoratedKey valueKey, ByteBuffer rowKey, IColumn col)
+        public void insert(ByteBuffer rowKey, IColumn col)
         {
         }
 
         @Override
-        public void updateColumn(DecoratedKey valueKey, ByteBuffer rowKey, IColumn col)
+        public void update(ByteBuffer rowKey, IColumn col)
         {
         }
     }