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 2011/02/05 06:13:50 UTC

svn commit: r1067391 - in /cassandra/trunk: CHANGES.txt interface/cassandra.thrift src/java/org/apache/cassandra/db/CounterColumn.java test/unit/org/apache/cassandra/db/CounterColumnTest.java

Author: jbellis
Date: Sat Feb  5 05:13:50 2011
New Revision: 1067391

URL: http://svn.apache.org/viewvc?rev=1067391&view=rev
Log:
add delete support for counters
patch by Kelvin Kakugawa; reviewed by slebresne for CASSANDRA-2101

Modified:
    cassandra/trunk/CHANGES.txt
    cassandra/trunk/interface/cassandra.thrift
    cassandra/trunk/src/java/org/apache/cassandra/db/CounterColumn.java
    cassandra/trunk/test/unit/org/apache/cassandra/db/CounterColumnTest.java

Modified: cassandra/trunk/CHANGES.txt
URL: http://svn.apache.org/viewvc/cassandra/trunk/CHANGES.txt?rev=1067391&r1=1067390&r2=1067391&view=diff
==============================================================================
--- cassandra/trunk/CHANGES.txt (original)
+++ cassandra/trunk/CHANGES.txt Sat Feb  5 05:13:50 2011
@@ -1,7 +1,7 @@
 0.8-dev
  * avoid double RowMutation serialization on write path (CASSANDRA-1800)
  * adds support for columns that act as incr/decr counters 
-   (CASSANDRA-1072, 1937, 1944, 1936)
+   (CASSANDRA-1072, 1937, 1944, 1936, 2101)
  * make NetworkTopologyStrategy the default (CASSANDRA-1960)
  * configurable internode encryption (CASSANDRA-1567)
  * human readable column names in sstable2json output (CASSANDRA-1933)

Modified: cassandra/trunk/interface/cassandra.thrift
URL: http://svn.apache.org/viewvc/cassandra/trunk/interface/cassandra.thrift?rev=1067391&r1=1067390&r2=1067391&view=diff
==============================================================================
--- cassandra/trunk/interface/cassandra.thrift (original)
+++ cassandra/trunk/interface/cassandra.thrift Sat Feb  5 05:13:50 2011
@@ -498,6 +498,11 @@ service Cassandra {
     Remove data from the row specified by key at the granularity specified by column_path, and the given timestamp. Note
     that all the values in column_path besides column_path.column_family are truly optional: you can remove the entire
     row by just specifying the ColumnFamily, or you can remove a SuperColumn or a single Column by specifying those levels too.
+
+    Note that counters have limited support for deletes: if you remove
+    a counter, you must wait to issue any following update until the
+    delete has reached all the nodes and all of them have been fully
+    compacted.
    */
   void remove(1:required binary key,
               2:required ColumnPath column_path,

Modified: cassandra/trunk/src/java/org/apache/cassandra/db/CounterColumn.java
URL: http://svn.apache.org/viewvc/cassandra/trunk/src/java/org/apache/cassandra/db/CounterColumn.java?rev=1067391&r1=1067390&r2=1067391&view=diff
==============================================================================
--- cassandra/trunk/src/java/org/apache/cassandra/db/CounterColumn.java (original)
+++ cassandra/trunk/src/java/org/apache/cassandra/db/CounterColumn.java Sat Feb  5 05:13:50 2011
@@ -110,28 +110,7 @@ public class CounterColumn extends Colum
     {
         assert (column instanceof CounterColumn) || (column instanceof DeletedColumn) : "Wrong class type.";
 
-        if (isMarkedForDelete())
-        {
-            if (column.isMarkedForDelete()) // tombstone + tombstone: keep later tombstone
-            {
-                return timestamp() > column.timestamp() ? this : column;
-            }
-            else // tombstone + live: track last tombstone
-            {
-                if (timestamp() > column.timestamp()) // tombstone > live
-                {
-                    return this;
-                }
-                // tombstone <= live last delete
-                if (timestamp() <= ((CounterColumn)column).timestampOfLastDelete())
-                {
-                    return column;
-                }
-                // tombstone > live last delete
-                return new CounterColumn(column.name(), column.value(), column.timestamp(), timestamp());
-            }
-        }
-        else if (column.isMarkedForDelete()) // live + tombstone: track last tombstone
+        if (column.isMarkedForDelete()) // live + tombstone: track last tombstone
         {
             if (timestamp() < column.timestamp()) // live < tombstone
             {
@@ -145,6 +124,12 @@ public class CounterColumn extends Colum
             // live last delete < tombstone
             return new CounterColumn(name(), value(), timestamp(), column.timestamp());
         }
+        // live < live last delete
+        if (timestamp() < ((CounterColumn)column).timestampOfLastDelete())
+            return column;
+        // live last delete > live
+        if (timestampOfLastDelete() > column.timestamp())
+            return this;
         // live + live: merge clocks; update value
         return new CounterColumn(
             name(),

Modified: cassandra/trunk/test/unit/org/apache/cassandra/db/CounterColumnTest.java
URL: http://svn.apache.org/viewvc/cassandra/trunk/test/unit/org/apache/cassandra/db/CounterColumnTest.java?rev=1067391&r1=1067390&r2=1067391&view=diff
==============================================================================
--- cassandra/trunk/test/unit/org/apache/cassandra/db/CounterColumnTest.java (original)
+++ cassandra/trunk/test/unit/org/apache/cassandra/db/CounterColumnTest.java Sat Feb  5 05:13:50 2011
@@ -34,8 +34,7 @@ import org.junit.Test;
 
 import org.apache.cassandra.Util;
 import org.apache.cassandra.db.context.CounterContext;
-import org.apache.cassandra.db.marshal.AbstractCommutativeType;
-import org.apache.cassandra.db.marshal.CounterColumnType;
+import org.apache.cassandra.db.marshal.*;
 import org.apache.cassandra.io.util.DataOutputBuffer;
 import org.apache.cassandra.utils.ByteBufferUtil;
 import org.apache.cassandra.utils.FBUtilities;
@@ -64,7 +63,11 @@ public class CounterColumnTest
     {
         AbstractCommutativeType type = CounterColumnType.instance;
         long delta = 3L;
-        CounterColumn column = new CounterColumn(ByteBufferUtil.bytes("x"), delta, 1L);
+        CounterUpdateColumn cuc = (CounterUpdateColumn)type.createColumn(
+            ByteBufferUtil.bytes("x"),
+            ByteBufferUtil.bytes(delta),
+            1L);
+        CounterColumn column = cuc.asCounterColumn();
 
         assert delta == column.total();
         assert Arrays.equals(FBUtilities.getLocalAddress().getAddress(), ArrayUtils.subarray(column.value().array(), 0, idLength));
@@ -79,12 +82,14 @@ public class CounterColumnTest
         IColumn right;
         IColumn reconciled;
 
+        ByteBuffer context;
+
         // tombstone + tombstone
         left  = new DeletedColumn(ByteBufferUtil.bytes("x"), 1, 1L);
         right = new DeletedColumn(ByteBufferUtil.bytes("x"), 2, 2L);
 
-        assert left.reconcile(right).timestamp() == right.timestamp();
-        assert right.reconcile(left).timestamp() == right.timestamp();
+        assert left.reconcile(right).getMarkedForDeleteAt() == right.getMarkedForDeleteAt();
+        assert right.reconcile(left).getMarkedForDeleteAt() == right.getMarkedForDeleteAt();
 
         // tombstone > live
         left  = new DeletedColumn(ByteBufferUtil.bytes("x"), 1, 2L);
@@ -112,7 +117,7 @@ public class CounterColumnTest
         assert reconciled.name() == right.name();
         assert reconciled.value() == right.value();
         assert reconciled.timestamp() == right.timestamp();
-        assert ((CounterColumn)reconciled).timestampOfLastDelete() == left.timestamp();
+        assert ((CounterColumn)reconciled).timestampOfLastDelete() == left.getMarkedForDeleteAt();
 
         // live < tombstone
         left  = new CounterColumn(ByteBufferUtil.bytes("x"), 0L, 1L);
@@ -140,36 +145,46 @@ public class CounterColumnTest
         assert reconciled.name() == left.name();
         assert reconciled.value() == left.value();
         assert reconciled.timestamp() == left.timestamp();
-        assert ((CounterColumn)reconciled).timestampOfLastDelete() == right.timestamp();
+        assert ((CounterColumn)reconciled).timestampOfLastDelete() == right.getMarkedForDeleteAt();
 
-        // live + live
+        // live < live last delete
+        left  = new CounterColumn(ByteBufferUtil.bytes("x"), cc.create(FBUtilities.toByteArray(1), 2L, 3L), 1L, Long.MIN_VALUE);
+        right = new CounterColumn(ByteBufferUtil.bytes("x"), cc.create(FBUtilities.toByteArray(1), 1L, 1L), 4L, 3L);
 
-        left = new CounterColumn(ByteBufferUtil.bytes("x"), cc.create(FBUtilities.toByteArray(1), 1L, 1L), 4L);
-        right = new CounterColumn(ByteBufferUtil.bytes("x"), cc.create(FBUtilities.toByteArray(1), 2L, 3L), 1L);
+        assert left.reconcile(right) == right;
+
+        // live last delete > live
+        left  = new CounterColumn(ByteBufferUtil.bytes("x"), cc.create(FBUtilities.toByteArray(1), 2L, 3L), 6L, 5L);
+        right = new CounterColumn(ByteBufferUtil.bytes("x"), cc.create(FBUtilities.toByteArray(1), 1L, 1L), 4L, 3L);
+
+        assert left.reconcile(right) == left;
+
+        // live + live
+        left  = new CounterColumn(ByteBufferUtil.bytes("x"), cc.create(FBUtilities.toByteArray(1), 1L, 1L), 4L, Long.MIN_VALUE);
+        right = new CounterColumn(ByteBufferUtil.bytes("x"), cc.create(FBUtilities.toByteArray(1), 2L, 3L), 1L, Long.MIN_VALUE);
 
         reconciled = left.reconcile(right);
         assert reconciled.name().equals(left.name());
         assert ((CounterColumn)reconciled).total() == 3L;
         assert reconciled.timestamp() == 4L;
 
-        left = reconciled;
-        right = new CounterColumn(ByteBufferUtil.bytes("x"), cc.create(FBUtilities.toByteArray(2), 1L, 5L), 2L);
+        left  = reconciled;
+        right = new CounterColumn(ByteBufferUtil.bytes("x"), cc.create(FBUtilities.toByteArray(2), 1L, 5L), 2L, Long.MIN_VALUE);
 
         reconciled = left.reconcile(right);
-
         assert reconciled.name().equals(left.name());
         assert ((CounterColumn)reconciled).total() == 8L;
         assert reconciled.timestamp() == 4L;
 
-        left = reconciled;
-        right = new CounterColumn(ByteBufferUtil.bytes("x"), cc.create(FBUtilities.toByteArray(2), 2L, 2L), 6L);
+        left  = reconciled;
+        right = new CounterColumn(ByteBufferUtil.bytes("x"), cc.create(FBUtilities.toByteArray(2), 2L, 2L), 6L, Long.MIN_VALUE);
 
         reconciled = left.reconcile(right);
         assert reconciled.name().equals(left.name());
         assert ((CounterColumn)reconciled).total() == 5L;
         assert reconciled.timestamp() == 6L;
 
-        ByteBuffer context = reconciled.value();
+        context = reconciled.value();
         assert 2 * stepLength == context.remaining();
 
         assert  1 == context.getInt(0*stepLength);