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);