mirror of https://github.com/apache/cassandra
Allowing CMS reconfigure if all nodes in the cluster are used
This commit is contained in:
parent
1710e84c40
commit
c4319a7a0d
|
|
@ -184,16 +184,18 @@ public class CMSOperations implements CMSOperationsMBean
|
|||
private void guardMinimumCmsSize(ReplicationParams params)
|
||||
{
|
||||
ClusterMetadata metadata = ClusterMetadata.current();
|
||||
int minCmsSize = Guardrails.instance.getMinimumCmsSizeFailThreshold();
|
||||
int totalNodes = metadata.directory.allJoinedEndpoints().size();
|
||||
// Skip clusters smaller than the threshold: they cannot host that many replicas yet (e.g. during bootstrap).
|
||||
// When the guardrail is disabled this is never true, and guard() below is then a no-op.
|
||||
if (totalNodes < minCmsSize)
|
||||
return;
|
||||
|
||||
int cmsSize = params.options.values().stream()
|
||||
.mapToInt(Integer::parseInt)
|
||||
.sum();
|
||||
// A cluster can't host more CMS replicas than it has nodes. If the request already uses every node there's
|
||||
// nothing more to enforce (e.g. during bootstrap), and requiring more would brick reconfiguration. Otherwise
|
||||
// the request must meet the configured minimum, even when the threshold exceeds the current cluster size, so
|
||||
// an operator can't sidestep the floor by setting a high threshold. An operator who genuinely wants a smaller
|
||||
// CMS should disable the guardrail. When it is disabled, guard() below is a no-op.
|
||||
if (cmsSize >= totalNodes)
|
||||
return;
|
||||
|
||||
Guardrails.minimumCmsSize.guard(cmsSize, "CMS", false, null);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -33,8 +33,8 @@ import static org.apache.cassandra.distributed.api.Feature.NETWORK;
|
|||
|
||||
/**
|
||||
* Exercises the minimum CMS size guardrail via the real {@code nodetool cms reconfigure} path against a live in-JVM
|
||||
* cluster. The guardrail only applies once the cluster has at least as many nodes as the threshold, so multiple nodes
|
||||
* are required to trigger it.
|
||||
* cluster. The guardrail applies unless the requested CMS size already uses every joined node (the cluster cannot
|
||||
* host more replicas), so multiple nodes are required to trigger it.
|
||||
*/
|
||||
public class GuardrailCmsSizeReconfigurationTest extends TestBaseImpl
|
||||
{
|
||||
|
|
@ -78,7 +78,7 @@ public class GuardrailCmsSizeReconfigurationTest extends TestBaseImpl
|
|||
@Test
|
||||
public void reconfigureBelowThresholdIsAllowedWhenClusterTooSmall() throws IOException
|
||||
{
|
||||
// The cluster has fewer nodes than the threshold, so it cannot host that many replicas and the guardrail is skipped.
|
||||
// The requested CMS size (2) already uses every node in the cluster, so there is nothing more to enforce.
|
||||
try (Cluster cluster = build(2).withConfig(config(THRESHOLD)).start())
|
||||
{
|
||||
cluster.get(1).nodetoolResult("cms", "reconfigure", "2")
|
||||
|
|
@ -87,6 +87,34 @@ public class GuardrailCmsSizeReconfigurationTest extends TestBaseImpl
|
|||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void reconfigureBelowClusterCapacityIsRejectedWhenThresholdAboveClusterSize() throws IOException
|
||||
{
|
||||
// Threshold (4) is above the cluster size (3), but the cluster can still host a CMS of 3. Requesting a smaller
|
||||
// size than the cluster can support must be rejected rather than silently skipped, so a high threshold can't
|
||||
// be used to sidestep the floor.
|
||||
try (Cluster cluster = build(3).withConfig(config(4)).start())
|
||||
{
|
||||
cluster.get(1).nodetoolResult("cms", "reconfigure", "2")
|
||||
.asserts()
|
||||
.failure()
|
||||
.stderrContains("failure threshold of 4");
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void reconfigureAtClusterCapacityIsAllowedWhenThresholdAboveClusterSize() throws IOException
|
||||
{
|
||||
// Threshold (4) is above the cluster size (3). A CMS of 3 already uses every node, so it is allowed even though
|
||||
// it is below the threshold: the cluster simply cannot do better, and blocking it would brick reconfiguration.
|
||||
try (Cluster cluster = build(3).withConfig(config(4)).start())
|
||||
{
|
||||
cluster.get(1).nodetoolResult("cms", "reconfigure", "3")
|
||||
.asserts()
|
||||
.success();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void reconfigureMultiDcBelowThresholdIsRejected() throws IOException
|
||||
{
|
||||
|
|
|
|||
Loading…
Reference in New Issue