Merge branch 'cassandra-6.0' into trunk

This commit is contained in:
Sam Tunnicliffe 2026-05-20 16:29:24 +01:00
commit 43a1f51d45
3 changed files with 31 additions and 14 deletions

View File

@ -1,8 +1,7 @@
7.0
* Allow nodetool garbagecollect to take a user defined list of SSTables (CASSANDRA-16767)
* Add a guardrail for misprepared statements (CASSANDRA-21139)
Merged from 6.0:
* Add an offline cluster metadata tool (CASSANDRA-19151)
6.0-alpha2
* Ensure schema created before 2.1 without tableId in folder name can be loaded in SnapshotLoader (CASSANDRA-21246)
* 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)
@ -12,6 +11,8 @@ Merged from 5.0:
6.0-alpha2
* Restore option to avoid hint transfer during decommission (CASSANDRA-21341)
* Add an offline cluster metadata tool (CASSANDRA-19151)
* Accord: Tail Latency Improvements (CASSANDRA-21361)
* Artificial Latency Injection (CASSANDRA-17024)
* Accord: Clean Shutdown/Restart, Rebootstrap, et al (CASSANDRA-21355)

View File

@ -30,9 +30,11 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.apache.cassandra.batchlog.BatchlogManager;
import org.apache.cassandra.config.DatabaseDescriptor;
import org.apache.cassandra.db.SystemKeyspace;
import org.apache.cassandra.dht.Range;
import org.apache.cassandra.dht.Token;
import org.apache.cassandra.hints.HintsService;
import org.apache.cassandra.locator.EndpointsByReplica;
import org.apache.cassandra.locator.InetAddressAndPort;
import org.apache.cassandra.locator.RangesAtEndpoint;
@ -50,6 +52,7 @@ import org.apache.cassandra.tcm.membership.NodeId;
import org.apache.cassandra.tcm.ownership.MovementMap;
import org.apache.cassandra.tcm.ownership.PlacementDeltas;
import org.apache.cassandra.utils.concurrent.Future;
import org.apache.cassandra.utils.concurrent.ImmediateFuture;
public class UnbootstrapStreams implements LeaveStreams
{
@ -125,9 +128,20 @@ public class UnbootstrapStreams implements LeaveStreams
logger.debug("waiting for batch log processing.");
batchlogReplay.get();
logger.info("streaming hints to other nodes");
Future<?> hintsSuccess = ImmediateFuture.success(null);
Future<?> hintsSuccess = StorageService.instance.streamHints();
if (DatabaseDescriptor.getTransferHintsOnDecommission())
{
logger.info("streaming hints to other nodes");
hintsSuccess = StorageService.instance.streamHints();
}
else
{
logger.info("pausing dispatch and deleting hints");
DatabaseDescriptor.setHintedHandoffEnabled(false);
HintsService.instance.pauseDispatch();
HintsService.instance.deleteAllHints();
}
// wait for the transfer runnables to signal the latch.
logger.debug("waiting for stream acks.");

View File

@ -71,25 +71,27 @@ public class HintedHandoffAddRemoveNodesTest extends TestBaseImpl
{
cluster.schemaChange(withKeyspace("CREATE TABLE %s.decom_no_hints_test (key int PRIMARY KEY, value int)"));
cluster.coordinator(1).execute(withKeyspace("INSERT INTO %s.decom_no_hints_test (key, value) VALUES (?, ?)"), ALL, 0, 0);
long hintsBeforeShutdown = countTotalHints(cluster.get(1));
int secondNode = 2;
cluster.coordinator(secondNode).execute(withKeyspace("INSERT INTO %s.decom_no_hints_test (key, value) VALUES (?, ?)"), ALL, 0, 0);
long hintsBeforeShutdown = countTotalHints(cluster.get(secondNode));
assertThat(hintsBeforeShutdown).isEqualTo(0);
long hintsDelivered = countHintsDelivered(cluster.get(1));
long hintsDelivered = countHintsDelivered(cluster.get(secondNode));
assertThat(hintsDelivered).isEqualTo(0);
// Shutdown node 3 so hints can be written against it.
cluster.get(3).shutdown().get();
cluster.coordinator(1).execute(withKeyspace("INSERT INTO %s.decom_no_hints_test (key, value) VALUES (?, ?)"), TWO, 0, 0);
Awaitility.await().until(() -> countTotalHints(cluster.get(1)) > 0);
long hintsAfterShutdown = countTotalHints(cluster.get(1));
cluster.coordinator(secondNode).execute(withKeyspace("INSERT INTO %s.decom_no_hints_test (key, value) VALUES (?, ?)"), TWO, 0, 0);
Awaitility.await().until(() -> countTotalHints(cluster.get(secondNode)) > 0);
long hintsAfterShutdown = countTotalHints(cluster.get(secondNode));
assertThat(hintsAfterShutdown).isEqualTo(1);
cluster.get(2).runOnInstance(() -> setProgressBarrierMinConsistencyLevel(org.apache.cassandra.db.ConsistencyLevel.ONE));
cluster.get(secondNode).runOnInstance(() -> setProgressBarrierMinConsistencyLevel(org.apache.cassandra.db.ConsistencyLevel.ONE));
ClusterUtils.waitForCMSToQuiesce(cluster, cluster.get(1), 3);
cluster.get(2).nodetoolResult("decommission", "--force").asserts().success();
long hintsDeliveredByDecom = countHintsDelivered(cluster.get(2));
String mode = cluster.get(2).callOnInstance(() -> StorageService.instance.getOperationMode());
cluster.get(secondNode).nodetoolResult("decommission", "--force").asserts().success();
long hintsDeliveredByDecom = countHintsDelivered(cluster.get(secondNode));
String mode = cluster.get(secondNode).callOnInstance(() -> StorageService.instance.getOperationMode());
assertEquals(StorageService.Mode.DECOMMISSIONED.toString(), mode);
assertThat(hintsDeliveredByDecom).isEqualTo(0);
}