[
https://issues.apache.org/jira/browse/CASSANDRA-21307?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
]
Francisco Guerrero updated CASSANDRA-21307:
-------------------------------------------
Resolution: Resolved
Status: Resolved (was: Triage Needed)
Already resolved by CASSANDRA-21255
> Lower bound [SSTABLE_UPPER_BOUND(row000063)] is bigger than first returned
> value
> --------------------------------------------------------------------------------
>
> Key: CASSANDRA-21307
> URL: https://issues.apache.org/jira/browse/CASSANDRA-21307
> Project: Apache Cassandra
> Issue Type: Bug
> Reporter: Alex Petrov
> Assignee: Alex Petrov
> Priority: Normal
>
> {code}
> package org.apache.cassandra.db;
> import org.junit.Before;
> import org.junit.Test;
> import org.apache.cassandra.config.DatabaseDescriptor;
> import org.apache.cassandra.cql3.CQLTester;
> /**
> * Reproduces a bug in SSTableCursorWriter.addIndexBlock() where the sentinel
> check
> * clusteringLength() == 0 incorrectly matches an INCL_END_BOUND (TOP) marker
> with 0 components.
> *
> * When the last item in a column index block is TOP (INCL_END_BOUND with 0
> components),
> * addIndexBlock() mistakes it for "no IndexInfo#lastName set" (the sentinel
> after resetClustering() also has
> * clusteringLength==0 but kind==CLUSTERING, while TOP has
> kind==INCL_END_BOUND). This causes the
> * block's IndexInfo#lastName to be set to IndexInfo#firstName instead of TOP.
> *
> * When a reversed (DESC) scan reads the resulting SSTable,
> getLowerBoundPrefixFromCache()
> * returns SSTABLE_UPPER_BOUND(IndexInfo#firstName) as the lower bound, but
> the first item
> * actually returned is TOP (INCL_END_BOUND with 0 components). In reversed
> order,
> * TOP > any specific bound, so the assertion
> * "Lower bound is bigger than first returned value" fires.
> *
> * The fix: change the sentinel in addIndexBlock() from
> * clusteringLength() == 0
> * to
> * clusteringKind() == CLUSTERING && clusteringLength() == 0
> *
> * Trigger conditions (all must hold):
> * 1. The partition has enough data for at least 3 column index blocks
> (rowIndexEntriesOffsets.size() > 1)
> * 2. The range tombstone extends to the top of the partition (INCL_END_BOUND
> with 0 components = TOP)
> * 3. TOP lands in the LAST block (not as the sole item in its own block)
> * 4. Two SSTables must be compacted (rows in one SSTable, tombstone in
> another)
> */
> public class RangeTombstoneReproTest extends CQLTester
> {
> @Before
> public void setUp()
> {
> DatabaseDescriptor.setColumnIndexSizeInKiB(1);
> }
> @Test
> public void testDescScanAfterCompactionWithOpenEndedRangeTombstone()
> throws Throwable
> {
> // Need enough rows to produce >= 2 finalized 1 KiB column index
> blocks.
> // Each row ~32 bytes → 32 rows per block → 64 rows → 2 complete
> blocks + partial last block with tombstone.
> createTable("CREATE TABLE %s (pk text, ck text, v text, PRIMARY KEY
> (pk, ck))");
> ColumnFamilyStore cfs = getCurrentColumnFamilyStore();
> cfs.disableAutoCompaction();
> String pk = "pk0";
> for (int i = 0; i < 64; i++)
> {
> String ck = String.format("row%06d", i);
> execute("INSERT INTO %s (pk, ck, v) VALUES (?, ?, ?)", pk, ck,
> "value_" + ck);
> }
> flush();
> // Open-ended tombstone: INCL_END_BOUND() = TOP (0 components) lands
> in the last block.
> // Must be in a separate SSTable; single-SSTable compaction does not
> trigger the bug.
> execute("DELETE FROM %s WHERE pk = ? AND ck >= 'z'", pk);
> flush();
> // Compact the 2 SSTables; writes buggy RowIndexEntry (wrong
> IndexInfo#lastName in last block)
> cfs.forceMajorCompaction();
> // DESC scan reads the SSTable, computes lower bound from the buggy
> RowIndexEntry,
> // and asserts: "Lower bound [SSTABLE_UPPER_BOUND(row000063)] is
> bigger than first returned value
> // [Marker INCL_END_BOUND()]"
> execute("SELECT * FROM %s WHERE pk = ? ORDER BY ck DESC", pk);
> }
> }
> {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]