Alex Petrov created CASSANDRA-21292:
---------------------------------------

             Summary: Row re-inserted at the exact start of a range tombstone 
disappears after major compaction
                 Key: CASSANDRA-21292
                 URL: https://issues.apache.org/jira/browse/CASSANDRA-21292
             Project: Apache Cassandra
          Issue Type: Bug
            Reporter: Alex Petrov
            Assignee: Alex Petrov


{code}

package org.apache.cassandra.db;

import org.junit.Assert;
import org.junit.Test;

import org.apache.cassandra.config.DatabaseDescriptor;
import org.apache.cassandra.cql3.CQLTester;
import org.apache.cassandra.cql3.UntypedResultSet;

/**
* Repro for a bug where a row re-inserted at the exact start of a range 
tombstone
* disappears after major compaction.
*
* Reproduces with LeveledCompactionStrategy and gc_grace_seconds=86400 (the 
default).
*
*   1. Insert NUM_ROWS rows (ck = "row000000".."rowNNNNNN") into SSTable #1.
*   2. Delete  ck >= TOMBSTONE_CK  (open-ended; sorts after all "row*" keys).
*   3. Re-insert TOMBSTONE_CK with a timestamp newer than the delete.
*   4. Force major compaction.
*   5. Range-scan ... AND ck <= TOMBSTONE_CK -- the re-inserted row disappears.
*/
public class RangeTombstoneBoundaryReproTest extends CQLTester
{
   // Padding makes each row large enough that NUM_ROWS rows span multiple 1 KiB
   // column-index blocks.  With ~300-byte rows and 1 KiB blocks, ~3 rows/block;
   // NUM_ROWS = 9 is the minimum: 8 rows pass cleanly.
   private static final String VALUE_PAD = "x".repeat(270);
   private static final int    NUM_ROWS  = 9;

   // Tombstone boundary: sorts after every "row*" key.
   private static final String TOMBSTONE_CK = "z";

   @Test
   public void testReinsertedRowAtTombstoneBoundaryMissingAfterCompaction() 
throws Throwable
   {
       int savedIdx   = DatabaseDescriptor.getColumnIndexSizeInKiB();
       int savedCache = DatabaseDescriptor.getColumnIndexCacheSizeInKiB();
       DatabaseDescriptor.setColumnIndexSizeInKiB(1);
       DatabaseDescriptor.setColumnIndexCacheSize(1);
       try
       {
           createTable(
               "CREATE TABLE %s (" +
               "  pk ascii, ck ascii, v text," +
               "  PRIMARY KEY (pk, ck)" +
               ") WITH" +
               " compaction = {" +
               "        'class': 'LeveledCompactionStrategy'," +
               "        'enabled': false" +
               "      }"
           );

           final String PK = "p";

           // SSTable 1: bulk insert
           for (int i = 0; i < NUM_ROWS; i++)
               execute("INSERT INTO %s (pk, ck, v) VALUES (?, ?, ?) USING 
TIMESTAMP ?",
                       PK, String.format("row%06d", i), VALUE_PAD + i, (long) 
i);
           flush();

           // SSTable 2: open-ended tombstone starting at TOMBSTONE_CK
           execute("DELETE FROM %s USING TIMESTAMP 100 WHERE pk = ? AND ck >= 
?",
                   PK, TOMBSTONE_CK);
           flush();

           // SSTable 3: re-insert at tombstone boundary with newer timestamp
           execute("INSERT INTO %s (pk, ck, v) VALUES (?, ?, ?) USING TIMESTAMP 
200",
                   PK, TOMBSTONE_CK, "reinserted");
           flush();

           // Sanity: row must exist before compaction
           UntypedResultSet before = execute(
               "SELECT ck FROM %s WHERE pk = ? AND ck >= ? AND ck <= ?",
               PK, "s", TOMBSTONE_CK);
           Assert.assertEquals("Row must exist before compaction", 1, 
before.size());

           getCurrentColumnFamilyStore().forceMajorCompaction(); // Comment / 
uncomment this line to make the test pass

           // BUG: re-inserted row disappears after compaction
           UntypedResultSet after = execute(
               "SELECT ck FROM %s WHERE pk = ? AND ck >= ? AND ck <= ?",
               PK, "s", TOMBSTONE_CK);
           Assert.assertEquals(
               "Re-inserted row at tombstone boundary must survive compaction",
               1, after.size());
       }
       finally
       {
           DatabaseDescriptor.setColumnIndexSizeInKiB(savedIdx);
           DatabaseDescriptor.setColumnIndexCacheSize(savedCache);
       }
   }
}
{code}



--
This message was sent by Atlassian Jira
(v8.20.10#820010)

---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to