From 93012e43ea03411456c20e7cec1ede73ff46b7d2 Mon Sep 17 00:00:00 2001 From: Fransisco Fernandez Castano Date: Sun, 22 Apr 2018 13:08:26 +0200 Subject: [PATCH] Ignore empty Counter cells on digest calculation. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit patch by Francisco Fernández Castaño; reviewed by Sylvain Lebresne for CASSANDRA-14167 --- CHANGES.txt | 1 + .../cassandra/db/context/CounterContext.java | 3 +++ .../apache/cassandra/db/CounterCellTest.java | 23 +++++++++++++++++++ 3 files changed, 27 insertions(+) diff --git a/CHANGES.txt b/CHANGES.txt index ee957182bd..00944dc1ff 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,4 +1,5 @@ 3.0.17 + * Fix potential IndexOutOfBoundsException with counters (CASSANDRA-14167) * Restore resumable hints delivery, backport CASSANDRA-11960 (CASSANDRA-14419) * Always close RT markers returned by ReadCommand#executeLocally() (CASSANDRA-14515) * Reverse order queries with range tombstones can cause data loss (CASSANDRA-14513) diff --git a/src/java/org/apache/cassandra/db/context/CounterContext.java b/src/java/org/apache/cassandra/db/context/CounterContext.java index 29e5cfcf7b..b40246455d 100644 --- a/src/java/org/apache/cassandra/db/context/CounterContext.java +++ b/src/java/org/apache/cassandra/db/context/CounterContext.java @@ -692,6 +692,9 @@ public class CounterContext */ public void updateDigest(MessageDigest message, ByteBuffer context) { + // context can be empty due to the optimization from CASSANDRA-10657 + if (!context.hasRemaining()) + return; ByteBuffer dup = context.duplicate(); dup.position(context.position() + headerLength(context)); message.update(dup); diff --git a/test/unit/org/apache/cassandra/db/CounterCellTest.java b/test/unit/org/apache/cassandra/db/CounterCellTest.java index a8ddfccc8f..8859fc671f 100644 --- a/test/unit/org/apache/cassandra/db/CounterCellTest.java +++ b/test/unit/org/apache/cassandra/db/CounterCellTest.java @@ -29,13 +29,16 @@ import org.junit.Test; import org.apache.cassandra.SchemaLoader; import org.apache.cassandra.config.ColumnDefinition; +import org.apache.cassandra.db.rows.BTreeRow; import org.apache.cassandra.db.rows.BufferCell; import org.apache.cassandra.db.rows.Cell; import org.apache.cassandra.db.rows.CellPath; import org.apache.cassandra.db.rows.Cells; import org.apache.cassandra.db.context.CounterContext; +import org.apache.cassandra.db.rows.Row; import org.apache.cassandra.exceptions.ConfigurationException; import org.apache.cassandra.schema.KeyspaceParams; +import org.apache.cassandra.serializers.AsciiSerializer; import org.apache.cassandra.utils.*; import static org.junit.Assert.*; @@ -281,4 +284,24 @@ public class CounterCellTest assert Arrays.equals(digest1.digest(), digest2.digest()); } + + @Test + public void testDigestWithEmptyCells() throws Exception + { + // For DB-1881 + ColumnFamilyStore cfs = Keyspace.open(KEYSPACE1).getColumnFamilyStore(COUNTER1); + + ColumnDefinition emptyColDef = cfs.metadata.getColumnDefinition(ByteBufferUtil.bytes("val2")); + BufferCell emptyCell = BufferCell.live(emptyColDef, 0, ByteBuffer.allocate(0)); + + Row.Builder builder = BTreeRow.unsortedBuilder(0); + builder.newRow(Clustering.make(AsciiSerializer.instance.serialize("test"))); + builder.addCell(emptyCell); + Row row = builder.build(); + + MessageDigest digest = MessageDigest.getInstance("md5"); + row.digest(digest); + assertNotNull(digest.digest()); + } + }