This is an automated email from the ASF dual-hosted git repository. asf-gitbox-commits pushed a commit to branch trunk in repository https://gitbox.apache.org/repos/asf/cassandra.git
commit 78817fa41b32edaff85f5fe4ff6663503f540dd8 Merge: a621de992a 60b833a8f4 Author: Caleb Rackliffe <[email protected]> AuthorDate: Mon Aug 17 15:09:41 2026 -0500 Merge branch 'cassandra-6.0' into trunk * cassandra-6.0: Make runWithCompactionsDisabled return non-null on success CHANGES.txt | 1 + .../org/apache/cassandra/db/ColumnFamilyStore.java | 84 +++++--- .../cassandra/db/compaction/CompactionManager.java | 5 +- .../cassandra/exceptions/RequestFailure.java | 5 + .../cassandra/exceptions/RequestFailureReason.java | 2 + src/java/org/apache/cassandra/net/InboundSink.java | 4 +- .../apache/cassandra/service/StorageService.java | 2 + .../apache/cassandra/db/TruncateBlockingTest.java | 226 +++++++++++++++++++++ .../db/compaction/CancelCompactionsTest.java | 112 ++++++++++ .../exceptions/RequestFailureReasonTest.java | 1 + 10 files changed, 415 insertions(+), 27 deletions(-) diff --cc CHANGES.txt index 3114310058,dfa56b6881..9d19ee6e61 --- a/CHANGES.txt +++ b/CHANGES.txt @@@ -78,34 -83,6 +78,35 @@@ Merged from 6.0 * Differentiate between legitimate cases where the first entry is the same as the last entry and empty bounds in SSTableCursorWriter#addIndexBlock() (CASSANDRA-21255) * Introduce minimum_threshold for data resurrection startup check (CASSANDRA-21293) * Synchronously publish changes to local gossip state following metadata updates (CASSANDRA-21239) +Merged from 5.0: + * Avoid rebuilding per-SSTable SAI components unless missing or corrupted (CASSANDRA-21515) + * Propagate trickle_fsync settings to compressed SSTable writers (CASSANDRA-21487) + * Allow setCompressedReadAheadBufferSizeInKb(0) to disable read-ahead buffer (CASSANDRA-21522) + * Fix ThreadLocalReadAheadBuffer#fill() to throw a CorruptBlockException if chunk metadata and file size are out of sync (CASSANDRA-21519) + * Support Python 3.12 and 3.13 in cqlsh (CASSANDRA-20997) + * Make synchronization on VectorMemoryIndex inserts more granular (CASSANDRA-21160) + * Fix RequestFailureReason serializer and nits in a few others (CASSANDRA-21437) + * Remove golang dependency in gen-doc and replace with python implementation (CASSANDRA-21432) + * Use estimated compressed size for tables to check if there is enough free space for a compaction (CASSANDRA-21245) + * Fix failing select on system_views.settings for non-string keys (CASSANDRA-21348) +Merged from 4.0: ++ * Make runWithCompactionsDisabled return non-null on success (CASSANDRA-21527) + * Validate authz before performing role check in LIST ROLES/PERMISSIONS (CASSANDRA-21560) + * Add validation to uncompressed length during decompression (CASSANDRA-21567) + * Fix regression in PasswordObfuscator for dollar-quoted passwords (CASSANDRA-21559) + * Do not make DNS lookup when querying system_views.clients for hostname column by removing it (CASSANDRA-21539) + * Fix memtable on-heap accounting drift in BTree.update and BTreeRow.merge (CASSANDRA-21472) + * Bound declared value length against readable bytes in CBUtil (CASSANDRA-21521) + * Verify extension type before initializing reflectively-loaded classes (CASSANDRA-21525) + * Rename conflicting nodetool import --copy-data short option from -p to -cd (CASSANDRA-20214) + * Fix PasswordObfuscator failing to obfuscate certain passwords (CASSANDRA-21113) + * Fix negative memtable allocator ownership when an update is shadowed by an existing row deletion (CASSANDRA-21469) + * Consider first token of SSTable when calculating SSTable intersection in LeveledScanner (CASSANDRA-21369) + * Remove inFlightEcho entry on ECHO_REQ failure (CASSANDRA-21428) + * Validate snapshot names (CASSANDRA-21389) + + +6.0-alpha2 * Change default for cassandra.set_sep_thread_name to false to reduce CPU usage (CASSANDRA-21089) * Avoid permission checks for masked columns when the table doesn't have any (CASSANDRA-21299) * Reduce allocations and array copies due to buffer resizing in LocalDataResponse during row serialization (CASSANDRA-21285) diff --cc src/java/org/apache/cassandra/db/ColumnFamilyStore.java index db15db6729,50e962ac04..5e9e2ac520 --- a/src/java/org/apache/cassandra/db/ColumnFamilyStore.java +++ b/src/java/org/apache/cassandra/db/ColumnFamilyStore.java @@@ -1957,8 -1961,15 +1966,15 @@@ public class ColumnFamilyStore implemen TimeUUID session = sst.getPendingRepair(); return session != null && sessions.contains(session); }; - return runWithCompactionsDisabled(() -> compactionStrategyManager.releaseRepairData(sessions), - predicate, OperationType.STREAM, false, true, true); + CleanupSummary summary = runWithCompactionsDisabled(() -> compactionStrategyManager.releaseRepairData(sessions), - predicate, OperationType.STREAM, false, true, true); ++ predicate, OperationType.STREAM, false, true, true); + if (summary == null) + { + logger.warn("Unable to cancel in-progress compactions for {}.{}, could not force release repair data for sessions {}", + getKeyspaceName(), name, sessions); + return new CleanupSummary(this, Collections.emptySet(), new HashSet<>(sessions)); + } + return summary; } else { diff --cc test/unit/org/apache/cassandra/db/TruncateBlockingTest.java index 0000000000,6d464a42e9..76c3ccc071 mode 000000,100644..100644 --- a/test/unit/org/apache/cassandra/db/TruncateBlockingTest.java +++ b/test/unit/org/apache/cassandra/db/TruncateBlockingTest.java @@@ -1,0 -1,226 +1,226 @@@ + /* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.apache.cassandra.db; + + import java.util.Collections; + + import org.assertj.core.api.Assertions; + import org.jboss.byteman.contrib.bmunit.BMRule; + import org.jboss.byteman.contrib.bmunit.BMUnitRunner; + import org.junit.Test; + import org.junit.runner.RunWith; + + import org.apache.cassandra.cql3.CQLTester; + import org.apache.cassandra.db.compaction.CompactionInfo; + import org.apache.cassandra.db.compaction.CompactionManager; + import org.apache.cassandra.db.compaction.OperationType; + import org.apache.cassandra.db.lifecycle.LifecycleTransaction; + import org.apache.cassandra.exceptions.TruncateException; + import org.apache.cassandra.io.sstable.format.SSTableReader; + import org.apache.cassandra.service.StorageService; + + import static org.apache.cassandra.utils.TimeUUID.Generator.nextTimeUUID; + import static org.junit.Assert.assertFalse; + import static org.junit.Assert.assertNotNull; + + @RunWith(BMUnitRunner.class) + public class TruncateBlockingTest extends CQLTester + { + @Test + public void testTruncateFailsWhenCompactionsCannotBeDisabled() + { + createTable("CREATE TABLE %s (id int PRIMARY KEY, v text)"); + + execute("INSERT INTO %s (id, v) VALUES (1, 'a')"); + execute("INSERT INTO %s (id, v) VALUES (2, 'b')"); + execute("INSERT INTO %s (id, v) VALUES (3, 'c')"); + flush(); + + ColumnFamilyStore cfs = getCurrentColumnFamilyStore(); + + // Register a P0-priority compaction holder for this table to force + // runWithCompactionsDisabled to return null immediately. + CompactionInfo.Holder holder = new CompactionInfo.Holder() + { + public CompactionInfo getCompactionInfo() + { + return new CompactionInfo(cfs.metadata(), + OperationType.P0, + 0, + 100, + 100, + nextTimeUUID(), + Collections.emptySet()); + } + + public boolean isGlobal() + { + return false; + } + }; + + CompactionManager.instance.active.beginCompaction(holder); + try + { + Assertions.assertThatThrownBy(cfs::truncateBlocking) + .as("Unable to stop compaction. Usually retrying truncate will work") + .isInstanceOf(TruncateException.class); + + assertRows(execute("SELECT * FROM %s WHERE id = 1"), row(1, "a")); + assertRows(execute("SELECT * FROM %s WHERE id = 2"), row(2, "b")); + assertRows(execute("SELECT * FROM %s WHERE id = 3"), row(3, "c")); + assertFalse("SSTables should still be present after truncation failure", + cfs.getLiveSSTables().isEmpty()); + + } + finally + { + CompactionManager.instance.active.finishCompaction(holder); + } + } + + @Test + @BMRule(name = "no-op waitForCessation", + targetClass = "org.apache.cassandra.db.compaction.CompactionManager", + targetMethod = "waitForCessation", + action = "return;") + public void testTruncateFailsWhenCompactionsDoNotStopInTime() + { + createTable("CREATE TABLE %s (id int PRIMARY KEY, v text)"); + + execute("INSERT INTO %s (id, v) VALUES (1, 'a')"); + execute("INSERT INTO %s (id, v) VALUES (2, 'b')"); + execute("INSERT INTO %s (id, v) VALUES (3, 'c')"); + flush(); + + ColumnFamilyStore cfs = getCurrentColumnFamilyStore(); + SSTableReader sstable = cfs.getLiveSSTables().iterator().next(); + + // Mark the sstable as compacting directly in the tracker, without registering a + // CompactionInfo.Holder. There is nothing for interruptCompactionForCFs to stop, so + // runWithCompactionsDisabled falls through to waitForCessation, then finds the sstable + // still in the compacting set and returns null. + try (LifecycleTransaction txn = cfs.getTracker().tryModify(sstable, OperationType.ANTICOMPACTION)) + { + assertNotNull("Unable to mark sstable compacting", txn); + + Assertions.assertThatThrownBy(cfs::truncateBlocking) + .as("Unable to stop compaction. Usually retrying truncate will work") + .isInstanceOf(TruncateException.class); + + assertRows(execute("SELECT * FROM %s WHERE id = 1"), row(1, "a")); + assertRows(execute("SELECT * FROM %s WHERE id = 2"), row(2, "b")); + assertRows(execute("SELECT * FROM %s WHERE id = 3"), row(3, "c")); + assertFalse("SSTables should still be present after truncation failure", + cfs.getLiveSSTables().isEmpty()); + } + } + + @Test + public void testRebuildOnFailedScrubReturnsFalseWhenTruncateFails() + { + createTable("CREATE TABLE %s (id int PRIMARY KEY, v text)"); + // rebuildOnFailedScrub only applies to indexes with their own backing table + createIndex("CREATE INDEX ON %s (v) USING 'legacy_local_table'"); + + execute("INSERT INTO %s (id, v) VALUES (1, 'a')"); + flush(); + + ColumnFamilyStore baseCfs = getCurrentColumnFamilyStore(); + ColumnFamilyStore indexCfs = baseCfs.indexManager.getAllIndexColumnFamilyStores().iterator().next(); + + // Register a P0-priority compaction holder for the index cfs to force truncateBlocking to fail. + CompactionInfo.Holder holder = new CompactionInfo.Holder() + { + public CompactionInfo getCompactionInfo() + { + return new CompactionInfo(indexCfs.metadata(), + OperationType.P0, + 0, + 100, + 100, + nextTimeUUID(), + Collections.emptySet()); + } + + public boolean isGlobal() + { + return false; + } + }; + + CompactionManager.instance.active.beginCompaction(holder); + try + { + RuntimeException scrubFailure = new RuntimeException("original scrub failure"); + // rebuildOnFailedScrub should report the rebuild as unsuccessful + assertFalse("rebuildOnFailedScrub should return false when it can't truncate the index", + indexCfs.rebuildOnFailedScrub(scrubFailure)); + } + finally + { + CompactionManager.instance.active.finishCompaction(holder); + } + } + + @Test + public void testMutateSSTableRepairedStateThrowsWhenCompactionsCannotBeDisabled() + { + createTable("CREATE TABLE %s (id int PRIMARY KEY, v text)"); + + execute("INSERT INTO %s (id, v) VALUES (1, 'a')"); + flush(); + + ColumnFamilyStore cfs = getCurrentColumnFamilyStore(); + + // Register a P0-priority compaction holder for this table to force runWithCompactionsDisabled + // to return null + CompactionInfo.Holder holder = new CompactionInfo.Holder() + { + public CompactionInfo getCompactionInfo() + { + return new CompactionInfo(cfs.metadata(), + OperationType.P0, + 0, + 100, + 100, + nextTimeUUID(), + Collections.emptySet()); + } + + public boolean isGlobal() + { + return false; + } + }; + + CompactionManager.instance.active.beginCompaction(holder); + try + { + // mutateSSTableRepairedState should report the null runWithCompactionsDisabled result as a + // failure to the caller + Assertions.assertThatThrownBy(() -> StorageService.instance.mutateSSTableRepairedState(true, false, keyspace(), Collections.singletonList(currentTable()))) + .as("Unable to cancel in-progress compactions. Usually retrying will work") + .isInstanceOf(RuntimeException.class); + } + finally + { + CompactionManager.instance.active.finishCompaction(holder); + } + } -} ++} --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
