This is an automated email from the ASF dual-hosted git repository.
dcapwell pushed a commit to branch trunk
in repository https://gitbox.apache.org/repos/asf/cassandra.git
The following commit(s) were added to refs/heads/trunk by this push:
new da7c662227 Migrate threshold for minimum keyspace replication factor
to guardrails
da7c662227 is described below
commit da7c66222740f02c6de5b563681dd381d28f8201
Author: Savni Nagarkar <[email protected]>
AuthorDate: Thu Apr 28 13:18:39 2022 -0700
Migrate threshold for minimum keyspace replication factor to guardrails
patch by Savni Nagarkar; reviewed by Andres de la Peña, David Capwell for
CASSANDRA-17212
---
CHANGES.txt | 1 +
NEWS.txt | 1 +
conf/cassandra.yaml | 10 +-
src/java/org/apache/cassandra/config/Config.java | 5 +-
.../cassandra/config/DatabaseDescriptor.java | 26 +-
.../apache/cassandra/config/GuardrailsOptions.java | 109 ++++++--
.../statements/schema/AlterKeyspaceStatement.java | 2 +-
.../statements/schema/CreateKeyspaceStatement.java | 2 +-
.../apache/cassandra/db/guardrails/Guardrails.java | 239 ++++++++++--------
.../cassandra/db/guardrails/GuardrailsConfig.java | 11 +
.../cassandra/db/guardrails/GuardrailsMBean.java | 19 ++
...{PercentageThreshold.java => MaxThreshold.java} | 37 +--
...{PercentageThreshold.java => MinThreshold.java} | 39 +--
.../db/guardrails/PercentageThreshold.java | 2 +-
.../apache/cassandra/db/guardrails/Threshold.java | 35 ++-
.../locator/AbstractReplicationStrategy.java | 25 +-
.../cassandra/locator/NetworkTopologyStrategy.java | 5 +-
.../apache/cassandra/locator/SimpleStrategy.java | 5 +-
.../apache/cassandra/schema/KeyspaceMetadata.java | 2 +-
.../apache/cassandra/schema/KeyspaceParams.java | 6 +-
.../apache/cassandra/schema/ReplicationParams.java | 5 +-
.../apache/cassandra/service/StorageService.java | 11 -
.../cassandra/service/StorageServiceMBean.java | 2 -
src/java/org/apache/cassandra/tools/NodeProbe.java | 10 -
src/java/org/apache/cassandra/tools/NodeTool.java | 2 -
.../tools/nodetool/GetMinimumKeyspaceRF.java | 33 ---
.../tools/nodetool/SetMinimumKeyspaceRF.java | 36 ---
.../config/DatabaseDescriptorRefTest.java | 6 -
.../cassandra/config/DatabaseDescriptorTest.java | 20 --
.../cql3/validation/operations/AlterTest.java | 24 --
.../cql3/validation/operations/CreateTest.java | 22 --
.../guardrails/GuardrailColumnsPerTableTest.java | 2 +-
.../db/guardrails/GuardrailKeyspacesTest.java | 2 +-
.../GuardrailMinimumReplicationFactorTest.java | 277 +++++++++++++++++++++
.../GuardrailSecondaryIndexesPerTable.java | 2 +-
.../db/guardrails/GuardrailTablesTest.java | 2 +-
.../cassandra/db/guardrails/GuardrailTester.java | 2 +-
.../db/guardrails/GuardrailViewsPerTableTest.java | 2 +-
.../guardrails/GuardrailsConfigProviderTest.java | 2 +-
.../cassandra/db/guardrails/GuardrailsTest.java | 127 ++++++++--
.../cassandra/db/guardrails/ThresholdTester.java | 43 +++-
.../locator/NetworkTopologyStrategyTest.java | 2 +-
.../cassandra/locator/SimpleStrategyTest.java | 2 +-
.../tools/nodetool/GetMinimumKeyspaceRFTest.java | 87 -------
.../tools/nodetool/SetMinimumKeyspaceRFTest.java | 94 -------
45 files changed, 796 insertions(+), 602 deletions(-)
diff --git a/CHANGES.txt b/CHANGES.txt
index b069eacb4a..09e1471b33 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -1,4 +1,5 @@
4.1
+ * Migrate threshold for minimum keyspace replication factor to guardrails
(CASSANDRA-17212)
* Add guardrail to disallow TRUNCATE and DROP TABLE commands (CASSANDRA-17558)
* Add plugin support for CQLSH (CASSANDRA-16456)
* Add guardrail to disallow querying with ALLOW FILTERING (CASSANDRA-17370)
diff --git a/NEWS.txt b/NEWS.txt
index 97bfd331c4..cd13c996d4 100644
--- a/NEWS.txt
+++ b/NEWS.txt
@@ -79,6 +79,7 @@ New features
- Allowed write consistency levels.
- Collections size.
- Query page size.
+ - Minimum replication factor.
- Data disk usage, defined either as a percentage or as an absolute
size.
- Whether user-defined timestamps are allowed.
- Whether GROUP BY queries are allowed.
diff --git a/conf/cassandra.yaml b/conf/cassandra.yaml
index c3e183fbd3..89feab4b12 100644
--- a/conf/cassandra.yaml
+++ b/conf/cassandra.yaml
@@ -1449,11 +1449,6 @@ compaction_tombstone_warning_threshold: 100000
# Suggested value for use in production: 3
# default_keyspace_rf: 1
-# The minimum allowable replication factor. Creating a keyspace with a
replication factor less than this value will be rejected.
-# This would also apply to system keyspaces.
-# Suggested value for use in production: 2 or higher
-# minimum_keyspace_rf: 0
-
# Track a metric per keyspace indicating whether replication achieved the
ideal consistency
# level for writes without timing out. This is different from the consistency
level requested by
# each write which may be lower in order to facilitate availability.
@@ -1690,6 +1685,11 @@ drop_compact_storage_enabled: false
# Valid values are in [1, max available disk size of all data directories].
# Defaults to null to disable and use the physically available disk size of
data directories during calculations.
# data_disk_usage_max_disk_size:
+# Guardrail to warn or fail when the minimum replication factor is lesser than
threshold.
+# This would also apply to system keyspaces.
+# Suggested value for use in production: 2 or higher
+# minimum_replication_factor_warn_threshold: -1
+# minimum_replication_factor_fail_threshold: -1
# Startup Checks are executed as part of Cassandra startup process, not all of
them
# are configurable (so you can disable them) but these which are enumerated
bellow.
diff --git a/src/java/org/apache/cassandra/config/Config.java
b/src/java/org/apache/cassandra/config/Config.java
index 1c277cf0c7..c39d9daaae 100644
--- a/src/java/org/apache/cassandra/config/Config.java
+++ b/src/java/org/apache/cassandra/config/Config.java
@@ -636,10 +636,9 @@ public class Config
public volatile boolean diagnostic_events_enabled = false;
- // Default and minimum keyspace replication factors allow validation of
newly created keyspaces
+ // Default keyspace replication factors allow validation of newly created
keyspaces
// and good defaults if no replication factor is provided by the user
public volatile int default_keyspace_rf = 1;
- public volatile int minimum_keyspace_rf = 0;
/**
* flags for enabling tracking repaired state of data during reads
@@ -823,6 +822,8 @@ public class Config
public volatile int data_disk_usage_percentage_warn_threshold = -1;
public volatile int data_disk_usage_percentage_fail_threshold = -1;
public volatile DataStorageSpec data_disk_usage_max_disk_size = null;
+ public volatile int minimum_replication_factor_warn_threshold = -1;
+ public volatile int minimum_replication_factor_fail_threshold = -1;
public volatile DurationSpec streaming_state_expires =
DurationSpec.inDays(3);
public volatile DataStorageSpec streaming_state_size =
DataStorageSpec.inMebibytes(40);
diff --git a/src/java/org/apache/cassandra/config/DatabaseDescriptor.java
b/src/java/org/apache/cassandra/config/DatabaseDescriptor.java
index 0ce787fe32..a264cbc847 100644
--- a/src/java/org/apache/cassandra/config/DatabaseDescriptor.java
+++ b/src/java/org/apache/cassandra/config/DatabaseDescriptor.java
@@ -868,10 +868,10 @@ public class DatabaseDescriptor
validateMaxConcurrentAutoUpgradeTasksConf(conf.max_concurrent_automatic_sstable_upgrades);
- if (conf.default_keyspace_rf < conf.minimum_keyspace_rf)
+ if (conf.default_keyspace_rf <
conf.minimum_replication_factor_fail_threshold)
{
- throw new
ConfigurationException(String.format("default_keyspace_rf (%d) cannot be less
than minimum_keyspace_rf (%d)",
-
conf.default_keyspace_rf, conf.minimum_keyspace_rf));
+ throw new
ConfigurationException(String.format("default_keyspace_rf (%d) cannot be less
than minimum_replication_factor_fail_threshold (%d)",
+
conf.default_keyspace_rf, conf.minimum_replication_factor_fail_threshold));
}
if (conf.paxos_repair_parallelism <= 0)
@@ -4081,30 +4081,14 @@ public class DatabaseDescriptor
throw new ConfigurationException("default_keyspace_rf cannot be
less than 1");
}
- if (value < getMinimumKeyspaceRF())
+ if (value < guardrails.getMinimumReplicationFactorFailThreshold())
{
- throw new
ConfigurationException(String.format("default_keyspace_rf to be set (%d) cannot
be less than minimum_keyspace_rf (%d)", value, getMinimumKeyspaceRF()));
+ throw new
ConfigurationException(String.format("default_keyspace_rf to be set (%d) cannot
be less than minimum_replication_factor_fail_threshold (%d)", value,
guardrails.getMinimumReplicationFactorFailThreshold()));
}
conf.default_keyspace_rf = value;
}
- public static int getMinimumKeyspaceRF() { return
conf.minimum_keyspace_rf; }
-
- public static void setMinimumKeyspaceRF(int value) throws
ConfigurationException
- {
- if (value < 0)
- {
- throw new ConfigurationException("minimum_keyspace_rf cannot be
negative");
- }
-
- if (value > getDefaultKeyspaceRF())
- {
- throw new
ConfigurationException(String.format("minimum_keyspace_rf to be set (%d) cannot
be greater than default_keyspace_rf (%d)", value, getDefaultKeyspaceRF()));
- }
-
- conf.minimum_keyspace_rf = value;
- }
public static boolean getUseStatementsEnabled()
{
diff --git a/src/java/org/apache/cassandra/config/GuardrailsOptions.java
b/src/java/org/apache/cassandra/config/GuardrailsOptions.java
index 6654b4fc74..27ad37d3ef 100644
--- a/src/java/org/apache/cassandra/config/GuardrailsOptions.java
+++ b/src/java/org/apache/cassandra/config/GuardrailsOptions.java
@@ -61,27 +61,27 @@ public class GuardrailsOptions implements GuardrailsConfig
public GuardrailsOptions(Config config)
{
this.config = config;
- validateIntThreshold(config.keyspaces_warn_threshold,
config.keyspaces_fail_threshold, "keyspaces");
- validateIntThreshold(config.tables_warn_threshold,
config.tables_fail_threshold, "tables");
- validateIntThreshold(config.columns_per_table_warn_threshold,
config.columns_per_table_fail_threshold, "columns_per_table");
-
validateIntThreshold(config.secondary_indexes_per_table_warn_threshold,
config.secondary_indexes_per_table_fail_threshold,
"secondary_indexes_per_table");
-
validateIntThreshold(config.materialized_views_per_table_warn_threshold,
config.materialized_views_per_table_fail_threshold,
"materialized_views_per_table");
+ validateMaxIntThreshold(config.keyspaces_warn_threshold,
config.keyspaces_fail_threshold, "keyspaces");
+ validateMaxIntThreshold(config.tables_warn_threshold,
config.tables_fail_threshold, "tables");
+ validateMaxIntThreshold(config.columns_per_table_warn_threshold,
config.columns_per_table_fail_threshold, "columns_per_table");
+
validateMaxIntThreshold(config.secondary_indexes_per_table_warn_threshold,
config.secondary_indexes_per_table_fail_threshold,
"secondary_indexes_per_table");
+
validateMaxIntThreshold(config.materialized_views_per_table_warn_threshold,
config.materialized_views_per_table_fail_threshold,
"materialized_views_per_table");
config.table_properties_warned =
validateTableProperties(config.table_properties_warned,
"table_properties_warned");
config.table_properties_ignored =
validateTableProperties(config.table_properties_ignored,
"table_properties_ignored");
config.table_properties_disallowed =
validateTableProperties(config.table_properties_disallowed,
"table_properties_disallowed");
- validateIntThreshold(config.page_size_warn_threshold,
config.page_size_fail_threshold, "page_size");
- validateIntThreshold(config.partition_keys_in_select_warn_threshold,
- config.partition_keys_in_select_fail_threshold,
"partition_keys_in_select");
-
validateIntThreshold(config.in_select_cartesian_product_warn_threshold,
config.in_select_cartesian_product_fail_threshold,
"in_select_cartesian_product");
+ validateMaxIntThreshold(config.page_size_warn_threshold,
config.page_size_fail_threshold, "page_size");
+
validateMaxIntThreshold(config.partition_keys_in_select_warn_threshold,
config.partition_keys_in_select_fail_threshold, "partition_keys_in_select");
+
validateMaxIntThreshold(config.in_select_cartesian_product_warn_threshold,
config.in_select_cartesian_product_fail_threshold,
"in_select_cartesian_product");
config.read_consistency_levels_warned =
validateConsistencyLevels(config.read_consistency_levels_warned,
"read_consistency_levels_warned");
config.read_consistency_levels_disallowed =
validateConsistencyLevels(config.read_consistency_levels_disallowed,
"read_consistency_levels_disallowed");
config.write_consistency_levels_warned =
validateConsistencyLevels(config.write_consistency_levels_warned,
"write_consistency_levels_warned");
config.write_consistency_levels_disallowed =
validateConsistencyLevels(config.write_consistency_levels_disallowed,
"write_consistency_levels_disallowed");
validateSizeThreshold(config.collection_size_warn_threshold,
config.collection_size_fail_threshold, false, "collection_size");
- validateIntThreshold(config.items_per_collection_warn_threshold,
config.items_per_collection_fail_threshold, "items_per_collection");
- validateIntThreshold(config.fields_per_udt_warn_threshold,
config.fields_per_udt_fail_threshold, "fields_per_udt");
+ validateMaxIntThreshold(config.items_per_collection_warn_threshold,
config.items_per_collection_fail_threshold, "items_per_collection");
+ validateMaxIntThreshold(config.fields_per_udt_warn_threshold,
config.fields_per_udt_fail_threshold, "fields_per_udt");
validatePercentageThreshold(config.data_disk_usage_percentage_warn_threshold,
config.data_disk_usage_percentage_fail_threshold, "data_disk_usage_percentage");
validateDataDiskUsageMaxDiskSize(config.data_disk_usage_max_disk_size);
+
validateMinRFThreshold(config.minimum_replication_factor_warn_threshold,
config.minimum_replication_factor_fail_threshold, "minimum_replication_factor");
}
@Override
@@ -98,7 +98,7 @@ public class GuardrailsOptions implements GuardrailsConfig
public void setKeyspacesThreshold(int warn, int fail)
{
- validateIntThreshold(warn, fail, "keyspaces");
+ validateMaxIntThreshold(warn, fail, "keyspaces");
updatePropertyWithLogging("keyspaces_warn_threshold",
warn,
() -> config.keyspaces_warn_threshold,
@@ -123,7 +123,7 @@ public class GuardrailsOptions implements GuardrailsConfig
public void setTablesThreshold(int warn, int fail)
{
- validateIntThreshold(warn, fail, "tables");
+ validateMaxIntThreshold(warn, fail, "tables");
updatePropertyWithLogging("tables_warn_threshold",
warn,
() -> config.tables_warn_threshold,
@@ -148,7 +148,7 @@ public class GuardrailsOptions implements GuardrailsConfig
public void setColumnsPerTableThreshold(int warn, int fail)
{
- validateIntThreshold(warn, fail, "columns_per_table");
+ validateMaxIntThreshold(warn, fail, "columns_per_table");
updatePropertyWithLogging("columns_per_table_warn_threshold",
warn,
() ->
config.columns_per_table_warn_threshold,
@@ -173,7 +173,7 @@ public class GuardrailsOptions implements GuardrailsConfig
public void setSecondaryIndexesPerTableThreshold(int warn, int fail)
{
- validateIntThreshold(warn, fail, "secondary_indexes_per_table");
+ validateMaxIntThreshold(warn, fail, "secondary_indexes_per_table");
updatePropertyWithLogging("secondary_indexes_per_table_warn_threshold",
warn,
() ->
config.secondary_indexes_per_table_warn_threshold,
@@ -204,7 +204,7 @@ public class GuardrailsOptions implements GuardrailsConfig
public void setPartitionKeysInSelectThreshold(int warn, int fail)
{
- validateIntThreshold(warn, fail, "partition_keys_in_select");
+ validateMaxIntThreshold(warn, fail, "partition_keys_in_select");
updatePropertyWithLogging("partition_keys_in_select_warn_threshold",
warn,
() ->
config.partition_keys_in_select_warn_threshold,
@@ -223,7 +223,7 @@ public class GuardrailsOptions implements GuardrailsConfig
public void setMaterializedViewsPerTableThreshold(int warn, int fail)
{
- validateIntThreshold(warn, fail, "materialized_views_per_table");
+ validateMaxIntThreshold(warn, fail, "materialized_views_per_table");
updatePropertyWithLogging("materialized_views_per_table_warn_threshold",
warn,
() ->
config.materialized_views_per_table_warn_threshold,
@@ -248,7 +248,7 @@ public class GuardrailsOptions implements GuardrailsConfig
public void setPageSizeThreshold(int warn, int fail)
{
- validateIntThreshold(warn, fail, "page_size");
+ validateMaxIntThreshold(warn, fail, "page_size");
updatePropertyWithLogging("page_size_warn_threshold",
warn,
() -> config.page_size_warn_threshold,
@@ -427,7 +427,7 @@ public class GuardrailsOptions implements GuardrailsConfig
public void setInSelectCartesianProductThreshold(int warn, int fail)
{
- validateIntThreshold(warn, fail, "in_select_cartesian_product");
+ validateMaxIntThreshold(warn, fail, "in_select_cartesian_product");
updatePropertyWithLogging("in_select_cartesian_product_warn_threshold",
warn,
() ->
config.in_select_cartesian_product_warn_threshold,
@@ -534,7 +534,7 @@ public class GuardrailsOptions implements GuardrailsConfig
public void setItemsPerCollectionThreshold(int warn, int fail)
{
- validateIntThreshold(warn, fail, "items_per_collection");
+ validateMaxIntThreshold(warn, fail, "items_per_collection");
updatePropertyWithLogging("items_per_collection_warn_threshold",
warn,
() ->
config.items_per_collection_warn_threshold,
@@ -559,7 +559,7 @@ public class GuardrailsOptions implements GuardrailsConfig
public void setFieldsPerUDTThreshold(int warn, int fail)
{
- validateIntThreshold(warn, fail, "fields_per_udt");
+ validateMaxIntThreshold(warn, fail, "fields_per_udt");
updatePropertyWithLogging("fields_per_udt_warn_threshold",
warn,
() -> config.fields_per_udt_warn_threshold,
@@ -609,6 +609,31 @@ public class GuardrailsOptions implements GuardrailsConfig
x -> config.data_disk_usage_max_disk_size =
x);
}
+ @Override
+ public int getMinimumReplicationFactorWarnThreshold()
+ {
+ return config.minimum_replication_factor_warn_threshold;
+ }
+
+ @Override
+ public int getMinimumReplicationFactorFailThreshold()
+ {
+ return config.minimum_replication_factor_fail_threshold;
+ }
+
+ public void setMinimumReplicationFactorThreshold(int warn, int fail)
+ {
+ validateMinRFThreshold(warn, fail, "minimum_replication_factor");
+ updatePropertyWithLogging("minimum_replication_factor_warn_threshold",
+ warn,
+ () ->
config.minimum_replication_factor_warn_threshold,
+ x ->
config.minimum_replication_factor_warn_threshold = x);
+ updatePropertyWithLogging("minimum_replication_factor_fail_threshold",
+ fail,
+ () ->
config.minimum_replication_factor_fail_threshold,
+ x ->
config.minimum_replication_factor_fail_threshold = x);
+ }
+
private static <T> void updatePropertyWithLogging(String propertyName, T
newValue, Supplier<T> getter, Consumer<T> setter)
{
T oldValue = getter.get();
@@ -643,18 +668,31 @@ public class GuardrailsOptions implements GuardrailsConfig
validatePositiveNumeric(value, 100, name);
}
- private static void validateIntThreshold(int warn, int fail, String name)
+ private static void validatePercentageThreshold(int warn, int fail, String
name)
+ {
+ validatePercentage(warn, name + "_warn_threshold");
+ validatePercentage(fail, name + "_fail_threshold");
+ validateWarnLowerThanFail(warn, fail, name);
+ }
+
+ private static void validateMaxIntThreshold(int warn, int fail, String
name)
{
validatePositiveNumeric(warn, Integer.MAX_VALUE, name +
"_warn_threshold");
validatePositiveNumeric(fail, Integer.MAX_VALUE, name +
"_fail_threshold");
validateWarnLowerThanFail(warn, fail, name);
}
- private static void validatePercentageThreshold(int warn, int fail, String
name)
+ private static void validateMinIntThreshold(int warn, int fail, String
name)
{
- validatePercentage(warn, name + "_warn_threshold");
- validatePercentage(fail, name + "_fail_threshold");
- validateWarnLowerThanFail(warn, fail, name);
+ validatePositiveNumeric(warn, Integer.MAX_VALUE, name +
"_warn_threshold");
+ validatePositiveNumeric(fail, Integer.MAX_VALUE, name +
"_fail_threshold");
+ validateWarnGreaterThanFail(warn, fail, name);
+ }
+
+ private static void validateMinRFThreshold(int warn, int fail, String name)
+ {
+ validateMinIntThreshold(warn, fail, name);
+ validateMinRFVersusDefaultRF(fail, name);
}
private static void validateWarnLowerThanFail(long warn, long fail, String
name)
@@ -667,6 +705,25 @@ public class GuardrailsOptions implements GuardrailsConfig
"than the fail threshold
%d", warn, name, fail));
}
+ private static void validateWarnGreaterThanFail(long warn, long fail,
String name)
+ {
+ if (warn == -1 || fail == -1)
+ return;
+
+ if (fail > warn)
+ throw new IllegalArgumentException(format("The warn threshold %d
for %s_warn_threshold should be greater " +
+ "than the fail threshold
%d", warn, name, fail));
+ }
+
+ private static void validateMinRFVersusDefaultRF(int fail, String name)
throws IllegalArgumentException
+ {
+ if (fail > DatabaseDescriptor.getDefaultKeyspaceRF())
+ {
+ throw new
IllegalArgumentException(String.format("%s_fail_threshold to be set (%d) cannot
be greater than default_keyspace_rf (%d)",
+ name, fail,
DatabaseDescriptor.getDefaultKeyspaceRF()));
+ }
+ }
+
private static void validateSize(DataStorageSpec size, boolean allowZero,
String name)
{
if (size == null)
diff --git
a/src/java/org/apache/cassandra/cql3/statements/schema/AlterKeyspaceStatement.java
b/src/java/org/apache/cassandra/cql3/statements/schema/AlterKeyspaceStatement.java
index 14c648f70d..87377d70ec 100644
---
a/src/java/org/apache/cassandra/cql3/statements/schema/AlterKeyspaceStatement.java
+++
b/src/java/org/apache/cassandra/cql3/statements/schema/AlterKeyspaceStatement.java
@@ -79,7 +79,7 @@ public final class AlterKeyspaceStatement extends
AlterSchemaStatement
if (newKeyspace.params.replication.klass.equals(LocalStrategy.class))
throw ire("Unable to use given strategy class: LocalStrategy is
reserved for internal use.");
- newKeyspace.params.validate(keyspaceName);
+ newKeyspace.params.validate(keyspaceName, state);
validateNoRangeMovements();
validateTransientReplication(keyspace.createReplicationStrategy(),
newKeyspace.createReplicationStrategy());
diff --git
a/src/java/org/apache/cassandra/cql3/statements/schema/CreateKeyspaceStatement.java
b/src/java/org/apache/cassandra/cql3/statements/schema/CreateKeyspaceStatement.java
index 256b33b430..dc82f93a10 100644
---
a/src/java/org/apache/cassandra/cql3/statements/schema/CreateKeyspaceStatement.java
+++
b/src/java/org/apache/cassandra/cql3/statements/schema/CreateKeyspaceStatement.java
@@ -80,7 +80,7 @@ public final class CreateKeyspaceStatement extends
AlterSchemaStatement
if (keyspace.params.replication.klass.equals(LocalStrategy.class))
throw ire("Unable to use given strategy class: LocalStrategy is
reserved for internal use.");
- keyspace.params.validate(keyspaceName);
+ keyspace.params.validate(keyspaceName, state);
return schema.withAddedOrUpdated(keyspace);
}
diff --git a/src/java/org/apache/cassandra/db/guardrails/Guardrails.java
b/src/java/org/apache/cassandra/db/guardrails/Guardrails.java
index 3578ceb1ec..1eb2fbd93f 100644
--- a/src/java/org/apache/cassandra/db/guardrails/Guardrails.java
+++ b/src/java/org/apache/cassandra/db/guardrails/Guardrails.java
@@ -55,51 +55,51 @@ public final class Guardrails implements GuardrailsMBean
/**
* Guardrail on the total number of user keyspaces.
*/
- public static final Threshold keyspaces =
- new Threshold("keyspaces",
- state ->
CONFIG_PROVIDER.getOrCreate(state).getKeyspacesWarnThreshold(),
- state ->
CONFIG_PROVIDER.getOrCreate(state).getKeyspacesFailThreshold(),
- (isWarning, what, value, threshold) ->
- isWarning ? format("Creating keyspace %s, current number of
keyspaces %s exceeds warning threshold of %s.",
- what, value, threshold)
- : format("Cannot have more than %s keyspaces,
aborting the creation of keyspace %s",
- threshold, what));
+ public static final MaxThreshold keyspaces =
+ new MaxThreshold("keyspaces",
+ state ->
CONFIG_PROVIDER.getOrCreate(state).getKeyspacesWarnThreshold(),
+ state ->
CONFIG_PROVIDER.getOrCreate(state).getKeyspacesFailThreshold(),
+ (isWarning, what, value, threshold) ->
+ isWarning ? format("Creating keyspace %s, current number
of keyspaces %s exceeds warning threshold of %s.",
+ what, value, threshold)
+ : format("Cannot have more than %s keyspaces,
aborting the creation of keyspace %s",
+ threshold, what));
/**
* Guardrail on the total number of tables on user keyspaces.
*/
- public static final Threshold tables =
- new Threshold("tables",
- state ->
CONFIG_PROVIDER.getOrCreate(state).getTablesWarnThreshold(),
- state ->
CONFIG_PROVIDER.getOrCreate(state).getTablesFailThreshold(),
- (isWarning, what, value, threshold) ->
- isWarning ? format("Creating table %s, current number of
tables %s exceeds warning threshold of %s.",
- what, value, threshold)
- : format("Cannot have more than %s tables,
aborting the creation of table %s",
- threshold, what));
+ public static final MaxThreshold tables =
+ new MaxThreshold("tables",
+ state ->
CONFIG_PROVIDER.getOrCreate(state).getTablesWarnThreshold(),
+ state ->
CONFIG_PROVIDER.getOrCreate(state).getTablesFailThreshold(),
+ (isWarning, what, value, threshold) ->
+ isWarning ? format("Creating table %s, current number of
tables %s exceeds warning threshold of %s.",
+ what, value, threshold)
+ : format("Cannot have more than %s tables,
aborting the creation of table %s",
+ threshold, what));
/**
* Guardrail on the number of columns per table.
*/
- public static final Threshold columnsPerTable =
- new Threshold("columns_per_table",
- state ->
CONFIG_PROVIDER.getOrCreate(state).getColumnsPerTableWarnThreshold(),
- state ->
CONFIG_PROVIDER.getOrCreate(state).getColumnsPerTableFailThreshold(),
- (isWarning, what, value, threshold) ->
- isWarning ? format("The table %s has %s columns, this
exceeds the warning threshold of %s.",
- what, value, threshold)
- : format("Tables cannot have more than %s columns,
but %s provided for table %s",
- threshold, value, what));
-
- public static final Threshold secondaryIndexesPerTable =
- new Threshold("secondary_indexes_per_table",
- state ->
CONFIG_PROVIDER.getOrCreate(state).getSecondaryIndexesPerTableWarnThreshold(),
- state ->
CONFIG_PROVIDER.getOrCreate(state).getSecondaryIndexesPerTableFailThreshold(),
- (isWarning, what, value, threshold) ->
- isWarning ? format("Creating secondary index %s, current
number of indexes %s exceeds warning threshold of %s.",
- what, value, threshold)
- : format("Tables cannot have more than %s
secondary indexes, aborting the creation of secondary index %s",
- threshold, what));
+ public static final MaxThreshold columnsPerTable =
+ new MaxThreshold("columns_per_table",
+ state ->
CONFIG_PROVIDER.getOrCreate(state).getColumnsPerTableWarnThreshold(),
+ state ->
CONFIG_PROVIDER.getOrCreate(state).getColumnsPerTableFailThreshold(),
+ (isWarning, what, value, threshold) ->
+ isWarning ? format("The table %s has %s columns, this
exceeds the warning threshold of %s.",
+ what, value, threshold)
+ : format("Tables cannot have more than %s
columns, but %s provided for table %s",
+ threshold, value, what));
+
+ public static final MaxThreshold secondaryIndexesPerTable =
+ new MaxThreshold("secondary_indexes_per_table",
+ state ->
CONFIG_PROVIDER.getOrCreate(state).getSecondaryIndexesPerTableWarnThreshold(),
+ state ->
CONFIG_PROVIDER.getOrCreate(state).getSecondaryIndexesPerTableFailThreshold(),
+ (isWarning, what, value, threshold) ->
+ isWarning ? format("Creating secondary index %s, current
number of indexes %s exceeds warning threshold of %s.",
+ what, value, threshold)
+ : format("Tables cannot have more than %s
secondary indexes, aborting the creation of secondary index %s",
+ threshold, what));
/**
* Guardrail disabling user's ability to create secondary indexes
@@ -112,15 +112,15 @@ public final class Guardrails implements GuardrailsMBean
/**
* Guardrail on the number of materialized views per table.
*/
- public static final Threshold materializedViewsPerTable =
- new Threshold("materialized_views_per_table",
- state ->
CONFIG_PROVIDER.getOrCreate(state).getMaterializedViewsPerTableWarnThreshold(),
- state ->
CONFIG_PROVIDER.getOrCreate(state).getMaterializedViewsPerTableFailThreshold(),
- (isWarning, what, value, threshold) ->
- isWarning ? format("Creating materialized view %s, current
number of views %s exceeds warning threshold of %s.",
- what, value, threshold)
- : format("Tables cannot have more than %s
materialized views, aborting the creation of materialized view %s",
- threshold, what));
+ public static final MaxThreshold materializedViewsPerTable =
+ new MaxThreshold("materialized_views_per_table",
+ state ->
CONFIG_PROVIDER.getOrCreate(state).getMaterializedViewsPerTableWarnThreshold(),
+ state ->
CONFIG_PROVIDER.getOrCreate(state).getMaterializedViewsPerTableFailThreshold(),
+ (isWarning, what, value, threshold) ->
+ isWarning ? format("Creating materialized view %s,
current number of views %s exceeds warning threshold of %s.",
+ what, value, threshold)
+ : format("Tables cannot have more than %s
materialized views, aborting the creation of materialized view %s",
+ threshold, what));
/**
* Guardrail warning about, ignoring or rejecting the usage of certain
table properties.
@@ -169,30 +169,30 @@ public final class Guardrails implements GuardrailsMBean
/**
* Guardrail on the number of elements returned within page.
*/
- public static final Threshold pageSize =
- new Threshold("page_size",
- state ->
CONFIG_PROVIDER.getOrCreate(state).getPageSizeWarnThreshold(),
- state ->
CONFIG_PROVIDER.getOrCreate(state).getPageSizeFailThreshold(),
- (isWarning, what, value, threshold) ->
- isWarning ? format("Query for table %s with page size %s
exceeds warning threshold of %s.",
- what, value, threshold)
- : format("Aborting query for table %s, page size
%s exceeds fail threshold of %s.",
- what, value, threshold));
+ public static final MaxThreshold pageSize =
+ new MaxThreshold("page_size",
+ state ->
CONFIG_PROVIDER.getOrCreate(state).getPageSizeWarnThreshold(),
+ state ->
CONFIG_PROVIDER.getOrCreate(state).getPageSizeFailThreshold(),
+ (isWarning, what, value, threshold) ->
+ isWarning ? format("Query for table %s with page size %s
exceeds warning threshold of %s.",
+ what, value, threshold)
+ : format("Aborting query for table %s, page
size %s exceeds fail threshold of %s.",
+ what, value, threshold));
/**
* Guardrail on the number of partition keys in the IN clause.
*/
- public static final Threshold partitionKeysInSelect =
- new Threshold("partition_keys_in_select",
- state ->
CONFIG_PROVIDER.getOrCreate(state).getPartitionKeysInSelectWarnThreshold(),
- state ->
CONFIG_PROVIDER.getOrCreate(state).getPartitionKeysInSelectFailThreshold(),
- (isWarning, what, value, threshold) ->
- isWarning ? format("Query with partition keys in IN clause
on table %s, with number of " +
- "partition keys %s exceeds warning
threshold of %s.",
- what, value, threshold)
- : format("Aborting query with partition keys in IN
clause on table %s, " +
- "number of partition keys %s exceeds fail
threshold of %s.",
- what, value, threshold));
+ public static final MaxThreshold partitionKeysInSelect =
+ new MaxThreshold("partition_keys_in_select",
+ state ->
CONFIG_PROVIDER.getOrCreate(state).getPartitionKeysInSelectWarnThreshold(),
+ state ->
CONFIG_PROVIDER.getOrCreate(state).getPartitionKeysInSelectFailThreshold(),
+ (isWarning, what, value, threshold) ->
+ isWarning ? format("Query with partition keys in IN
clause on table %s, with number of " +
+ "partition keys %s exceeds warning
threshold of %s.",
+ what, value, threshold)
+ : format("Aborting query with partition keys in
IN clause on table %s, " +
+ "number of partition keys %s exceeds
fail threshold of %s.",
+ what, value, threshold));
/**
* Guardrail disabling operations on lists that require read before write.
@@ -213,17 +213,17 @@ public final class Guardrails implements GuardrailsMBean
/**
* Guardrail on the number of restrictions created by a cartesian product
of a CQL's {@code IN} query.
*/
- public static final Threshold inSelectCartesianProduct =
- new Threshold("in_select_cartesian_product",
- state ->
CONFIG_PROVIDER.getOrCreate(state).getInSelectCartesianProductWarnThreshold(),
- state ->
CONFIG_PROVIDER.getOrCreate(state).getInSelectCartesianProductFailThreshold(),
- (isWarning, what, value, threshold) ->
- isWarning ? format("The cartesian product of the IN
restrictions on %s produces %s values, " +
- "this exceeds warning threshold of %s.",
- what, value, threshold)
- : format("Aborting query because the cartesian
product of the IN restrictions on %s " +
- "produces %s values, this exceeds fail
threshold of %s.",
- what, value, threshold));
+ public static final MaxThreshold inSelectCartesianProduct =
+ new MaxThreshold("in_select_cartesian_product",
+ state ->
CONFIG_PROVIDER.getOrCreate(state).getInSelectCartesianProductWarnThreshold(),
+ state ->
CONFIG_PROVIDER.getOrCreate(state).getInSelectCartesianProductFailThreshold(),
+ (isWarning, what, value, threshold) ->
+ isWarning ? format("The cartesian product of the IN
restrictions on %s produces %s values, " +
+ "this exceeds warning threshold of
%s.",
+ what, value, threshold)
+ : format("Aborting query because the cartesian
product of the IN restrictions on %s " +
+ "produces %s values, this exceeds fail
threshold of %s.",
+ what, value, threshold));
/**
* Guardrail on read consistency levels.
@@ -248,41 +248,41 @@ public final class Guardrails implements GuardrailsMBean
/**
* Guardrail on the size of a collection.
*/
- public static final Threshold collectionSize =
- new Threshold("collection_size",
- state ->
sizeToBytes(CONFIG_PROVIDER.getOrCreate(state).getCollectionSizeWarnThreshold()),
- state ->
sizeToBytes(CONFIG_PROVIDER.getOrCreate(state).getCollectionSizeFailThreshold()),
- (isWarning, what, value, threshold) ->
- isWarning ? format("Detected collection %s of size %s, this
exceeds the warning threshold of %s.",
- what, value, threshold)
- : format("Detected collection %s of size %s, this
exceeds the failure threshold of %s.",
- what, value, threshold));
+ public static final MaxThreshold collectionSize =
+ new MaxThreshold("collection_size",
+ state ->
sizeToBytes(CONFIG_PROVIDER.getOrCreate(state).getCollectionSizeWarnThreshold()),
+ state ->
sizeToBytes(CONFIG_PROVIDER.getOrCreate(state).getCollectionSizeFailThreshold()),
+ (isWarning, what, value, threshold) ->
+ isWarning ? format("Detected collection %s of size %s,
this exceeds the warning threshold of %s.",
+ what, value, threshold)
+ : format("Detected collection %s of size %s,
this exceeds the failure threshold of %s.",
+ what, value, threshold));
/**
* Guardrail on the number of items of a collection.
*/
- public static final Threshold itemsPerCollection =
- new Threshold("items_per_collection",
- state ->
CONFIG_PROVIDER.getOrCreate(state).getItemsPerCollectionWarnThreshold(),
- state ->
CONFIG_PROVIDER.getOrCreate(state).getItemsPerCollectionFailThreshold(),
- (isWarning, what, value, threshold) ->
- isWarning ? format("Detected collection %s with %s items,
this exceeds the warning threshold of %s.",
- what, value, threshold)
- : format("Detected collection %s with %s items,
this exceeds the failure threshold of %s.",
- what, value, threshold));
+ public static final MaxThreshold itemsPerCollection =
+ new MaxThreshold("items_per_collection",
+ state ->
CONFIG_PROVIDER.getOrCreate(state).getItemsPerCollectionWarnThreshold(),
+ state ->
CONFIG_PROVIDER.getOrCreate(state).getItemsPerCollectionFailThreshold(),
+ (isWarning, what, value, threshold) ->
+ isWarning ? format("Detected collection %s with %s items,
this exceeds the warning threshold of %s.",
+ what, value, threshold)
+ : format("Detected collection %s with %s items,
this exceeds the failure threshold of %s.",
+ what, value, threshold));
/**
* Guardrail on the number of fields on each UDT.
*/
- public static final Threshold fieldsPerUDT =
- new Threshold("fields_per_udt",
- state ->
CONFIG_PROVIDER.getOrCreate(state).getFieldsPerUDTWarnThreshold(),
- state ->
CONFIG_PROVIDER.getOrCreate(state).getFieldsPerUDTFailThreshold(),
- (isWarning, what, value, threshold) ->
- isWarning ? format("The user type %s has %s columns, this
exceeds the warning threshold of %s.",
- what, value, threshold)
- : format("User types cannot have more than %s
columns, but %s provided for user type %s.",
- threshold, value, what));
+ public static final MaxThreshold fieldsPerUDT =
+ new MaxThreshold("fields_per_udt",
+ state ->
CONFIG_PROVIDER.getOrCreate(state).getFieldsPerUDTWarnThreshold(),
+ state ->
CONFIG_PROVIDER.getOrCreate(state).getFieldsPerUDTFailThreshold(),
+ (isWarning, what, value, threshold) ->
+ isWarning ? format("The user type %s has %s columns, this
exceeds the warning threshold of %s.",
+ what, value, threshold)
+ : format("User types cannot have more than %s
columns, but %s provided for user type %s.",
+ threshold, value, what));
/**
* Guardrail on the data disk usage on the local node, used by a periodic
task to calculate and propagate that status.
@@ -320,6 +320,19 @@ public final class Guardrails implements GuardrailsMBean
replicaDiskUsage.minNotifyIntervalInMs(minNotifyInterval);
}
+ /**
+ * Guardrail on the minimum replication factor.
+ */
+ public static final MinThreshold minimumReplicationFactor =
+ new MinThreshold("minimum_replication_factor",
+ state ->
CONFIG_PROVIDER.getOrCreate(state).getMinimumReplicationFactorWarnThreshold(),
+ state ->
CONFIG_PROVIDER.getOrCreate(state).getMinimumReplicationFactorFailThreshold(),
+ (isWarning, what, value, threshold) ->
+ isWarning ? format("The keyspace %s has a replication
factor of %s, below the warning threshold of %s.",
+ what, value, threshold)
+ : format("The keyspace %s has a replication
factor of %s, below the failure threshold of %s.",
+ what, value, threshold));
+
private Guardrails()
{
MBeanWrapper.instance.registerMBean(this, MBEAN_NAME);
@@ -835,6 +848,24 @@ public final class Guardrails implements GuardrailsMBean
DEFAULT_CONFIG.setDataDiskUsageMaxDiskSize(sizeFromString(size));
}
+ @Override
+ public int getMinimumReplicationFactorWarnThreshold()
+ {
+ return DEFAULT_CONFIG.getMinimumReplicationFactorWarnThreshold();
+ }
+
+ @Override
+ public int getMinimumReplicationFactorFailThreshold()
+ {
+ return DEFAULT_CONFIG.getMinimumReplicationFactorFailThreshold();
+ }
+
+ @Override
+ public void setMinimumReplicationFactorThreshold(int warn, int fail)
+ {
+ DEFAULT_CONFIG.setMinimumReplicationFactorThreshold(warn, fail);
+ }
+
private static String toCSV(Set<String> values)
{
return values == null || values.isEmpty() ? "" : String.join(",",
values);
diff --git a/src/java/org/apache/cassandra/db/guardrails/GuardrailsConfig.java
b/src/java/org/apache/cassandra/db/guardrails/GuardrailsConfig.java
index cb2bd313b9..8c9cf6b20f 100644
--- a/src/java/org/apache/cassandra/db/guardrails/GuardrailsConfig.java
+++ b/src/java/org/apache/cassandra/db/guardrails/GuardrailsConfig.java
@@ -266,4 +266,15 @@ public interface GuardrailsConfig
*/
@Nullable
DataStorageSpec getDataDiskUsageMaxDiskSize();
+
+ /**
+ * @return The threshold to warn when replication factor is lesser than
threshold.
+ */
+ int getMinimumReplicationFactorWarnThreshold();
+
+ /**
+ * @return The threshold to fail when replication factor is lesser than
threshold.
+ */
+ int getMinimumReplicationFactorFailThreshold();
+
}
diff --git a/src/java/org/apache/cassandra/db/guardrails/GuardrailsMBean.java
b/src/java/org/apache/cassandra/db/guardrails/GuardrailsMBean.java
index 0240f430a4..e109c40873 100644
--- a/src/java/org/apache/cassandra/db/guardrails/GuardrailsMBean.java
+++ b/src/java/org/apache/cassandra/db/guardrails/GuardrailsMBean.java
@@ -520,4 +520,23 @@ public interface GuardrailsMBean
* A {@code null} value means disabled.
*/
void setDataDiskUsageMaxDiskSize(@Nullable String size);
+
+ /**
+ * @return The threshold to warn when replication factor is lesser
threshold.
+ */
+ int getMinimumReplicationFactorWarnThreshold();
+
+ /**
+ * @return The threshold to fail when replication factor is lesser
threshold.
+ */
+ int getMinimumReplicationFactorFailThreshold();
+
+ /**
+ * @param warn the threshold to warn when the minimum replication factor
is lesser than
+ * threshold -1 means disabled.
+ * @param fail the threshold to fail when the minimum replication factor
is lesser than
+ * threshold -1 means disabled.
+ */
+ void setMinimumReplicationFactorThreshold (int warn, int fail);
+
}
diff --git
a/src/java/org/apache/cassandra/db/guardrails/PercentageThreshold.java
b/src/java/org/apache/cassandra/db/guardrails/MaxThreshold.java
similarity index 63%
copy from src/java/org/apache/cassandra/db/guardrails/PercentageThreshold.java
copy to src/java/org/apache/cassandra/db/guardrails/MaxThreshold.java
index c08d02641b..badaff784b 100644
--- a/src/java/org/apache/cassandra/db/guardrails/PercentageThreshold.java
+++ b/src/java/org/apache/cassandra/db/guardrails/MaxThreshold.java
@@ -19,15 +19,12 @@
package org.apache.cassandra.db.guardrails;
import java.util.function.ToLongFunction;
-
import org.apache.cassandra.service.ClientState;
/**
- * A {@link Threshold} guardrail whose values represent a percentage
- * <p>
- * This works exactly as a {@link Threshold}, but provides slightly more
convenient error messages for percentage
+ * {@link MaxThreshold} for maximum guardrails, the value is checked to see if
it is greater than the warn and fail thresholds.
*/
-public class PercentageThreshold extends Threshold
+public class MaxThreshold extends Threshold
{
/**
* Creates a new threshold guardrail.
@@ -37,20 +34,32 @@ public class PercentageThreshold extends Threshold
* @param failThreshold a {@link ClientState}-based provider of the
value above which the operation should be aborted.
* @param messageProvider a function to generate the warning or error
message if the guardrail is triggered
*/
- public PercentageThreshold(String name,
- ToLongFunction<ClientState> warnThreshold,
- ToLongFunction<ClientState> failThreshold,
- ErrorMessageProvider messageProvider)
+ public MaxThreshold(String name,
+ ToLongFunction<ClientState> warnThreshold,
+ ToLongFunction<ClientState> failThreshold,
+ Threshold.ErrorMessageProvider messageProvider)
{
super(name, warnThreshold, failThreshold, messageProvider);
}
@Override
- protected String errMsg(boolean isWarning, String what, long value, long
thresholdValue)
+ protected boolean compare(long value, long threshold)
+ {
+ return value > threshold;
+ }
+
+ @Override
+ protected long failValue(ClientState state)
{
- return messageProvider.createMessage(isWarning,
- what,
- String.format("%d%%", value),
- String.format("%d%%",
thresholdValue));
+ long failValue = failThreshold.applyAsLong(state);
+ return failValue <= 0 ? Long.MAX_VALUE : failValue;
}
+
+ @Override
+ protected long warnValue(ClientState state)
+ {
+ long warnValue = warnThreshold.applyAsLong(state);
+ return warnValue <= 0 ? Long.MAX_VALUE : warnValue;
+ }
+
}
diff --git
a/src/java/org/apache/cassandra/db/guardrails/PercentageThreshold.java
b/src/java/org/apache/cassandra/db/guardrails/MinThreshold.java
similarity index 61%
copy from src/java/org/apache/cassandra/db/guardrails/PercentageThreshold.java
copy to src/java/org/apache/cassandra/db/guardrails/MinThreshold.java
index c08d02641b..427f2777e8 100644
--- a/src/java/org/apache/cassandra/db/guardrails/PercentageThreshold.java
+++ b/src/java/org/apache/cassandra/db/guardrails/MinThreshold.java
@@ -19,38 +19,47 @@
package org.apache.cassandra.db.guardrails;
import java.util.function.ToLongFunction;
-
import org.apache.cassandra.service.ClientState;
/**
- * A {@link Threshold} guardrail whose values represent a percentage
- * <p>
- * This works exactly as a {@link Threshold}, but provides slightly more
convenient error messages for percentage
+ * {@link MinThreshold} for minimum guardrails, the value is checked to see if
it is lesser than the warn and fail thresholds.
*/
-public class PercentageThreshold extends Threshold
+public class MinThreshold extends Threshold
{
/**
- * Creates a new threshold guardrail.
+ * Creates a new minimum threshold guardrail.
*
* @param name the identifying name of the guardrail
* @param warnThreshold a {@link ClientState}-based provider of the
value above which a warning should be triggered.
* @param failThreshold a {@link ClientState}-based provider of the
value above which the operation should be aborted.
* @param messageProvider a function to generate the warning or error
message if the guardrail is triggered
*/
- public PercentageThreshold(String name,
- ToLongFunction<ClientState> warnThreshold,
- ToLongFunction<ClientState> failThreshold,
- ErrorMessageProvider messageProvider)
+ public MinThreshold(String name,
+ ToLongFunction<ClientState> warnThreshold,
+ ToLongFunction<ClientState> failThreshold,
+ Threshold.ErrorMessageProvider messageProvider)
{
super(name, warnThreshold, failThreshold, messageProvider);
}
@Override
- protected String errMsg(boolean isWarning, String what, long value, long
thresholdValue)
+ protected boolean compare(long value, long threshold)
+ {
+ return value < threshold;
+ }
+
+ @Override
+ protected long failValue(ClientState state)
{
- return messageProvider.createMessage(isWarning,
- what,
- String.format("%d%%", value),
- String.format("%d%%",
thresholdValue));
+ long failValue = failThreshold.applyAsLong(state);
+ return failValue <= 0 ? Long.MIN_VALUE : failValue;
}
+
+ @Override
+ protected long warnValue(ClientState state)
+ {
+ long warnValue = warnThreshold.applyAsLong(state);
+ return warnValue <= 0 ? Long.MIN_VALUE : warnValue;
+ }
+
}
diff --git
a/src/java/org/apache/cassandra/db/guardrails/PercentageThreshold.java
b/src/java/org/apache/cassandra/db/guardrails/PercentageThreshold.java
index c08d02641b..6f866c6ec0 100644
--- a/src/java/org/apache/cassandra/db/guardrails/PercentageThreshold.java
+++ b/src/java/org/apache/cassandra/db/guardrails/PercentageThreshold.java
@@ -27,7 +27,7 @@ import org.apache.cassandra.service.ClientState;
* <p>
* This works exactly as a {@link Threshold}, but provides slightly more
convenient error messages for percentage
*/
-public class PercentageThreshold extends Threshold
+public class PercentageThreshold extends MaxThreshold
{
/**
* Creates a new threshold guardrail.
diff --git a/src/java/org/apache/cassandra/db/guardrails/Threshold.java
b/src/java/org/apache/cassandra/db/guardrails/Threshold.java
index f7e4823448..b671907c62 100644
--- a/src/java/org/apache/cassandra/db/guardrails/Threshold.java
+++ b/src/java/org/apache/cassandra/db/guardrails/Threshold.java
@@ -26,15 +26,15 @@ import org.apache.cassandra.service.ClientState;
/**
* A guardrail based on numeric threshold(s).
*
- * <p>A {@link Threshold} guardrail defines (up to) 2 thresholds, one at which
a warning is issued, and a higher one
+ * <p>A {@link Threshold} guardrail defines (up to) 2 thresholds, one at which
a warning is issued, and a lower one
* at which the operation is aborted with an exception. Only one of those
thresholds can be activated if desired.
*
* <p>This guardrail only handles guarding positive values.
*/
-public class Threshold extends Guardrail
+public abstract class Threshold extends Guardrail
{
- private final ToLongFunction<ClientState> warnThreshold;
- private final ToLongFunction<ClientState> failThreshold;
+ protected ToLongFunction<ClientState> warnThreshold;
+ protected ToLongFunction<ClientState> failThreshold;
protected final ErrorMessageProvider messageProvider;
/**
@@ -56,6 +56,8 @@ public class Threshold extends Guardrail
this.messageProvider = messageProvider;
}
+ protected abstract boolean compare(long value, long threshold);
+
protected String errMsg(boolean isWarning, String what, long value, long
thresholdValue)
{
return messageProvider.createMessage(isWarning,
@@ -69,19 +71,10 @@ public class Threshold extends Guardrail
return errMsg(isWarning, REDACTED, value, thresholdValue);
}
- private long failValue(ClientState state)
- {
- long failValue = failThreshold.applyAsLong(state);
- return failValue <= 0 ? Long.MAX_VALUE : failValue;
- }
+ protected abstract long failValue(ClientState state);
- private long warnValue(ClientState state)
- {
- long warnValue = warnThreshold.applyAsLong(state);
- return warnValue <= 0 ? Long.MAX_VALUE : warnValue;
- }
+ protected abstract long warnValue(ClientState state);
- @Override
public boolean enabled(@Nullable ClientState state)
{
if (!super.enabled(state))
@@ -105,17 +98,17 @@ public class Threshold extends Guardrail
*/
public boolean triggersOn(long value, @Nullable ClientState state)
{
- return enabled(state) && (value > Math.min(failValue(state),
warnValue(state)));
+ return enabled(state) && (compare(value, warnValue(state)) ||
compare(value, failValue(state)));
}
public boolean warnsOn(long value, @Nullable ClientState state)
{
- return enabled(state) && (value > warnValue(state) && value <=
failValue(state));
+ return enabled(state) && compare(value, warnValue(state));
}
public boolean failsOn(long value, @Nullable ClientState state)
{
- return enabled(state) && (value > failValue(state));
+ return enabled(state) && compare(value, failValue(state));
}
/**
@@ -136,14 +129,14 @@ public class Threshold extends Guardrail
return;
long failValue = failValue(state);
- if (value > failValue)
+ if (compare(value, failValue))
{
triggerFail(value, failValue, what, containsUserData, state);
return;
}
long warnValue = warnValue(state);
- if (value > warnValue)
+ if (compare(value, warnValue))
triggerWarn(value, warnValue, what, containsUserData);
}
@@ -175,4 +168,4 @@ public class Threshold extends Guardrail
*/
String createMessage(boolean isWarning, String what, String value,
String threshold);
}
-}
+}
\ No newline at end of file
diff --git
a/src/java/org/apache/cassandra/locator/AbstractReplicationStrategy.java
b/src/java/org/apache/cassandra/locator/AbstractReplicationStrategy.java
index 7f33c578ae..c233fc0fbc 100644
--- a/src/java/org/apache/cassandra/locator/AbstractReplicationStrategy.java
+++ b/src/java/org/apache/cassandra/locator/AbstractReplicationStrategy.java
@@ -41,6 +41,7 @@ import org.apache.cassandra.dht.Token;
import org.apache.cassandra.exceptions.ConfigurationException;
import org.apache.cassandra.locator.ReplicaCollection.Builder.Conflict;
import org.apache.cassandra.service.AbstractWriteResponseHandler;
+import org.apache.cassandra.service.ClientState;
import org.apache.cassandra.service.DatacenterSyncWriteResponseHandler;
import org.apache.cassandra.service.DatacenterWriteResponseHandler;
import org.apache.cassandra.service.WriteResponseHandler;
@@ -286,7 +287,17 @@ public abstract class AbstractReplicationStrategy
public abstract void validateOptions() throws ConfigurationException;
- public abstract void maybeWarnOnOptions();
+ @Deprecated // use #maybeWarnOnOptions(ClientState) instead
+ public void maybeWarnOnOptions()
+ {
+ // nothing to do here
+ }
+
+ public void maybeWarnOnOptions(ClientState state)
+ {
+ maybeWarnOnOptions();
+ }
+
/*
* The options recognized by the strategy.
@@ -384,12 +395,13 @@ public abstract class AbstractReplicationStrategy
Class<? extends
AbstractReplicationStrategy> strategyClass,
TokenMetadata tokenMetadata,
IEndpointSnitch snitch,
- Map<String, String>
strategyOptions) throws ConfigurationException
+ Map<String, String>
strategyOptions,
+ ClientState state) throws
ConfigurationException
{
AbstractReplicationStrategy strategy = createInternal(keyspaceName,
strategyClass, tokenMetadata, snitch, strategyOptions);
strategy.validateExpectedOptions();
strategy.validateOptions();
- strategy.maybeWarnOnOptions();
+ strategy.maybeWarnOnOptions(state);
if (strategy.hasTransientReplicas() &&
!DatabaseDescriptor.isTransientReplicationEnabled())
{
throw new ConfigurationException("Transient replication is
disabled. Enable in cassandra.yaml to use.");
@@ -421,12 +433,7 @@ public abstract class AbstractReplicationStrategy
try
{
ReplicationFactor rf = ReplicationFactor.fromString(s);
-
- if (rf.fullReplicas < DatabaseDescriptor.getMinimumKeyspaceRF())
- {
- throw new ConfigurationException(String.format("Replication
factor cannot be less than minimum_keyspace_rf (%d), found %d",
DatabaseDescriptor.getMinimumKeyspaceRF(), rf.fullReplicas));
- }
-
+
if (rf.hasTransientReplicas())
{
if (DatabaseDescriptor.getNumTokens() > 1)
diff --git a/src/java/org/apache/cassandra/locator/NetworkTopologyStrategy.java
b/src/java/org/apache/cassandra/locator/NetworkTopologyStrategy.java
index dd2ec99d9b..9ae034121a 100644
--- a/src/java/org/apache/cassandra/locator/NetworkTopologyStrategy.java
+++ b/src/java/org/apache/cassandra/locator/NetworkTopologyStrategy.java
@@ -21,6 +21,7 @@ import java.util.*;
import java.util.Map.Entry;
import org.apache.cassandra.config.DatabaseDescriptor;
+import org.apache.cassandra.db.guardrails.Guardrails;
import org.apache.cassandra.locator.ReplicaCollection.Builder.Conflict;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -31,6 +32,7 @@ import org.apache.cassandra.exceptions.ConfigurationException;
import org.apache.cassandra.dht.Token;
import org.apache.cassandra.locator.TokenMetadata.Topology;
import org.apache.cassandra.schema.SchemaConstants;
+import org.apache.cassandra.service.ClientState;
import org.apache.cassandra.service.ClientWarn;
import org.apache.cassandra.service.StorageService;
import org.apache.cassandra.utils.FBUtilities;
@@ -336,7 +338,7 @@ public class NetworkTopologyStrategy extends
AbstractReplicationStrategy
}
@Override
- public void maybeWarnOnOptions()
+ public void maybeWarnOnOptions(ClientState state)
{
if (!SchemaConstants.isSystemKeyspace(keyspaceName))
{
@@ -347,6 +349,7 @@ public class NetworkTopologyStrategy extends
AbstractReplicationStrategy
String dc = e.getKey();
ReplicationFactor rf = getReplicationFactor(dc);
+ Guardrails.minimumReplicationFactor.guard(rf.fullReplicas,
keyspaceName, false, state);
int nodeCount = dcsNodes.get(dc).size();
// nodeCount==0 on many tests
if (rf.fullReplicas > nodeCount && nodeCount != 0)
diff --git a/src/java/org/apache/cassandra/locator/SimpleStrategy.java
b/src/java/org/apache/cassandra/locator/SimpleStrategy.java
index 1a578e9506..e5b92103b4 100644
--- a/src/java/org/apache/cassandra/locator/SimpleStrategy.java
+++ b/src/java/org/apache/cassandra/locator/SimpleStrategy.java
@@ -27,10 +27,12 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.apache.cassandra.config.DatabaseDescriptor;
+import org.apache.cassandra.db.guardrails.Guardrails;
import org.apache.cassandra.dht.Range;
import org.apache.cassandra.dht.Token;
import org.apache.cassandra.exceptions.ConfigurationException;
import org.apache.cassandra.schema.SchemaConstants;
+import org.apache.cassandra.service.ClientState;
import org.apache.cassandra.service.ClientWarn;
import org.apache.cassandra.service.StorageService;
@@ -100,12 +102,13 @@ public class SimpleStrategy extends
AbstractReplicationStrategy
}
@Override
- public void maybeWarnOnOptions()
+ public void maybeWarnOnOptions(ClientState state)
{
if (!SchemaConstants.isSystemKeyspace(keyspaceName))
{
int nodeCount =
StorageService.instance.getHostIdToEndpoint().size();
// nodeCount==0 on many tests
+ Guardrails.minimumReplicationFactor.guard(rf.fullReplicas,
keyspaceName, false, state);
if (rf.fullReplicas > nodeCount && nodeCount != 0)
{
String msg = "Your replication factor " + rf.fullReplicas
diff --git a/src/java/org/apache/cassandra/schema/KeyspaceMetadata.java
b/src/java/org/apache/cassandra/schema/KeyspaceMetadata.java
index 7978854e31..6d85391d30 100644
--- a/src/java/org/apache/cassandra/schema/KeyspaceMetadata.java
+++ b/src/java/org/apache/cassandra/schema/KeyspaceMetadata.java
@@ -308,7 +308,7 @@ public final class KeyspaceMetadata implements SchemaElement
name));
}
- params.validate(name);
+ params.validate(name, null);
tablesAndViews().forEach(TableMetadata::validate);
diff --git a/src/java/org/apache/cassandra/schema/KeyspaceParams.java
b/src/java/org/apache/cassandra/schema/KeyspaceParams.java
index cc464743ff..539993e2b3 100644
--- a/src/java/org/apache/cassandra/schema/KeyspaceParams.java
+++ b/src/java/org/apache/cassandra/schema/KeyspaceParams.java
@@ -23,6 +23,8 @@ import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.MoreObjects;
import com.google.common.base.Objects;
+import org.apache.cassandra.service.ClientState;
+
/**
* An immutable class representing keyspace parameters (durability and
replication).
*/
@@ -89,9 +91,9 @@ public final class KeyspaceParams
return new KeyspaceParams(true, ReplicationParams.nts(args));
}
- public void validate(String name)
+ public void validate(String name, ClientState state)
{
- replication.validate(name);
+ replication.validate(name, state);
}
@Override
diff --git a/src/java/org/apache/cassandra/schema/ReplicationParams.java
b/src/java/org/apache/cassandra/schema/ReplicationParams.java
index 8fbf1cd822..2998aa57ad 100644
--- a/src/java/org/apache/cassandra/schema/ReplicationParams.java
+++ b/src/java/org/apache/cassandra/schema/ReplicationParams.java
@@ -27,6 +27,7 @@ import com.google.common.collect.ImmutableMap;
import org.apache.cassandra.config.DatabaseDescriptor;
import org.apache.cassandra.cql3.CqlBuilder;
import org.apache.cassandra.locator.*;
+import org.apache.cassandra.service.ClientState;
import org.apache.cassandra.service.StorageService;
public final class ReplicationParams
@@ -70,12 +71,12 @@ public final class ReplicationParams
return new ReplicationParams(NetworkTopologyStrategy.class, options);
}
- public void validate(String name)
+ public void validate(String name, ClientState state)
{
// Attempt to instantiate the ARS, which will throw a
ConfigurationException if the options aren't valid.
TokenMetadata tmd = StorageService.instance.getTokenMetadata();
IEndpointSnitch eps = DatabaseDescriptor.getEndpointSnitch();
- AbstractReplicationStrategy.validateReplicationStrategy(name, klass,
tmd, eps, options);
+ AbstractReplicationStrategy.validateReplicationStrategy(name, klass,
tmd, eps, options, state);
}
public static ReplicationParams fromMap(Map<String, String> map) {
diff --git a/src/java/org/apache/cassandra/service/StorageService.java
b/src/java/org/apache/cassandra/service/StorageService.java
index 60df67e934..d5cd898c35 100644
--- a/src/java/org/apache/cassandra/service/StorageService.java
+++ b/src/java/org/apache/cassandra/service/StorageService.java
@@ -6505,17 +6505,6 @@ public class StorageService extends
NotificationBroadcasterSupport implements IE
return DatabaseDescriptor.getDefaultKeyspaceRF();
}
- public void setMinimumKeyspaceReplicationFactor(int value)
- {
- DatabaseDescriptor.setMinimumKeyspaceRF(value);
- logger.info("set minimum keyspace rf to {}", value);
- }
-
- public int getMinimumKeyspaceReplicationFactor()
- {
- return DatabaseDescriptor.getMinimumKeyspaceRF();
- }
-
public boolean getSkipPaxosRepairOnTopologyChange()
{
return DatabaseDescriptor.skipPaxosRepairOnTopologyChange();
diff --git a/src/java/org/apache/cassandra/service/StorageServiceMBean.java
b/src/java/org/apache/cassandra/service/StorageServiceMBean.java
index dd8f93fd31..fc198c817d 100644
--- a/src/java/org/apache/cassandra/service/StorageServiceMBean.java
+++ b/src/java/org/apache/cassandra/service/StorageServiceMBean.java
@@ -945,8 +945,6 @@ public interface StorageServiceMBean extends
NotificationEmitter
public void setDefaultKeyspaceReplicationFactor(int value);
public int getDefaultKeyspaceReplicationFactor();
- public void setMinimumKeyspaceReplicationFactor(int value);
- public int getMinimumKeyspaceReplicationFactor();
boolean getSkipPaxosRepairOnTopologyChange();
void setSkipPaxosRepairOnTopologyChange(boolean v);
diff --git a/src/java/org/apache/cassandra/tools/NodeProbe.java
b/src/java/org/apache/cassandra/tools/NodeProbe.java
index c9c81a874a..e25938aa26 100644
--- a/src/java/org/apache/cassandra/tools/NodeProbe.java
+++ b/src/java/org/apache/cassandra/tools/NodeProbe.java
@@ -2038,16 +2038,6 @@ public class NodeProbe implements AutoCloseable
{
return ssProxy.getDefaultKeyspaceReplicationFactor();
}
-
- public void setMinimumKeyspaceReplicationFactor(int value)
- {
- ssProxy.setMinimumKeyspaceReplicationFactor(value);
- }
-
- public int getMinimumKeyspaceReplicationFactor()
- {
- return ssProxy.getMinimumKeyspaceReplicationFactor();
- }
}
class ColumnFamilyStoreMBeanIterator implements Iterator<Map.Entry<String,
ColumnFamilyStoreMBean>>
diff --git a/src/java/org/apache/cassandra/tools/NodeTool.java
b/src/java/org/apache/cassandra/tools/NodeTool.java
index 476353fee0..8d87c88906 100644
--- a/src/java/org/apache/cassandra/tools/NodeTool.java
+++ b/src/java/org/apache/cassandra/tools/NodeTool.java
@@ -144,7 +144,6 @@ public class NodeTool
GetInterDCStreamThroughput.class,
GetLoggingLevels.class,
GetMaxHintWindow.class,
- GetMinimumKeyspaceRF.class,
GetSSTables.class,
GetSeeds.class,
GetSnapshotThrottle.class,
@@ -204,7 +203,6 @@ public class NodeTool
SetInterDCStreamThroughput.class,
SetLoggingLevel.class,
SetMaxHintWindow.class,
- SetMinimumKeyspaceRF.class,
SetSnapshotThrottle.class,
SetStreamThroughput.class,
SetTimeout.class,
diff --git
a/src/java/org/apache/cassandra/tools/nodetool/GetMinimumKeyspaceRF.java
b/src/java/org/apache/cassandra/tools/nodetool/GetMinimumKeyspaceRF.java
deleted file mode 100644
index 2de94f5f1a..0000000000
--- a/src/java/org/apache/cassandra/tools/nodetool/GetMinimumKeyspaceRF.java
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * 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.tools.nodetool;
-
-import io.airlift.airline.Arguments;
-import io.airlift.airline.Command;
-import org.apache.cassandra.tools.NodeProbe;
-import org.apache.cassandra.tools.NodeTool;
-
-@Command(name = "getminimumrf", description = "Gets minimum keyspace
replication factor.")
-public class GetMinimumKeyspaceRF extends NodeTool.NodeToolCmd
-{
- protected void execute(NodeProbe probe)
- {
-
probe.output().out.println(probe.getMinimumKeyspaceReplicationFactor());
- }
-}
diff --git
a/src/java/org/apache/cassandra/tools/nodetool/SetMinimumKeyspaceRF.java
b/src/java/org/apache/cassandra/tools/nodetool/SetMinimumKeyspaceRF.java
deleted file mode 100644
index 92ab7b72f5..0000000000
--- a/src/java/org/apache/cassandra/tools/nodetool/SetMinimumKeyspaceRF.java
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * 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.tools.nodetool;
-
-import io.airlift.airline.Arguments;
-import io.airlift.airline.Command;
-import org.apache.cassandra.tools.NodeProbe;
-import org.apache.cassandra.tools.NodeTool;
-
-@Command(name = "setminimumrf", description = "Sets minimum keyspace
replication factor.")
-public class SetMinimumKeyspaceRF extends NodeTool.NodeToolCmd
-{
- @Arguments(title = "minimum_rf", usage = "<value>", description = "Minimum
replication factor", required = true)
- private Integer minimumRF = null;
-
- protected void execute(NodeProbe probe)
- {
- probe.setMinimumKeyspaceReplicationFactor(minimumRF);
- }
-}
diff --git
a/test/unit/org/apache/cassandra/config/DatabaseDescriptorRefTest.java
b/test/unit/org/apache/cassandra/config/DatabaseDescriptorRefTest.java
index c1e771be9f..011b322cba 100644
--- a/test/unit/org/apache/cassandra/config/DatabaseDescriptorRefTest.java
+++ b/test/unit/org/apache/cassandra/config/DatabaseDescriptorRefTest.java
@@ -98,14 +98,11 @@ public class DatabaseDescriptorRefTest
"org.apache.cassandra.db.guardrails.GuardrailsConfig",
"org.apache.cassandra.db.guardrails.GuardrailsConfigMBean",
"org.apache.cassandra.db.guardrails.GuardrailsConfig$ConsistencyLevels",
- "org.apache.cassandra.db.guardrails.GuardrailsConfig$IntThreshold",
"org.apache.cassandra.db.guardrails.GuardrailsConfig$TableProperties",
"org.apache.cassandra.config.GuardrailsOptions",
"org.apache.cassandra.config.GuardrailsOptions$Config",
"org.apache.cassandra.config.GuardrailsOptions$ConsistencyLevels",
- "org.apache.cassandra.config.GuardrailsOptions$IntThreshold",
"org.apache.cassandra.config.GuardrailsOptions$TableProperties",
- "org.apache.cassandra.config.GuardrailsOptions$Threshold",
"org.apache.cassandra.config.ReplicaFilteringProtectionOptions",
"org.apache.cassandra.config.YamlConfigurationLoader",
"org.apache.cassandra.config.YamlConfigurationLoader$PropertiesChecker",
@@ -114,8 +111,6 @@ public class DatabaseDescriptorRefTest
"org.apache.cassandra.config.TransparentDataEncryptionOptions",
"org.apache.cassandra.config.SubnetGroups",
"org.apache.cassandra.config.TrackWarnings",
- "org.apache.cassandra.config.TrackWarnings$LongByteThreshold",
- "org.apache.cassandra.config.TrackWarnings$IntByteThreshold",
"org.apache.cassandra.db.ConsistencyLevel",
"org.apache.cassandra.db.commitlog.CommitLogSegmentManagerFactory",
"org.apache.cassandra.db.commitlog.DefaultCommitLogSegmentMgrFactory",
@@ -124,7 +119,6 @@ public class DatabaseDescriptorRefTest
"org.apache.cassandra.db.commitlog.CommitLogSegmentManagerStandard",
"org.apache.cassandra.db.commitlog.CommitLog",
"org.apache.cassandra.db.commitlog.CommitLogMBean",
- "org.apache.cassandra.db.guardrails.Threshold$Config",
"org.apache.cassandra.db.guardrails.Values$Config",
"org.apache.cassandra.dht.IPartitioner",
"org.apache.cassandra.distributed.api.IInstance",
diff --git a/test/unit/org/apache/cassandra/config/DatabaseDescriptorTest.java
b/test/unit/org/apache/cassandra/config/DatabaseDescriptorTest.java
index aedaf49991..32f80579e3 100644
--- a/test/unit/org/apache/cassandra/config/DatabaseDescriptorTest.java
+++ b/test/unit/org/apache/cassandra/config/DatabaseDescriptorTest.java
@@ -756,24 +756,4 @@ public class DatabaseDescriptorTest
{
DatabaseDescriptor.setDefaultKeyspaceRF(0);
}
-
- @Test (expected = ConfigurationException.class)
- public void testInvalidSub0MinimumRFs() throws ConfigurationException
- {
- DatabaseDescriptor.setMinimumKeyspaceRF(-1);
- }
-
- @Test (expected = ConfigurationException.class)
- public void testDefaultRfLessThanMinRF()
- {
- DatabaseDescriptor.setMinimumKeyspaceRF(2);
- DatabaseDescriptor.setDefaultKeyspaceRF(1);
- }
-
- @Test (expected = ConfigurationException.class)
- public void testMinimumRfGreaterThanDefaultRF()
- {
- DatabaseDescriptor.setDefaultKeyspaceRF(1);
- DatabaseDescriptor.setMinimumKeyspaceRF(2);
- }
}
diff --git
a/test/unit/org/apache/cassandra/cql3/validation/operations/AlterTest.java
b/test/unit/org/apache/cassandra/cql3/validation/operations/AlterTest.java
index a394d9593b..c4a376648d 100644
--- a/test/unit/org/apache/cassandra/cql3/validation/operations/AlterTest.java
+++ b/test/unit/org/apache/cassandra/cql3/validation/operations/AlterTest.java
@@ -435,30 +435,6 @@ public class AlterTest extends CQLTester
execute(String.format("DROP KEYSPACE IF EXISTS %s", ks6));
}
- @Test
- public void testMinimumRF() throws Throwable
- {
- DatabaseDescriptor.setDefaultKeyspaceRF(3);
- DatabaseDescriptor.setMinimumKeyspaceRF(2);
-
- String ks1 = createKeyspace("CREATE KEYSPACE %s WITH replication={
'class' : 'SimpleStrategy' }");
- String ks2 = createKeyspace("CREATE KEYSPACE %s WITH replication={
'class' : 'NetworkTopologyStrategy' }");
-
- assertAlterTableThrowsException(ConfigurationException.class,
- String.format("Replication factor
cannot be less than minimum_keyspace_rf (%s), found %s",
DatabaseDescriptor.getMinimumKeyspaceRF(), "1"),
- String.format("ALTER KEYSPACE %s WITH
replication={ 'class' : 'SimpleStrategy', 'replication_factor' : 1 }", ks1));
- assertAlterTableThrowsException(ConfigurationException.class,
- String.format("Replication factor
cannot be less than minimum_keyspace_rf (%s), found %s",
DatabaseDescriptor.getMinimumKeyspaceRF(), "1"),
- String.format("ALTER KEYSPACE %s WITH
replication={ 'class' : 'NetworkTopologyStrategy', '" + DATA_CENTER + "' : '1'
}", ks2));
-
- //clean up config change
- DatabaseDescriptor.setMinimumKeyspaceRF(0);
- DatabaseDescriptor.setDefaultKeyspaceRF(1);
-
- //clean up keyspaces
- execute(String.format("DROP KEYSPACE IF EXISTS %s", ks1));
- execute(String.format("DROP KEYSPACE IF EXISTS %s", ks2));
- }
/**
* Test {@link ConfigurationException} thrown when altering a keyspace to
invalid DC option in replication configuration.
diff --git
a/test/unit/org/apache/cassandra/cql3/validation/operations/CreateTest.java
b/test/unit/org/apache/cassandra/cql3/validation/operations/CreateTest.java
index b1a5c6b86c..0773c97531 100644
--- a/test/unit/org/apache/cassandra/cql3/validation/operations/CreateTest.java
+++ b/test/unit/org/apache/cassandra/cql3/validation/operations/CreateTest.java
@@ -738,26 +738,4 @@ public class CreateTest extends CQLTester
}
}
- @Test
- public void testMinimumRF()
- {
- try
- {
- DatabaseDescriptor.setDefaultKeyspaceRF(3);
- DatabaseDescriptor.setMinimumKeyspaceRF(2);
-
- assertThrowsConfigurationException(
- String.format("Replication factor cannot be less than
minimum_keyspace_rf (%s), found %s", DatabaseDescriptor.getMinimumKeyspaceRF(),
"1"),
- "CREATE KEYSPACE ks1 WITH replication={ 'class' :
'SimpleStrategy', 'replication_factor' : 1 }");
-
- assertThrowsConfigurationException(
- String.format("Replication factor cannot be less than
minimum_keyspace_rf (%s), found %s", DatabaseDescriptor.getMinimumKeyspaceRF(),
"1"),
- "CREATE KEYSPACE ks2 WITH replication={ 'class' :
'NetworkTopologyStrategy', 'replication_factor' : 1 }");
- }
- finally
- {
- DatabaseDescriptor.setMinimumKeyspaceRF(0);
- DatabaseDescriptor.setDefaultKeyspaceRF(1);
- }
- }
}
diff --git
a/test/unit/org/apache/cassandra/db/guardrails/GuardrailColumnsPerTableTest.java
b/test/unit/org/apache/cassandra/db/guardrails/GuardrailColumnsPerTableTest.java
index ca0c41d724..0c473353ee 100644
---
a/test/unit/org/apache/cassandra/db/guardrails/GuardrailColumnsPerTableTest.java
+++
b/test/unit/org/apache/cassandra/db/guardrails/GuardrailColumnsPerTableTest.java
@@ -140,7 +140,7 @@ public class GuardrailColumnsPerTableTest extends
ThresholdTester
private void assertCreateTableValid(String query) throws Throwable
{
- assertThresholdValid(format(query, keyspace() + '.' +
createTableName()));
+ assertMaxThresholdValid(format(query, keyspace() + '.' +
createTableName()));
}
private void assertDropColumnValid(String query) throws Throwable
diff --git
a/test/unit/org/apache/cassandra/db/guardrails/GuardrailKeyspacesTest.java
b/test/unit/org/apache/cassandra/db/guardrails/GuardrailKeyspacesTest.java
index 2c5b3d5fba..6c600933b7 100644
--- a/test/unit/org/apache/cassandra/db/guardrails/GuardrailKeyspacesTest.java
+++ b/test/unit/org/apache/cassandra/db/guardrails/GuardrailKeyspacesTest.java
@@ -82,7 +82,7 @@ public class GuardrailKeyspacesTest extends ThresholdTester
private String assertCreateKeyspaceValid() throws Throwable
{
String keyspaceName = createKeyspaceName();
- assertThresholdValid(createKeyspaceQuery(keyspaceName));
+ assertMaxThresholdValid(createKeyspaceQuery(keyspaceName));
return keyspaceName;
}
diff --git
a/test/unit/org/apache/cassandra/db/guardrails/GuardrailMinimumReplicationFactorTest.java
b/test/unit/org/apache/cassandra/db/guardrails/GuardrailMinimumReplicationFactorTest.java
new file mode 100644
index 0000000000..16d201e1df
--- /dev/null
+++
b/test/unit/org/apache/cassandra/db/guardrails/GuardrailMinimumReplicationFactorTest.java
@@ -0,0 +1,277 @@
+/*
+ * 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.guardrails;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.UUID;
+import java.util.stream.Collectors;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import org.apache.cassandra.ServerTestUtils;
+import org.apache.cassandra.config.DatabaseDescriptor;
+import org.apache.cassandra.db.Keyspace;
+import org.apache.cassandra.exceptions.ConfigurationException;
+import org.apache.cassandra.locator.AbstractEndpointSnitch;
+import org.apache.cassandra.locator.IEndpointSnitch;
+import org.apache.cassandra.locator.InetAddressAndPort;
+import org.apache.cassandra.locator.Replica;
+import org.apache.cassandra.service.ClientWarn;
+import org.apache.cassandra.service.StorageService;
+import org.assertj.core.api.Assertions;
+
+import static java.lang.String.format;
+import static org.junit.Assert.assertNotNull;
+
+public class GuardrailMinimumReplicationFactorTest extends ThresholdTester
+{
+ private static final int MINIMUM_REPLICATION_FACTOR_WARN_THRESHOLD = 4;
+ private static int MINIMUM_REPLICATION_FACTOR_FAIL_THRESHOLD = 1;
+ private static final int DEFAULT_REPLICATION_FACTOR = 2;
+ private static final int DISABLED_GUARDRAIL = -1;
+ private static final String WHAT = "minimum_replication_factor";
+ private static final String DATACENTER1 = "datacenter1";
+ private static final String KS = "ks";
+ private final TriConsumer<Guardrails, Integer, Integer> setter;
+
+ public GuardrailMinimumReplicationFactorTest()
+ {
+ super(MINIMUM_REPLICATION_FACTOR_WARN_THRESHOLD,
+ MINIMUM_REPLICATION_FACTOR_FAIL_THRESHOLD,
+ Guardrails.minimumReplicationFactor,
+ Guardrails::setMinimumReplicationFactorThreshold,
+ Guardrails::getMinimumReplicationFactorWarnThreshold,
+ Guardrails::getMinimumReplicationFactorFailThreshold);
+
+ this.setter = Guardrails::setMinimumReplicationFactorThreshold;
+ }
+
+ @Before
+ public void setupTest() throws Throwable
+ {
+ DatabaseDescriptor.setDefaultKeyspaceRF(DEFAULT_REPLICATION_FACTOR);
+ MINIMUM_REPLICATION_FACTOR_FAIL_THRESHOLD = 2;
+ }
+
+ @After
+ public void cleanupTest() throws Throwable
+ {
+ execute("DROP KEYSPACE IF EXISTS ks");
+ }
+
+ @Override
+ protected long currentValue()
+ {
+ return
Long.parseLong((Keyspace.open(KS).getReplicationStrategy()).configOptions.get(DATACENTER1));
+ }
+
+ @Override
+ protected List<String> getWarnings()
+ {
+ List<String> warnings = ClientWarn.instance.getWarnings();
+
+ return warnings == null
+ ? Collections.emptyList()
+ : warnings.stream()
+ .filter(w -> !w.contains("keyspace ks is higher than
the number of nodes 1 for datacenter") &&
+ !w.contains("When increasing replication
factor you need to run a full (-full) repair to distribute the data") &&
+ !w.contains("keyspace ks is higher than
the number of nodes") &&
+ !w.contains("Your replication factor 4
for keyspace ks is higher than the number of nodes 2 for datacenter
datacenter2"))
+ .collect(Collectors.toList());
+ }
+
+ @Test
+ public void testConfigValidation()
+ {
+ assertNotNull(guardrail);
+ setter.accept(guardrails(), DISABLED_GUARDRAIL, DISABLED_GUARDRAIL);
+
+ assertInvalidPositiveIntProperty((g, a) -> setter.accept(g,
DISABLED_GUARDRAIL, a), Integer.MIN_VALUE, Integer.MAX_VALUE, WHAT +
"_fail_threshold");
+ assertInvalidPositiveIntProperty((g, a) -> setter.accept(g,
DISABLED_GUARDRAIL, a), -2, Integer.MAX_VALUE, WHAT + "_fail_threshold");
+ assertValidProperty((g, a) -> setter.accept(g, DISABLED_GUARDRAIL, a),
DISABLED_GUARDRAIL);
+ assertInvalidPositiveIntProperty((g, a) -> setter.accept(g,
DISABLED_GUARDRAIL, a), 0, Integer.MAX_VALUE, WHAT + "_fail_threshold");
+ assertValidProperty((g, a) -> setter.accept(g, DISABLED_GUARDRAIL, a),
1);
+ assertValidProperty((g, a) -> setter.accept(g, DISABLED_GUARDRAIL, a),
2);
+
+ assertInvalidPositiveIntProperty((g, w) -> setter.accept(g, w,
DISABLED_GUARDRAIL), Integer.MIN_VALUE, Integer.MAX_VALUE, WHAT +
"_warn_threshold");
+ assertInvalidPositiveIntProperty((g, w) -> setter.accept(g, w,
DISABLED_GUARDRAIL), -2, Integer.MAX_VALUE, WHAT + "_warn_threshold");
+ assertValidProperty((g, w) -> setter.accept(g, w, DISABLED_GUARDRAIL),
DISABLED_GUARDRAIL);
+ assertInvalidPositiveIntProperty((g, w) -> setter.accept(g, w,
DISABLED_GUARDRAIL), 0, Integer.MAX_VALUE, WHAT + "_warn_threshold");
+ assertValidProperty((g, w) -> setter.accept(g, w, DISABLED_GUARDRAIL),
1);
+ assertValidProperty((g, w) -> setter.accept(g, w, DISABLED_GUARDRAIL),
2);
+
+ Assertions.assertThatThrownBy(() -> setter.accept(guardrails(), 1, 2))
+ .hasMessageContaining(guardrail.name + "_warn_threshold
should be greater than the fail threshold");
+ }
+
+ @Test
+ public void testMinKeyspaceRFDisabled() throws Throwable
+ {
+ guardrails().setMinimumReplicationFactorThreshold(DISABLED_GUARDRAIL,
DISABLED_GUARDRAIL);
+ assertMinThresholdValid("CREATE KEYSPACE ks WITH replication = {
'class': 'NetworkTopologyStrategy', 'datacenter1': 1}");
+ assertMinThresholdValid("ALTER KEYSPACE ks WITH replication = {
'class' : 'NetworkTopologyStrategy', 'datacenter1': 3}");
+ }
+
+ @Test
+ public void testSimpleStrategy() throws Throwable
+ {
+
guardrails().setMinimumReplicationFactorThreshold(MINIMUM_REPLICATION_FACTOR_WARN_THRESHOLD,
MINIMUM_REPLICATION_FACTOR_FAIL_THRESHOLD);
+ assertWarns("CREATE KEYSPACE ks WITH replication = { 'class':
'SimpleStrategy', 'replication_factor': 3}",
+ format("The keyspace %s has a replication factor of 3,
below the warning threshold of %s.", KS,
MINIMUM_REPLICATION_FACTOR_WARN_THRESHOLD));
+ assertFails("ALTER KEYSPACE ks WITH replication = { 'class':
'SimpleStrategy', 'replication_factor': 1}",
+ format("The keyspace %s has a replication factor of 1,
below the failure threshold of %s.", KS,
MINIMUM_REPLICATION_FACTOR_FAIL_THRESHOLD));
+ }
+
+ @Test
+ public void testMultipleDatacenter() throws Throwable
+ {
+ IEndpointSnitch snitch = DatabaseDescriptor.getEndpointSnitch();
+ DatabaseDescriptor.setEndpointSnitch(new AbstractEndpointSnitch()
+ {
+ public static final String RACK1 = ServerTestUtils.RACK1;
+
+ @Override
+ public String getRack(InetAddressAndPort endpoint) { return RACK1;
}
+
+ @Override
+ public String getDatacenter(InetAddressAndPort endpoint) { return
"datacenter2"; }
+
+ @Override
+ public int compareEndpoints(InetAddressAndPort target, Replica a1,
Replica a2) { return 0; }
+ });
+
+ List<String> twoWarnings = Arrays.asList(format("The keyspace %s has a
replication factor of 2, below the warning threshold of %d.", KS,
MINIMUM_REPLICATION_FACTOR_WARN_THRESHOLD),
+ format("The keyspace %s has a
replication factor of 2, below the warning threshold of %d.", KS,
MINIMUM_REPLICATION_FACTOR_WARN_THRESHOLD));
+
+
StorageService.instance.getTokenMetadata().updateHostId(UUID.randomUUID(),
InetAddressAndPort.getByName("127.0.0.255"));
+
guardrails().setMinimumReplicationFactorThreshold(MINIMUM_REPLICATION_FACTOR_WARN_THRESHOLD,
MINIMUM_REPLICATION_FACTOR_FAIL_THRESHOLD);
+ assertValid("CREATE KEYSPACE ks WITH replication = { 'class' :
'NetworkTopologyStrategy', 'datacenter1': 4, 'datacenter2' : 4 };");
+ assertWarns("ALTER KEYSPACE ks WITH replication = { 'class' :
'NetworkTopologyStrategy', 'datacenter1': 4, 'datacenter2' : 2 };",
+ format("The keyspace %s has a replication factor of 2,
below the warning threshold of %d.", KS,
MINIMUM_REPLICATION_FACTOR_WARN_THRESHOLD));
+ assertWarns("ALTER KEYSPACE ks WITH replication = { 'class' :
'NetworkTopologyStrategy', 'datacenter1': 2, 'datacenter2' : 2 };",
twoWarnings);
+ assertFails("ALTER KEYSPACE ks WITH replication = { 'class' :
'NetworkTopologyStrategy', 'datacenter1': 4, 'datacenter2' : 1 };",
+ format("The keyspace %s has a replication factor of 1,
below the failure threshold of %d.", KS,
MINIMUM_REPLICATION_FACTOR_FAIL_THRESHOLD));
+ assertFails("CREATE KEYSPACE ks1 WITH replication = { 'class' :
'NetworkTopologyStrategy', 'datacenter1': 1, 'datacenter2' : 1 };",
+ format("The keyspace ks1 has a replication factor of 1,
below the failure threshold of %d.",
MINIMUM_REPLICATION_FACTOR_FAIL_THRESHOLD));
+
+ DatabaseDescriptor.setEndpointSnitch(snitch);
+ execute("DROP KEYSPACE IF EXISTS ks1");
+ }
+
+ @Test
+ public void testMinKeyspaceRFOnlyWarnAbove() throws Throwable
+ {
+
guardrails().setMinimumReplicationFactorThreshold(MINIMUM_REPLICATION_FACTOR_WARN_THRESHOLD,
DISABLED_GUARDRAIL);
+ assertMinThresholdValid("CREATE KEYSPACE ks WITH replication = {
'class': 'NetworkTopologyStrategy', 'datacenter1': 6}");
+ assertMinThresholdValid("ALTER KEYSPACE ks WITH replication = {
'class': 'NetworkTopologyStrategy', 'datacenter1': 5}");
+ }
+
+ @Test
+ public void testMinKeyspaceRFOnlyWarnBelow() throws Throwable
+ {
+
guardrails().setMinimumReplicationFactorThreshold(MINIMUM_REPLICATION_FACTOR_WARN_THRESHOLD,
DISABLED_GUARDRAIL);
+ assertWarns("CREATE KEYSPACE ks WITH replication = { 'class':
'NetworkTopologyStrategy', 'datacenter1': 3}",
+ format("The keyspace %s has a replication factor of 3,
below the warning threshold of %s.", KS,
MINIMUM_REPLICATION_FACTOR_WARN_THRESHOLD));
+ assertWarns("ALTER KEYSPACE ks WITH replication = { 'class':
'NetworkTopologyStrategy', 'datacenter1': 2}",
+ format("The keyspace %s has a replication factor of 2,
below the warning threshold of %s.", KS,
MINIMUM_REPLICATION_FACTOR_WARN_THRESHOLD));
+ }
+
+ @Test
+ public void testMinKeyspaceRFOnlyFailAbove() throws Throwable
+ {
+ guardrails().setMinimumReplicationFactorThreshold(DISABLED_GUARDRAIL,
MINIMUM_REPLICATION_FACTOR_FAIL_THRESHOLD);
+ assertMinThresholdValid("CREATE KEYSPACE ks WITH replication = {
'class': 'NetworkTopologyStrategy', 'datacenter1': 4}");
+ assertMinThresholdValid("ALTER KEYSPACE ks WITH replication = {
'class': 'NetworkTopologyStrategy', 'datacenter1': 2}");
+ }
+
+ @Test
+ public void testMinKeyspaceRFOnlyFailBelow() throws Throwable
+ {
+ guardrails().setMinimumReplicationFactorThreshold(DISABLED_GUARDRAIL,
MINIMUM_REPLICATION_FACTOR_FAIL_THRESHOLD);
+ assertFails("CREATE KEYSPACE ks WITH replication = { 'class':
'NetworkTopologyStrategy', 'datacenter1': 1}",
+ format("The keyspace %s has a replication factor of 1,
below the failure threshold of %s.", KS,
MINIMUM_REPLICATION_FACTOR_FAIL_THRESHOLD));
+ }
+
+ @Test
+ public void testMinKeyspaceRFOnlyFailBelowAlter() throws Throwable
+ {
+ guardrails().setMinimumReplicationFactorThreshold(DISABLED_GUARDRAIL,
MINIMUM_REPLICATION_FACTOR_FAIL_THRESHOLD);
+ execute("CREATE KEYSPACE ks WITH replication = { 'class':
'NetworkTopologyStrategy', 'datacenter1': 3}");
+ assertFails("ALTER KEYSPACE ks WITH replication = { 'class':
'NetworkTopologyStrategy', 'datacenter1': 1}",
+ format("The keyspace %s has a replication factor of 1,
below the failure threshold of %s.", KS,
MINIMUM_REPLICATION_FACTOR_FAIL_THRESHOLD));
+ }
+
+ @Test
+ public void testMinKeyspaceRFWarnAbove() throws Throwable
+ {
+
guardrails().setMinimumReplicationFactorThreshold(MINIMUM_REPLICATION_FACTOR_WARN_THRESHOLD,
MINIMUM_REPLICATION_FACTOR_FAIL_THRESHOLD);
+ assertMinThresholdValid("CREATE KEYSPACE ks WITH replication = {
'class': 'NetworkTopologyStrategy', 'datacenter1': 6}");
+ assertMinThresholdValid("ALTER KEYSPACE ks WITH replication = {
'class': 'NetworkTopologyStrategy', 'datacenter1': 5}");
+ }
+
+ @Test
+ public void testMinKeyspaceRFWarnFailBetween() throws Throwable
+ {
+
guardrails().setMinimumReplicationFactorThreshold(MINIMUM_REPLICATION_FACTOR_WARN_THRESHOLD,
MINIMUM_REPLICATION_FACTOR_FAIL_THRESHOLD);
+ assertWarns("CREATE KEYSPACE ks WITH replication = { 'class':
'NetworkTopologyStrategy', 'datacenter1': 3}",
+ format("The keyspace %s has a replication factor of 3,
below the warning threshold of %s.", KS,
MINIMUM_REPLICATION_FACTOR_WARN_THRESHOLD));
+ assertWarns("ALTER KEYSPACE ks WITH replication = { 'class':
'NetworkTopologyStrategy', 'datacenter1': 2}",
+ format("The keyspace %s has a replication factor of 2,
below the warning threshold of %s.", KS,
MINIMUM_REPLICATION_FACTOR_WARN_THRESHOLD));
+ }
+
+ @Test
+ public void testMinKeyspaceRFFailBelow() throws Throwable
+ {
+
guardrails().setMinimumReplicationFactorThreshold(MINIMUM_REPLICATION_FACTOR_WARN_THRESHOLD,
MINIMUM_REPLICATION_FACTOR_FAIL_THRESHOLD);
+ assertFails("CREATE KEYSPACE ks WITH replication = { 'class':
'NetworkTopologyStrategy', 'datacenter1': 1}",
+ format("The keyspace %s has a replication factor of 1,
below the failure threshold of %s.", KS,
MINIMUM_REPLICATION_FACTOR_FAIL_THRESHOLD));
+ }
+
+ @Test
+ public void testMinKeyspaceRFFailBelowAlter() throws Throwable
+ {
+
guardrails().setMinimumReplicationFactorThreshold(MINIMUM_REPLICATION_FACTOR_WARN_THRESHOLD,
MINIMUM_REPLICATION_FACTOR_FAIL_THRESHOLD);
+ execute("CREATE KEYSPACE ks WITH replication = { 'class':
'NetworkTopologyStrategy', 'datacenter1': 4}");
+ assertFails("ALTER KEYSPACE ks WITH replication = { 'class':
'NetworkTopologyStrategy', 'datacenter1': 1}",
+ format("The keyspace %s has a replication factor of 1,
below the failure threshold of %s.", KS,
MINIMUM_REPLICATION_FACTOR_FAIL_THRESHOLD));
+ }
+
+ @Test
+ public void testMinRFGreaterThanDefaultRF()
+ {
+ try
+ {
+ DatabaseDescriptor.setDefaultKeyspaceRF(1);
+
guardrails().setMinimumReplicationFactorThreshold(MINIMUM_REPLICATION_FACTOR_WARN_THRESHOLD,
MINIMUM_REPLICATION_FACTOR_FAIL_THRESHOLD);
+ }
+ catch (ConfigurationException e)
+ {
+ String expectedMessage = "";
+
+ if(guardrails().getMinimumReplicationFactorFailThreshold() >
DatabaseDescriptor.getDefaultKeyspaceRF())
+ expectedMessage = format("%s_fail_threshold to be set (%d)
cannot be greater than default_keyspace_rf (%d)",
+ WHAT,
guardrails().getMinimumReplicationFactorFailThreshold(),
DatabaseDescriptor.getDefaultKeyspaceRF());
+ Assertions.assertThat(e.getMessage()).contains(expectedMessage);
+ }
+ }
+}
diff --git
a/test/unit/org/apache/cassandra/db/guardrails/GuardrailSecondaryIndexesPerTable.java
b/test/unit/org/apache/cassandra/db/guardrails/GuardrailSecondaryIndexesPerTable.java
index 102da71c8a..8591f823af 100644
---
a/test/unit/org/apache/cassandra/db/guardrails/GuardrailSecondaryIndexesPerTable.java
+++
b/test/unit/org/apache/cassandra/db/guardrails/GuardrailSecondaryIndexesPerTable.java
@@ -92,7 +92,7 @@ public class GuardrailSecondaryIndexesPerTable extends
ThresholdTester
private void assertCreateIndexSucceeds(String column, String indexName)
throws Throwable
{
- assertThresholdValid(format("CREATE INDEX %s ON %s.%s(%s)", indexName,
keyspace(), currentTable(), column));
+ assertMaxThresholdValid(format("CREATE INDEX %s ON %s.%s(%s)",
indexName, keyspace(), currentTable(), column));
}
private void assertCreateIndexWarns(String column, String indexName)
throws Throwable
diff --git
a/test/unit/org/apache/cassandra/db/guardrails/GuardrailTablesTest.java
b/test/unit/org/apache/cassandra/db/guardrails/GuardrailTablesTest.java
index 969b50c668..7e69636600 100644
--- a/test/unit/org/apache/cassandra/db/guardrails/GuardrailTablesTest.java
+++ b/test/unit/org/apache/cassandra/db/guardrails/GuardrailTablesTest.java
@@ -83,7 +83,7 @@ public class GuardrailTablesTest extends ThresholdTester
private String assertCreateTableValid() throws Throwable
{
String tableName = createTableName();
- assertThresholdValid(createTableQuery(tableName));
+ assertMaxThresholdValid(createTableQuery(tableName));
return tableName;
}
diff --git a/test/unit/org/apache/cassandra/db/guardrails/GuardrailTester.java
b/test/unit/org/apache/cassandra/db/guardrails/GuardrailTester.java
index 986e1d698f..7c94702a21 100644
--- a/test/unit/org/apache/cassandra/db/guardrails/GuardrailTester.java
+++ b/test/unit/org/apache/cassandra/db/guardrails/GuardrailTester.java
@@ -416,7 +416,7 @@ public abstract class GuardrailTester extends CQLTester
assertTrue(format("Expect no warning messages but got %s", warnings),
warnings.isEmpty());
}
- private List<String> getWarnings()
+ protected List<String> getWarnings()
{
List<String> warnings = ClientWarn.instance.getWarnings();
diff --git
a/test/unit/org/apache/cassandra/db/guardrails/GuardrailViewsPerTableTest.java
b/test/unit/org/apache/cassandra/db/guardrails/GuardrailViewsPerTableTest.java
index edff3172f7..3be58b00cb 100644
---
a/test/unit/org/apache/cassandra/db/guardrails/GuardrailViewsPerTableTest.java
+++
b/test/unit/org/apache/cassandra/db/guardrails/GuardrailViewsPerTableTest.java
@@ -101,7 +101,7 @@ public class GuardrailViewsPerTableTest extends
ThresholdTester
private String assertCreateViewSucceeds() throws Throwable
{
String viewName = createViewName();
- assertThresholdValid(format(CREATE_VIEW, viewName));
+ assertMaxThresholdValid(format(CREATE_VIEW, viewName));
return viewName;
}
diff --git
a/test/unit/org/apache/cassandra/db/guardrails/GuardrailsConfigProviderTest.java
b/test/unit/org/apache/cassandra/db/guardrails/GuardrailsConfigProviderTest.java
index 991dcf7cd4..e99b736b03 100644
---
a/test/unit/org/apache/cassandra/db/guardrails/GuardrailsConfigProviderTest.java
+++
b/test/unit/org/apache/cassandra/db/guardrails/GuardrailsConfigProviderTest.java
@@ -36,7 +36,7 @@ public class GuardrailsConfigProviderTest extends
GuardrailTester
{
String name = getClass().getCanonicalName() + '$' +
CustomProvider.class.getSimpleName();
GuardrailsConfigProvider provider =
GuardrailsConfigProvider.build(name);
- Threshold guard = new Threshold("test_guardrail",
+ MaxThreshold guard = new MaxThreshold("test_guardrail",
state ->
provider.getOrCreate(state).getTablesWarnThreshold(),
state ->
provider.getOrCreate(state).getTablesFailThreshold(),
(isWarn, what, v, t) -> format("%s:
for %s, %s > %s",
diff --git a/test/unit/org/apache/cassandra/db/guardrails/GuardrailsTest.java
b/test/unit/org/apache/cassandra/db/guardrails/GuardrailsTest.java
index b278e7f6f8..a0a5823b01 100644
--- a/test/unit/org/apache/cassandra/db/guardrails/GuardrailsTest.java
+++ b/test/unit/org/apache/cassandra/db/guardrails/GuardrailsTest.java
@@ -39,12 +39,6 @@ public class GuardrailsTest extends GuardrailTester
{
public static final int DISABLED = -1;
- @Test
- public void testDisabledThreshold() throws Throwable
- {
- Threshold.ErrorMessageProvider errorMessageProvider = (isWarn, what,
v, t) -> "Should never trigger";
- testDisabledThreshold(new Threshold("x", state -> DISABLED, state ->
DISABLED, errorMessageProvider));
- }
private void testDisabledThreshold(Threshold guard) throws Throwable
{
@@ -61,9 +55,16 @@ public class GuardrailsTest extends GuardrailTester
}
@Test
- public void testThreshold() throws Throwable
+ public void testDisabledMaxThreshold() throws Throwable
{
- Threshold guard = new Threshold("x",
+ Threshold.ErrorMessageProvider errorMessageProvider = (isWarn, what,
v, t) -> "Should never trigger";
+ testDisabledThreshold(new MaxThreshold("x", state -> DISABLED, state
-> DISABLED, errorMessageProvider));
+ }
+
+ @Test
+ public void testMaxThreshold() throws Throwable
+ {
+ MaxThreshold guard = new MaxThreshold("x",
state -> 10,
state -> 100,
(isWarn, what, v, t) -> format("%s:
for %s, %s > %s",
@@ -87,9 +88,9 @@ public class GuardrailsTest extends GuardrailTester
}
@Test
- public void testWarnOnlyThreshold() throws Throwable
+ public void testWarnOnlyMaxThreshold() throws Throwable
{
- Threshold guard = new Threshold("x",
+ MaxThreshold guard = new MaxThreshold("x",
state -> 10,
state -> DISABLED,
(isWarn, what, v, t) -> format("%s:
for %s, %s > %s",
@@ -105,9 +106,9 @@ public class GuardrailsTest extends GuardrailTester
}
@Test
- public void testFailOnlyThreshold() throws Throwable
+ public void testFailOnlyMaxThreshold() throws Throwable
{
- Threshold guard = new Threshold("x",
+ MaxThreshold guard = new MaxThreshold("x",
state -> DISABLED,
state -> 10,
(isWarn, what, v, t) -> format("%s:
for %s, %s > %s",
@@ -123,9 +124,9 @@ public class GuardrailsTest extends GuardrailTester
}
@Test
- public void testThresholdUsers() throws Throwable
+ public void testMaxThresholdUsers() throws Throwable
{
- Threshold guard = new Threshold("x",
+ MaxThreshold guard = new MaxThreshold("x",
state -> 10,
state -> 100,
(isWarn, what, v, t) -> format("%s:
for %s, %s > %s",
@@ -151,6 +152,104 @@ public class GuardrailsTest extends GuardrailTester
assertValid(() -> guard.guard(101, "z", false, superClientState));
}
+ @Test
+ public void testDisabledMinThreshold() throws Throwable
+ {
+ Threshold.ErrorMessageProvider errorMessageProvider = (isWarn, what,
v, t) -> "Should never trigger";
+ testDisabledThreshold(new MinThreshold("x", state -> DISABLED, state
-> DISABLED, errorMessageProvider));
+ }
+
+ @Test
+ public void testMinThreshold() throws Throwable
+ {
+ MinThreshold guard = new MinThreshold("x",
+ state -> 100,
+ state -> 10,
+ (isWarn, what, v, t) ->
format("%s: for %s, %s < %s",
+
isWarn ? "Warning" : "Aborting", what, v, t));
+
+ assertTrue(guard.enabled(userClientState));
+
+ assertValid(() -> guard.guard(200, "Z", false, userClientState));
+ assertWarns(() -> guard.guard(25, "A", false, userClientState),
"Warning: for A, 25 < 100");
+ assertWarns(() -> guard.guard(10, "B", false, userClientState),
"Warning: for B, 10 < 100");
+ assertFails(() -> guard.guard(9, "X", false, userClientState),
"Aborting: for X, 9 < 10");
+ assertFails(() -> guard.guard(1, "Y", false, userClientState),
"Aborting: for Y, 1 < 10");
+ assertValid(() -> guard.guard(200, "Z", false, userClientState));
+
+ assertValid(() -> guard.guard(200, "Z", true, userClientState));
+ assertWarns(() -> guard.guard(25, "A", true, userClientState),
"Warning: for A, 25 < 100", "Warning: for <redacted>, 25 < 100");
+ assertWarns(() -> guard.guard(10, "B", true, userClientState),
"Warning: for B, 10 < 100", "Warning: for <redacted>, 10 < 100");
+ assertFails(() -> guard.guard(9, "X", true, userClientState),
"Aborting: for X, 9 < 10", "Aborting: for <redacted>, 9 < 10");
+ assertFails(() -> guard.guard(1, "Y", true, userClientState),
"Aborting: for Y, 1 < 10", "Aborting: for <redacted>, 1 < 10");
+ assertValid(() -> guard.guard(200, "Z", true, userClientState));
+ }
+
+ @Test
+ public void testWarnOnlyMinThreshold() throws Throwable
+ {
+ MinThreshold guard = new MinThreshold("x",
+ state -> 10,
+ state -> DISABLED,
+ (isWarn, what, v, t) ->
format("%s: for %s, %s < %s",
+
isWarn ? "Warning" : "Aborting", what, v, t));
+
+ assertTrue(guard.enabled(userClientState));
+
+ assertValid(() -> guard.guard(11, "Z", false, userClientState));
+ assertWarns(() -> guard.guard(5, "A", false, userClientState),
"Warning: for A, 5 < 10");
+
+ assertValid(() -> guard.guard(11, "Z", true, userClientState));
+ assertWarns(() -> guard.guard(5, "A", true, userClientState),
"Warning: for A, 5 < 10", "Warning: for <redacted>, 5 < 10");
+ }
+
+ @Test
+ public void testFailOnlyMinThreshold() throws Throwable
+ {
+ MinThreshold guard = new MinThreshold("x",
+ state -> DISABLED,
+ state -> 10,
+ (isWarn, what, v, t) ->
format("%s: for %s, %s < %s",
+
isWarn ? "Warning" : "Aborting", what, v, t));
+
+ assertTrue(guard.enabled(userClientState));
+
+ assertValid(() -> guard.guard(11, "Z", false, userClientState));
+ assertFails(() -> guard.guard(5, "A", false, userClientState),
"Aborting: for A, 5 < 10");
+
+ assertValid(() -> guard.guard(11, "Z", true, userClientState));
+ assertFails(() -> guard.guard(5, "A", true, userClientState),
"Aborting: for A, 5 < 10", "Aborting: for <redacted>, 5 < 10");
+ }
+
+ @Test
+ public void testMinThresholdUsers() throws Throwable
+ {
+ MinThreshold guard = new MinThreshold("x",
+ state -> 100,
+ state -> 10,
+ (isWarn, what, v, t) ->
format("%s: for %s, %s < %s",
+
isWarn ? "Warning" : "Failure", what, v, t));
+
+ // value above both thresholds
+ assertValid(() -> guard.guard(200, "x", false, null));
+ assertValid(() -> guard.guard(200, "x", false, userClientState));
+ assertValid(() -> guard.guard(200, "x", false, systemClientState));
+ assertValid(() -> guard.guard(200, "x", false, superClientState));
+
+ // value under warning threshold
+ assertWarns(() -> guard.guard(10, "y", false, null), "Warning: for y,
10 < 100");
+ assertWarns(() -> guard.guard(10, "y", false, userClientState),
"Warning: for y, 10 < 100");
+ assertValid(() -> guard.guard(10, "y", false, systemClientState));
+ assertValid(() -> guard.guard(10, "y", false, superClientState));
+
+ // value under fail threshold. An undefined user means that the check
comes from a background process, so we
+ // still emit failure messages and events, but we don't throw an
exception to prevent interrupting that process.
+ assertFails(() -> guard.guard(9, "z", false, null), false, "Failure:
for z, 9 < 10");
+ assertFails(() -> guard.guard(9, "z", false, userClientState),
"Failure: for z, 9 < 10");
+ assertValid(() -> guard.guard(9, "z", false, systemClientState));
+ assertValid(() -> guard.guard(9, "z", false, superClientState));
+ }
+
@Test
public void testDisableFlag() throws Throwable
{
diff --git a/test/unit/org/apache/cassandra/db/guardrails/ThresholdTester.java
b/test/unit/org/apache/cassandra/db/guardrails/ThresholdTester.java
index a04cc9933b..13ce67d142 100644
--- a/test/unit/org/apache/cassandra/db/guardrails/ThresholdTester.java
+++ b/test/unit/org/apache/cassandra/db/guardrails/ThresholdTester.java
@@ -136,15 +136,41 @@ public abstract class ThresholdTester extends
GuardrailTester
.hasMessageContaining(guardrail.name + "_warn_threshold
should be lower than the fail threshold");
}
- protected void assertThresholdValid(String query) throws Throwable
+ protected void assertMaxThresholdValid(String query) throws Throwable
{
assertValid(query);
- Assertions.assertThat(currentValue())
- .isLessThanOrEqualTo(warnGetter.applyAsLong(guardrails()))
- .isLessThanOrEqualTo(failGetter.applyAsLong(guardrails()));
+ long warnValue = warnGetter.applyAsLong(guardrails());
+ long failValue = failGetter.applyAsLong(guardrails());
+ long current = currentValue();
+
+ if (warnValue != disabledValue)
+ Assertions.assertThat(current)
+ .isLessThanOrEqualTo(warnValue);
+
+ if (failValue != disabledValue)
+ Assertions.assertThat(current)
+ .isLessThanOrEqualTo(failValue);
}
+ protected void assertMinThresholdValid(String query) throws Throwable
+ {
+ assertValid(query);
+
+ long warnValue = warnGetter.applyAsLong(guardrails());
+ long failValue = failGetter.applyAsLong(guardrails());
+ long current = currentValue();
+
+ if (warnValue != disabledValue)
+ Assertions.assertThat(current)
+ .isGreaterThanOrEqualTo(warnValue);
+
+ if (failValue != disabledValue)
+ Assertions.assertThat(current)
+ .isGreaterThanOrEqualTo(failValue);
+ }
+
+
protected void assertThresholdWarns(String query, String message) throws
Throwable
{
assertThresholdWarns(query, message, message);
@@ -193,7 +219,7 @@ public abstract class ThresholdTester extends
GuardrailTester
.isEqualTo(failGetter.applyAsLong(guardrails()));
}
- private void assertInvalidPositiveProperty(BiConsumer<Guardrails, Long>
setter,
+ protected void assertInvalidPositiveProperty(BiConsumer<Guardrails, Long>
setter,
long value,
long maxValue,
String name)
@@ -238,6 +264,13 @@ public abstract class ThresholdTester extends
GuardrailTester
assertInvalidPositiveProperty(setter, value, maxValue, name);
}
+ protected void assertInvalidPositiveIntProperty (BiConsumer<Guardrails,
Integer> setter, int value,
+ int maxValue,
+ String name)
+ {
+ assertInvalidPositiveProperty((g, l) -> setter.accept(g,
l.intValue()), (long) value, maxValue, name);
+ }
+
protected void
testValidationOfStrictlyPositiveProperty(BiConsumer<Guardrails, Long> setter,
String name)
{
assertInvalidStrictlyPositiveProperty(setter, Integer.MIN_VALUE, name);
diff --git
a/test/unit/org/apache/cassandra/locator/NetworkTopologyStrategyTest.java
b/test/unit/org/apache/cassandra/locator/NetworkTopologyStrategyTest.java
index 8ab1bfa953..45ba5d8f1d 100644
--- a/test/unit/org/apache/cassandra/locator/NetworkTopologyStrategyTest.java
+++ b/test/unit/org/apache/cassandra/locator/NetworkTopologyStrategyTest.java
@@ -480,7 +480,7 @@ public class NetworkTopologyStrategyTest
StorageService.instance.getTokenMetadata().updateHostId(UUID.randomUUID(),
FBUtilities.getBroadcastAddressAndPort());
ClientWarn.instance.captureWarnings();
- strategy.maybeWarnOnOptions();
+ strategy.maybeWarnOnOptions(null);
assertTrue(ClientWarn.instance.getWarnings().stream().anyMatch(s ->
s.contains("Your replication factor")));
}
}
diff --git a/test/unit/org/apache/cassandra/locator/SimpleStrategyTest.java
b/test/unit/org/apache/cassandra/locator/SimpleStrategyTest.java
index 1665d01a33..809b6fc989 100644
--- a/test/unit/org/apache/cassandra/locator/SimpleStrategyTest.java
+++ b/test/unit/org/apache/cassandra/locator/SimpleStrategyTest.java
@@ -349,7 +349,7 @@ public class SimpleStrategyTest
StorageService.instance.getTokenMetadata().updateHostId(UUID.randomUUID(),
FBUtilities.getBroadcastAddressAndPort());
ClientWarn.instance.captureWarnings();
- strategy.maybeWarnOnOptions();
+ strategy.maybeWarnOnOptions(null);
assertTrue(ClientWarn.instance.getWarnings().stream().anyMatch(s ->
s.contains("Your replication factor")));
}
diff --git
a/test/unit/org/apache/cassandra/tools/nodetool/GetMinimumKeyspaceRFTest.java
b/test/unit/org/apache/cassandra/tools/nodetool/GetMinimumKeyspaceRFTest.java
deleted file mode 100644
index d2ff34b912..0000000000
---
a/test/unit/org/apache/cassandra/tools/nodetool/GetMinimumKeyspaceRFTest.java
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * 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.tools.nodetool;
-
-import org.junit.BeforeClass;
-import org.junit.Test;
-
-import org.apache.cassandra.config.DatabaseDescriptor;
-import org.apache.cassandra.cql3.CQLTester;
-import org.apache.cassandra.tools.ToolRunner;
-import org.assertj.core.api.Assertions;
-
-import static org.assertj.core.api.Assertions.assertThat;
-
-public class GetMinimumKeyspaceRFTest extends CQLTester
-{
- @BeforeClass
- public static void setup() throws Exception
- {
- requireNetwork();
- startJMXServer();
- }
-
- @Test
- @SuppressWarnings("SingleCharacterStringConcatenation")
- public void testMaybeChangeDocs()
- {
- // If you added, modified options or help, please update docs if
necessary
- ToolRunner.ToolResult tool = ToolRunner.invokeNodetool("help",
"getminimumrf");
- tool.assertOnCleanExit();
-
- String help = "NAME\n" +
- " nodetool getminimumrf - Gets minimum keyspace
replication factor.\n" +
- "\n" +
- "SYNOPSIS\n" +
- " nodetool [(-h <host> | --host <host>)] [(-p
<port> | --port <port>)]\n" +
- " [(-pp | --print-port)] [(-pw
<password> | --password <password>)]\n" +
- " [(-pwf <passwordFilePath> |
--password-file <passwordFilePath>)]\n" +
- " [(-u <username> | --username
<username>)] getminimumrf\n" +
- "\n" +
- "OPTIONS\n" +
- " -h <host>, --host <host>\n" +
- " Node hostname or ip address\n" +
- "\n" +
- " -p <port>, --port <port>\n" +
- " Remote jmx agent port number\n" +
- "\n" +
- " -pp, --print-port\n" +
- " Operate in 4.0 mode with hosts
disambiguated by port number\n" +
- "\n" +
- " -pw <password>, --password <password>\n" +
- " Remote jmx agent password\n" +
- "\n" +
- " -pwf <passwordFilePath>, --password-file
<passwordFilePath>\n" +
- " Path to the JMX password file\n" +
- "\n" +
- " -u <username>, --username <username>\n" +
- " Remote jmx agent username\n" +
- "\n" +
- "\n";
- assertThat(tool.getStdout()).isEqualTo(help);
- }
-
- @Test
- public void testGetMinimumRF()
- {
- ToolRunner.ToolResult tool = ToolRunner.invokeNodetool("getminimumrf");
- tool.assertOnCleanExit();
-
assertThat(tool.getStdout().trim()).isEqualTo(Integer.toString(DatabaseDescriptor.getMinimumKeyspaceRF()));
- }
-}
\ No newline at end of file
diff --git
a/test/unit/org/apache/cassandra/tools/nodetool/SetMinimumKeyspaceRFTest.java
b/test/unit/org/apache/cassandra/tools/nodetool/SetMinimumKeyspaceRFTest.java
deleted file mode 100644
index 09d3625d50..0000000000
---
a/test/unit/org/apache/cassandra/tools/nodetool/SetMinimumKeyspaceRFTest.java
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * 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.tools.nodetool;
-
-import org.junit.BeforeClass;
-import org.junit.Test;
-
-import org.apache.cassandra.config.DatabaseDescriptor;
-import org.apache.cassandra.cql3.CQLTester;
-import org.apache.cassandra.tools.ToolRunner;
-
-import static org.assertj.core.api.Assertions.assertThat;
-
-public class SetMinimumKeyspaceRFTest extends CQLTester
-{
- @BeforeClass
- public static void setup() throws Exception
- {
- requireNetwork();
- startJMXServer();
- }
-
- @Test
- @SuppressWarnings("SingleCharacterStringConcatenation")
- public void testMaybeChangeDocs()
- {
- // If you added, modified options or help, please update docs if
necessary
- ToolRunner.ToolResult tool = ToolRunner.invokeNodetool("help",
"setminimumrf");
- tool.assertOnCleanExit();
-
- String help = "NAME\n" +
- " nodetool setminimumrf - Sets minimum keyspace
replication factor.\n" +
- "\n" +
- "SYNOPSIS\n" +
- " nodetool [(-h <host> | --host <host>)] [(-p
<port> | --port <port>)]\n" +
- " [(-pp | --print-port)] [(-pw
<password> | --password <password>)]\n" +
- " [(-pwf <passwordFilePath> |
--password-file <passwordFilePath>)]\n" +
- " [(-u <username> | --username
<username>)] setminimumrf [--] <value>\n" +
- "\n" +
- "OPTIONS\n" +
- " -h <host>, --host <host>\n" +
- " Node hostname or ip address\n" +
- "\n" +
- " -p <port>, --port <port>\n" +
- " Remote jmx agent port number\n" +
- "\n" +
- " -pp, --print-port\n" +
- " Operate in 4.0 mode with hosts
disambiguated by port number\n" +
- "\n" +
- " -pw <password>, --password <password>\n" +
- " Remote jmx agent password\n" +
- "\n" +
- " -pwf <passwordFilePath>, --password-file
<passwordFilePath>\n" +
- " Path to the JMX password file\n" +
- "\n" +
- " -u <username>, --username <username>\n" +
- " Remote jmx agent username\n" +
- "\n" +
- " --\n" +
- " This option can be used to separate
command-line options from the\n" +
- " list of argument, (useful when arguments
might be mistaken for\n" +
- " command-line options\n" +
- "\n" +
- " <value>\n" +
- " Minimum replication factor\n" +
- "\n" +
- "\n";
- assertThat(tool.getStdout()).isEqualTo(help);
- }
-
- @Test
- public void testSetMinimumRF()
- {
- ToolRunner.ToolResult tool = ToolRunner.invokeNodetool("setminimumrf",
"1");
- tool.assertOnCleanExit();
- assertThat(DatabaseDescriptor.getMinimumKeyspaceRF()).isEqualTo(1);
- }
-}
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]