Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGES.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
4.1.12
* Fix UnsupportedOperationException in repairPaxosForTopologyChange when there are insufficient live nodes (CASSANDRA-21427)
* Add Paxos v2 option and informatin in cassandra.yaml (CASSANDRA-21316)
* Harden data resurrection startup check with atomic heartbeat file write with fallback (CASSANDRA-21290)
Merged from 4.0:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1038,7 +1038,6 @@ public Future<?> repairPaxosForTopologyChange(String ksName, Collection<Range<To
if (!PaxosRepair.hasSufficientLiveNodesForTopologyChange(keyspace, range, endpoints))
{
Set<InetAddressAndPort> downEndpoints = replication.getNaturalReplicas(range.right).filter(e -> !endpoints.contains(e)).endpoints();
downEndpoints.removeAll(endpoints);

throw new RuntimeException(String.format("Insufficient live nodes to repair paxos for %s in %s for %s.\n" +
"There must be enough live nodes to satisfy EACH_QUORUM, but the following nodes are down: %s\n" +
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@
public class ActiveRepairServiceTest
{
public static final String KEYSPACE5 = "Keyspace5";
public static final String KEYSPACE_RF3 = "KeyspaceRf3";
public static final String CF_STANDARD1 = "Standard1";
public static final String CF_COUNTER = "Counter1";
public static final int TASK_SECONDS = 10;
Expand All @@ -101,6 +102,9 @@ public static void defineSchema() throws ConfigurationException
KeyspaceParams.simple(2),
SchemaLoader.standardCFMD(KEYSPACE5, CF_COUNTER),
SchemaLoader.standardCFMD(KEYSPACE5, CF_STANDARD1));
SchemaLoader.createKeyspace(KEYSPACE_RF3,
KeyspaceParams.simple(3),
SchemaLoader.standardCFMD(KEYSPACE_RF3, CF_STANDARD1));
}

@Before
Expand Down Expand Up @@ -265,6 +269,38 @@ public void testParentRepairStatus() throws Throwable

}

@Test
public void repairPaxosForTopologyChangeThrowsRuntimeExceptionWhenInsufficientLiveNodes() throws Throwable
{
TokenMetadata tmd = StorageService.instance.getTokenMetadata();
tmd.clearUnsafe();

// Local node is the only live replica.
tmd.updateNormalToken(tmd.partitioner.getRandomToken(), FBUtilities.getBroadcastAddressAndPort());
// Two additional natural replicas with no gossip state -> treated as down by the FailureDetector.
tmd.updateNormalToken(tmd.partitioner.getRandomToken(), InetAddressAndPort.getByName("127.0.0.3"));
tmd.updateNormalToken(tmd.partitioner.getRandomToken(), InetAddressAndPort.getByName("127.0.0.4"));

// With exactly RF endpoints in the ring, every range's natural replicas are all three nodes.
Token token = tmd.partitioner.getMinimumToken();
Collection<Range<Token>> ranges = Collections.singleton(new Range<>(token, token));

try
{
ActiveRepairService.instance.repairPaxosForTopologyChange(KEYSPACE_RF3, ranges, "test");
Assert.fail("Expected RuntimeException due to insufficient live nodes");
}
catch (UnsupportedOperationException e)
{
Assert.fail("repairPaxosForTopologyChange must not throw UnsupportedOperationException: " + e);
}
catch (RuntimeException e)
{
Assert.assertTrue("Unexpected message: " + e.getMessage(),
e.getMessage() != null && e.getMessage().contains("Insufficient live nodes to repair paxos"));
}
}

Set<InetAddressAndPort> addTokens(int max) throws Throwable
{
TokenMetadata tmd = StorageService.instance.getTokenMetadata();
Expand Down