This is an automated email from the ASF dual-hosted git repository.
adelapena 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 bae92ee Migrate thresholds for number of keyspaces and tables to
guardrails
bae92ee is described below
commit bae92ee139b411c94228f8fd5bb8befb4183ca9f
Author: Andrés de la Peña <[email protected]>
AuthorDate: Wed Dec 8 13:28:17 2021 +0000
Migrate thresholds for number of keyspaces and tables to guardrails
This adds a new guardrail for limiting the number of keyspaces. It also
marks the previous not-guardrail thresholds
for keyspaces and tables as deprecated in favour of the equivalent
guardrails. GuardrailsOptions is modified to always
log updates on guardrails config. A small refactor decouples guardrails
from their configuration interfaces.
patch by Andrés de la Peña; reviewed by Ekaterina Dimitrova for
CASSANDRA-17195
---
CHANGES.txt | 1 +
NEWS.txt | 5 +
conf/cassandra.yaml | 6 +
src/java/org/apache/cassandra/config/Config.java | 2 +
.../cassandra/config/DatabaseDescriptor.java | 5 +
.../apache/cassandra/config/GuardrailsOptions.java | 169 ++++++++++++++-------
.../statements/schema/CreateKeyspaceStatement.java | 11 ++
.../statements/schema/CreateTableStatement.java | 9 +-
.../apache/cassandra/db/guardrails/Guardrails.java | 75 ++++++---
.../cassandra/db/guardrails/GuardrailsConfig.java | 54 ++++++-
.../cassandra/db/guardrails/GuardrailsMBean.java | 18 +++
.../apache/cassandra/db/guardrails/Threshold.java | 49 +++---
.../org/apache/cassandra/db/guardrails/Values.java | 41 ++---
.../apache/cassandra/service/StorageService.java | 4 +
.../cassandra/service/StorageServiceMBean.java | 5 +
.../config/DatabaseDescriptorRefTest.java | 3 +
.../db/guardrails/GuardrailKeyspacesTest.java | 117 ++++++++++++++
.../guardrails/GuardrailTablePropertiesTest.java | 17 ++-
...blesLimitTest.java => GuardrailTablesTest.java} | 6 +-
.../guardrails/GuardrailsConfigProviderTest.java | 3 +-
.../cassandra/db/guardrails/GuardrailsTest.java | 77 +++-------
.../cassandra/db/guardrails/ThresholdTester.java | 7 +-
.../schema/CreateTableValidationTest.java | 1 +
23 files changed, 467 insertions(+), 218 deletions(-)
diff --git a/CHANGES.txt b/CHANGES.txt
index e829293..99c38b8 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -1,4 +1,5 @@
4.1
+ * Migrate thresholds for number of keyspaces and tables to guardrails
(CASSANDRA-17195)
* Remove self-reference in SSTableTidier (CASSANDRA-17205)
* Add guardrail for query page size (CASSANDRA-17189)
* Allow column_index_size_in_kb to be configurable through nodetool
(CASSANDRA-17121)
diff --git a/NEWS.txt b/NEWS.txt
index f365a68..07ee8a4 100644
--- a/NEWS.txt
+++ b/NEWS.txt
@@ -86,6 +86,11 @@ Upgrading
Deprecation
-----------
+ - The properties `keyspace_count_warn_threshold` and
`table_count_warn_threshold` in cassandra.yaml have been
+ deprecated in favour of the new `guardrails.keyspaces` and
`guardrails.tables` properties and will be removed
+ in a subsequent major version. This also affects the setters and getters
for those properties in the JMX MBean
+ `org.apache.cassandra.db:type=StorageService`, which are equally
deprecated in favour of the analogous methods
+ in the JMX MBean `org.apache.cassandra.db:type=Guardrails`. See
CASSANDRA-17195 for further details.
4.0
===
diff --git a/conf/cassandra.yaml b/conf/cassandra.yaml
index b0c3cb2..541aa6e 100644
--- a/conf/cassandra.yaml
+++ b/conf/cassandra.yaml
@@ -1518,6 +1518,7 @@ report_unconfirmed_repaired_data_mismatches: false
# Having many tables and/or keyspaces negatively affects performance of many
operations in the
# cluster. When the number of tables/keyspaces in the cluster exceeds the
following thresholds
# a client warning will be sent back to the user when creating a table or
keyspace.
+# As of cassandra 4.1, these properties are deprecated in favor of
guardrails.keyspaces and guardrails.tables
# table_count_warn_threshold: 150
# keyspace_count_warn_threshold: 40
@@ -1581,6 +1582,11 @@ enable_drop_compact_storage: false
# guardrails:
# Whether guardrails are enabled or not. Guardrails are disabled by default.
# enabled: false
+# Guardrail to warn or abort when creating more user keyspaces than threshold.
+# The two thresholds default to -1 to disable.
+# keyspaces:
+# warn_threshold: -1
+# abort_threshold: -1
# Guardrail to warn or abort when creating more user tables than threshold.
# The two thresholds default to -1 to disable.
# tables:
diff --git a/src/java/org/apache/cassandra/config/Config.java
b/src/java/org/apache/cassandra/config/Config.java
index 61aaf3c..b88767e 100644
--- a/src/java/org/apache/cassandra/config/Config.java
+++ b/src/java/org/apache/cassandra/config/Config.java
@@ -617,7 +617,9 @@ public class Config
isClientMode = clientMode;
}
+ @Deprecated // this warning threshold will be replaced by an equivalent
guardrail
public volatile int table_count_warn_threshold = 150;
+ @Deprecated // this warning threshold will be replaced by an equivalent
guardrail
public volatile int keyspace_count_warn_threshold = 40;
public volatile int consecutive_message_errors_threshold = 1;
diff --git a/src/java/org/apache/cassandra/config/DatabaseDescriptor.java
b/src/java/org/apache/cassandra/config/DatabaseDescriptor.java
index fe820cd..869678b 100644
--- a/src/java/org/apache/cassandra/config/DatabaseDescriptor.java
+++ b/src/java/org/apache/cassandra/config/DatabaseDescriptor.java
@@ -3539,26 +3539,31 @@ public class DatabaseDescriptor
conf.auto_optimise_preview_repair_streams = enabled;
}
+ @Deprecated
public static int tableCountWarnThreshold()
{
return conf.table_count_warn_threshold;
}
+ @Deprecated // this warning threshold will be replaced by an equivalent
guardrail
public static void setTableCountWarnThreshold(int value)
{
conf.table_count_warn_threshold = value;
}
+ @Deprecated // this warning threshold will be replaced by an equivalent
guardrail
public static int keyspaceCountWarnThreshold()
{
return conf.keyspace_count_warn_threshold;
}
+ @Deprecated // this warning threshold will be replaced by an equivalent
guardrail
public static void setKeyspaceCountWarnThreshold(int value)
{
conf.keyspace_count_warn_threshold = value;
}
+ @Deprecated // this warning threshold will be replaced by an equivalent
guardrail
public static ConsistencyLevel getAuthWriteConsistencyLevel()
{
return ConsistencyLevel.valueOf(conf.auth_write_consistency_level);
diff --git a/src/java/org/apache/cassandra/config/GuardrailsOptions.java
b/src/java/org/apache/cassandra/config/GuardrailsOptions.java
index aa512f3..e019b84 100644
--- a/src/java/org/apache/cassandra/config/GuardrailsOptions.java
+++ b/src/java/org/apache/cassandra/config/GuardrailsOptions.java
@@ -20,14 +20,16 @@ package org.apache.cassandra.config;
import java.util.Collections;
import java.util.Set;
-import javax.annotation.Nullable;
+import java.util.function.Consumer;
+import java.util.function.Supplier;
import com.google.common.collect.Sets;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import org.apache.cassandra.cql3.statements.schema.TableAttributes;
import org.apache.cassandra.db.guardrails.Guardrails;
import org.apache.cassandra.db.guardrails.GuardrailsConfig;
-import org.apache.cassandra.db.guardrails.Values;
import static java.lang.String.format;
import static java.util.stream.Collectors.toSet;
@@ -51,7 +53,11 @@ import static java.util.stream.Collectors.toSet;
*/
public class GuardrailsOptions implements GuardrailsConfig
{
+ private static final String NAME_PREFIX = "guardrails.";
+ private static final Logger logger =
LoggerFactory.getLogger(GuardrailsOptions.class);
+
public volatile boolean enabled = false;
+ public final IntThreshold keyspaces = new IntThreshold();
public final IntThreshold tables = new IntThreshold();
public final IntThreshold columns_per_table = new IntThreshold();
public final IntThreshold secondary_indexes_per_table = new IntThreshold();
@@ -63,12 +69,13 @@ public class GuardrailsOptions implements GuardrailsConfig
public void validate()
{
- tables.validate("guardrails.tables");
- columns_per_table.validate("guardrails.columns_per_table");
-
secondary_indexes_per_table.validate("guardrails.secondary_indexes_per_table");
-
materialized_views_per_table.validate("guardrails.materialized_views_per_table");
- table_properties.validate("guardrails.table_properties");
- page_size.validate("guardrails.page_size");
+ keyspaces.init("keyspaces");
+ tables.init("tables");
+ columns_per_table.init("columns_per_table");
+ secondary_indexes_per_table.init("secondary_indexes_per_table");
+ materialized_views_per_table.init("materialized_views_per_table");
+ table_properties.init("table_properties");
+ page_size.init("guardrails.page_size");
}
@Override
@@ -84,7 +91,13 @@ public class GuardrailsOptions implements GuardrailsConfig
*/
public void setEnabled(boolean enabled)
{
- this.enabled = enabled;
+ updatePropertyWithLogging(NAME_PREFIX + "enabled", enabled, () ->
this.enabled, x -> this.enabled = x);
+ }
+
+ @Override
+ public IntThreshold getKeyspaces()
+ {
+ return keyspaces;
}
@Override
@@ -131,48 +144,56 @@ public class GuardrailsOptions implements GuardrailsConfig
public void setUserTimestampsEnabled(boolean enabled)
{
- user_timestamps_enabled = enabled;
+ updatePropertyWithLogging(NAME_PREFIX + "user_timestamps_enabled",
+ enabled,
+ () -> user_timestamps_enabled,
+ x -> user_timestamps_enabled = x);
}
- public static abstract class Threshold implements
org.apache.cassandra.db.guardrails.Threshold.Config
+ private static <T> void updatePropertyWithLogging(String propertyName, T
newValue, Supplier<T> getter, Consumer<T> setter)
{
- public static final long DISABLED = -1;
-
- public volatile long warn_threshold = DISABLED;
- public volatile long abort_threshold = DISABLED;
-
- @Override
- public long getWarnThreshold()
+ T oldValue = getter.get();
+ if (!newValue.equals(oldValue))
{
- return warn_threshold;
+ setter.accept(newValue);
+ logger.info("Updated {} from {} to {}", propertyName, oldValue,
newValue);
}
+ }
- @Override
- public long getAbortThreshold()
- {
- return abort_threshold;
- }
+ protected static abstract class Config
+ {
+ protected String name;
- public void setThresholds(long warn, long abort)
+ public String getName()
{
- validateStrictlyPositive(warn, "warn threshold");
- validateStrictlyPositive(abort, "abort threshold");
- validateWarnLowerThanAbort(warn, abort, null);
- warn_threshold = warn;
- abort_threshold = abort;
+ return name;
}
- public void validate(String name)
+ protected void init(String name)
{
- validateStrictlyPositive(warn_threshold, name + ".warn_threshold");
- validateStrictlyPositive(abort_threshold, name +
".abort_threshold");
- validateWarnLowerThanAbort(warn_threshold, abort_threshold, name);
+ this.name = NAME_PREFIX + name;
+ validate();
}
+ protected abstract void validate();
+ }
+
+ public static abstract class Threshold extends Config
+ {
+ public static final long DISABLED = -1;
+
public abstract long maxValue();
+
public abstract boolean allowZero();
- private void validateStrictlyPositive(long value, String name)
+ protected void validate(long warn, long abort)
+ {
+ validateLimits(warn, name + ".warn_threshold");
+ validateLimits(abort, name + ".abort_threshold");
+ validateWarnLowerThanAbort(warn, abort);
+ }
+
+ protected void validateLimits(long value, String name)
{
if (value > maxValue())
throw new IllegalArgumentException(format("Invalid value %d
for %s: maximum allowed value is %d",
@@ -190,22 +211,47 @@ public class GuardrailsOptions implements GuardrailsConfig
value, name,
DISABLED));
}
- private void validateWarnLowerThanAbort(long warnValue, long
abortValue, @Nullable String name)
+ private void validateWarnLowerThanAbort(long warn, long abort)
{
- if (warnValue == DISABLED || abortValue == DISABLED)
+ if (warn == DISABLED || abort == DISABLED)
return;
- if (abortValue < warnValue)
- throw new IllegalArgumentException(format("The warn threshold
%d%s should be lower than the abort " +
- "threshold %d",
- warnValue,
- name == null ? "" :
" for " + name,
- abortValue));
+ if (abort < warn)
+ throw new IllegalArgumentException(format("The warn threshold
%d for %s should be lower than the " +
+ "abort threshold
%d", warn, name, abort));
}
}
- public static class IntThreshold extends Threshold
+ public static class IntThreshold extends Threshold implements
GuardrailsConfig.IntThreshold
{
+ public volatile int warn_threshold = (int) DISABLED;
+ public volatile int abort_threshold = (int) DISABLED;
+
+ @Override
+ public int getWarnThreshold()
+ {
+ return warn_threshold;
+ }
+
+ @Override
+ public int getAbortThreshold()
+ {
+ return abort_threshold;
+ }
+
+ public void setThresholds(int warn, int abort)
+ {
+ validate(warn, abort);
+ updatePropertyWithLogging(name + ".warn_threshold", warn, () ->
warn_threshold, x -> warn_threshold = x);
+ updatePropertyWithLogging(name + ".abort_threshold", abort, () ->
abort_threshold, x -> abort_threshold = x);
+ }
+
+ @Override
+ protected void validate()
+ {
+ validate(warn_threshold, abort_threshold);
+ }
+
@Override
public long maxValue()
{
@@ -219,7 +265,7 @@ public class GuardrailsOptions implements GuardrailsConfig
}
}
- public static class TableProperties implements Values.Config<String>
+ public static class TableProperties extends Config implements
GuardrailsConfig.TableProperties
{
public volatile Set<String> ignored = Collections.emptySet();
public volatile Set<String> disallowed = Collections.emptySet();
@@ -236,14 +282,31 @@ public class GuardrailsOptions implements GuardrailsConfig
return disallowed;
}
- public void setIgnoredValues(Set<String> values)
+ public void setIgnored(Set<String> properties)
+ {
+ updatePropertyWithLogging(name + ".ignored",
validateIgnored(properties), () -> ignored, x -> ignored = x);
+ }
+
+ public void setDisallowed(Set<String> properties)
+ {
+ updatePropertyWithLogging(name + ".disallowed",
validateDisallowed(properties), () -> disallowed, x -> disallowed = x);
+ }
+
+ @Override
+ protected void validate()
+ {
+ validateIgnored(ignored);
+ validateDisallowed(disallowed);
+ }
+
+ private Set<String> validateIgnored(Set<String> properties)
{
- this.ignored = validateTableProperties(values, "ignored
properties");
+ return validateTableProperties(properties, name + ".ignored");
}
- public void setDisallowedValues(Set<String> values)
+ private Set<String> validateDisallowed(Set<String> properties)
{
- this.disallowed = validateTableProperties(values, "disallowed
properties");
+ return validateTableProperties(properties, name + ".disallowed");
}
private Set<String> validateTableProperties(Set<String> properties,
String name)
@@ -257,15 +320,9 @@ public class GuardrailsOptions implements GuardrailsConfig
if (!diff.isEmpty())
throw new IllegalArgumentException(format("Invalid value for
%s: '%s' do not parse as valid table properties",
- name,
diff.toString()));
+ name, diff));
return lowerCaseProperties;
}
-
- public void validate(String name)
- {
- validateTableProperties(ignored, name + ".ignored");
- validateTableProperties(disallowed, name + ".disallowed");
- }
}
}
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 9aa27ce..a6036a3 100644
---
a/src/java/org/apache/cassandra/cql3/statements/schema/CreateKeyspaceStatement.java
+++
b/src/java/org/apache/cassandra/cql3/statements/schema/CreateKeyspaceStatement.java
@@ -33,6 +33,7 @@ import org.apache.cassandra.auth.IResource;
import org.apache.cassandra.auth.Permission;
import org.apache.cassandra.config.DatabaseDescriptor;
import org.apache.cassandra.cql3.CQLStatement;
+import org.apache.cassandra.db.guardrails.Guardrails;
import org.apache.cassandra.exceptions.AlreadyExistsException;
import org.apache.cassandra.locator.LocalStrategy;
import org.apache.cassandra.schema.KeyspaceMetadata;
@@ -111,8 +112,18 @@ public final class CreateKeyspaceStatement extends
AlterSchemaStatement
}
@Override
+ public void validate(ClientState state)
+ {
+ super.validate(state);
+
+ // Guardrail on number of keyspaces
+ Guardrails.keyspaces.guard(Schema.instance.getUserKeyspaces().size() +
1, keyspaceName, state);
+ }
+
+ @Override
Set<String> clientWarnings(KeyspacesDiff diff)
{
+ // this threshold is deprecated, it will be replaced by the guardrail
used in #validate(ClientState)
int keyspaceCount = Schema.instance.getKeyspaces().size();
if (keyspaceCount > DatabaseDescriptor.keyspaceCountWarnThreshold())
{
diff --git
a/src/java/org/apache/cassandra/cql3/statements/schema/CreateTableStatement.java
b/src/java/org/apache/cassandra/cql3/statements/schema/CreateTableStatement.java
index c765696..44a6042 100644
---
a/src/java/org/apache/cassandra/cql3/statements/schema/CreateTableStatement.java
+++
b/src/java/org/apache/cassandra/cql3/statements/schema/CreateTableStatement.java
@@ -129,21 +129,21 @@ public final class CreateTableStatement extends
AlterSchemaStatement
// optimization for the case where they are disabled, so we don't have
to do the same check on every guardrail
if (Guardrails.enabled(state))
{
- // Guardrails on table properties
+ // Guardrail on table properties
Guardrails.tableProperties.guard(attrs.updatedProperties(),
attrs::removeProperty, state);
// Guardrail on columns per table
Guardrails.columnsPerTable.guard(rawColumns.size(), tableName,
state);
- // Guardrails on number of tables
- if (Guardrails.tablesLimit.enabled(state))
+ // Guardrail on number of tables
+ if (Guardrails.tables.enabled(state))
{
int totalUserTables = Schema.instance.getUserKeyspaces()
.stream()
.map(Keyspace::open)
.mapToInt(keyspace ->
keyspace.getColumnFamilyStores().size())
.sum();
- Guardrails.tablesLimit.guard(totalUserTables + 1, tableName,
state);
+ Guardrails.tables.guard(totalUserTables + 1, tableName, state);
}
}
}
@@ -402,6 +402,7 @@ public final class CreateTableStatement extends
AlterSchemaStatement
@Override
public Set<String> clientWarnings(KeyspacesDiff diff)
{
+ // this threshold is deprecated, it will be replaced by the guardrail
used in #validate(ClientState)
int tableCount = Schema.instance.getNumberOfTables();
if (tableCount > DatabaseDescriptor.tableCountWarnThreshold())
{
diff --git a/src/java/org/apache/cassandra/db/guardrails/Guardrails.java
b/src/java/org/apache/cassandra/db/guardrails/Guardrails.java
index d299215..d29ab34 100644
--- a/src/java/org/apache/cassandra/db/guardrails/Guardrails.java
+++ b/src/java/org/apache/cassandra/db/guardrails/Guardrails.java
@@ -44,10 +44,23 @@ public final class Guardrails implements GuardrailsMBean
static final Guardrails instance = new Guardrails();
/**
+ * Guardrail on the total number of user keyspaces.
+ */
+ public static final Threshold keyspaces =
+ new Threshold(state ->
CONFIG_PROVIDER.getOrCreate(state).getKeyspaces().getWarnThreshold(),
+ state ->
CONFIG_PROVIDER.getOrCreate(state).getKeyspaces().getAbortThreshold(),
+ (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 tablesLimit =
- new Threshold(state -> CONFIG_PROVIDER.getOrCreate(state).getTables(),
+ public static final Threshold tables =
+ new Threshold(state ->
CONFIG_PROVIDER.getOrCreate(state).getTables().getWarnThreshold(),
+ state ->
CONFIG_PROVIDER.getOrCreate(state).getTables().getAbortThreshold(),
(isWarning, what, value, threshold) ->
isWarning ? format("Creating table %s, current number of
tables %s exceeds warning threshold of %s.",
what, value, threshold)
@@ -58,7 +71,8 @@ public final class Guardrails implements GuardrailsMBean
* Guardrail on the number of columns per table.
*/
public static final Threshold columnsPerTable =
- new Threshold(state ->
CONFIG_PROVIDER.getOrCreate(state).getColumnsPerTable(),
+ new Threshold(state ->
CONFIG_PROVIDER.getOrCreate(state).getColumnsPerTable().getWarnThreshold(),
+ state ->
CONFIG_PROVIDER.getOrCreate(state).getColumnsPerTable().getAbortThreshold(),
(isWarning, what, value, threshold) ->
isWarning ? format("The table %s has %s columns, this
exceeds the warning threshold of %s.",
what, value, threshold)
@@ -66,7 +80,8 @@ public final class Guardrails implements GuardrailsMBean
threshold, value, what));
public static final Threshold secondaryIndexesPerTable =
- new Threshold(state ->
CONFIG_PROVIDER.getOrCreate(state).getSecondaryIndexesPerTable(),
+ new Threshold(state ->
CONFIG_PROVIDER.getOrCreate(state).getSecondaryIndexesPerTable().getWarnThreshold(),
+ state ->
CONFIG_PROVIDER.getOrCreate(state).getSecondaryIndexesPerTable().getAbortThreshold(),
(isWarning, what, value, threshold) ->
isWarning ? format("Creating secondary index %s, current
number of indexes %s exceeds warning threshold of %s.",
what, value, threshold)
@@ -77,7 +92,8 @@ public final class Guardrails implements GuardrailsMBean
* Guardrail on the number of materialized views per table.
*/
public static final Threshold materializedViewsPerTable =
- new Threshold(state ->
CONFIG_PROVIDER.getOrCreate(state).getMaterializedViewsPerTable(),
+ new Threshold(state ->
CONFIG_PROVIDER.getOrCreate(state).getMaterializedViewsPerTable().getWarnThreshold(),
+ state ->
CONFIG_PROVIDER.getOrCreate(state).getMaterializedViewsPerTable().getAbortThreshold(),
(isWarning, what, value, threshold) ->
isWarning ? format("Creating materialized view %s, current
number of views %s exceeds warning threshold of %s.",
what, value, threshold)
@@ -88,7 +104,8 @@ public final class Guardrails implements GuardrailsMBean
* Guardrail ignoring/disallowing the usage of certain table properties.
*/
public static final Values<String> tableProperties =
- new Values<>(state ->
CONFIG_PROVIDER.getOrCreate(state).getTableProperties(),
+ new Values<>(state ->
CONFIG_PROVIDER.getOrCreate(state).getTableProperties().getIgnored(),
+ state ->
CONFIG_PROVIDER.getOrCreate(state).getTableProperties().getDisallowed(),
"Table Properties");
/**
@@ -102,14 +119,14 @@ public final class Guardrails implements GuardrailsMBean
* Guardrail on the number of elements returned within page.
*/
public static final Threshold pageSize =
- new Threshold(state -> CONFIG_PROVIDER.getOrCreate(state).getPageSize(),
+ new Threshold(state ->
CONFIG_PROVIDER.getOrCreate(state).getPageSize().getWarnThreshold(),
+ state ->
CONFIG_PROVIDER.getOrCreate(state).getPageSize().getAbortThreshold(),
(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 abort threshold of %s.",
what, value, threshold));
-
private Guardrails()
{
MBeanWrapper.instance.registerMBean(this, MBEAN_NAME);
@@ -139,15 +156,33 @@ public final class Guardrails implements GuardrailsMBean
}
@Override
+ public int getKeyspacesWarnThreshold()
+ {
+ return DEFAULT_CONFIG.getKeyspaces().getWarnThreshold();
+ }
+
+ @Override
+ public int getKeyspacesAbortThreshold()
+ {
+ return DEFAULT_CONFIG.getKeyspaces().getAbortThreshold();
+ }
+
+ @Override
+ public void setKeyspacesThreshold(int warn, int abort)
+ {
+ DEFAULT_CONFIG.getKeyspaces().setThresholds(warn, abort);
+ }
+
+ @Override
public int getTablesWarnThreshold()
{
- return (int) DEFAULT_CONFIG.getTables().getWarnThreshold();
+ return DEFAULT_CONFIG.getTables().getWarnThreshold();
}
@Override
public int getTablesAbortThreshold()
{
- return (int) DEFAULT_CONFIG.getTables().getAbortThreshold();
+ return DEFAULT_CONFIG.getTables().getAbortThreshold();
}
@Override
@@ -159,13 +194,13 @@ public final class Guardrails implements GuardrailsMBean
@Override
public int getColumnsPerTableWarnThreshold()
{
- return (int) DEFAULT_CONFIG.getColumnsPerTable().getWarnThreshold();
+ return DEFAULT_CONFIG.getColumnsPerTable().getWarnThreshold();
}
@Override
public int getColumnsPerTableAbortThreshold()
{
- return (int) DEFAULT_CONFIG.getColumnsPerTable().getAbortThreshold();
+ return DEFAULT_CONFIG.getColumnsPerTable().getAbortThreshold();
}
@Override
@@ -177,13 +212,13 @@ public final class Guardrails implements GuardrailsMBean
@Override
public int getSecondaryIndexesPerTableWarnThreshold()
{
- return (int)
DEFAULT_CONFIG.getSecondaryIndexesPerTable().getWarnThreshold();
+ return DEFAULT_CONFIG.getSecondaryIndexesPerTable().getWarnThreshold();
}
@Override
public int getSecondaryIndexesPerTableAbortThreshold()
{
- return (int)
DEFAULT_CONFIG.getSecondaryIndexesPerTable().getAbortThreshold();
+ return
DEFAULT_CONFIG.getSecondaryIndexesPerTable().getAbortThreshold();
}
@Override
@@ -195,13 +230,13 @@ public final class Guardrails implements GuardrailsMBean
@Override
public int getMaterializedViewsPerTableWarnThreshold()
{
- return (int)
DEFAULT_CONFIG.getMaterializedViewsPerTable().getWarnThreshold();
+ return
DEFAULT_CONFIG.getMaterializedViewsPerTable().getWarnThreshold();
}
@Override
public int getMaterializedViewsPerTableAbortThreshold()
{
- return (int)
DEFAULT_CONFIG.getMaterializedViewsPerTable().getAbortThreshold();
+ return
DEFAULT_CONFIG.getMaterializedViewsPerTable().getAbortThreshold();
}
@Override
@@ -230,7 +265,7 @@ public final class Guardrails implements GuardrailsMBean
@Override
public void setTablePropertiesDisallowed(Set<String> properties)
{
- DEFAULT_CONFIG.getTableProperties().setDisallowedValues(properties);
+ DEFAULT_CONFIG.getTableProperties().setDisallowed(properties);
}
@Override
@@ -259,7 +294,7 @@ public final class Guardrails implements GuardrailsMBean
@Override
public void setTablePropertiesIgnored(Set<String> properties)
{
- DEFAULT_CONFIG.getTableProperties().setIgnoredValues(properties);
+ DEFAULT_CONFIG.getTableProperties().setIgnored(properties);
}
@Override
@@ -283,13 +318,13 @@ public final class Guardrails implements GuardrailsMBean
@Override
public int getPageSizeWarnThreshold()
{
- return (int) DEFAULT_CONFIG.getPageSize().getWarnThreshold();
+ return DEFAULT_CONFIG.getPageSize().getWarnThreshold();
}
@Override
public int getPageSizeAbortThreshold()
{
- return (int) DEFAULT_CONFIG.getPageSize().getAbortThreshold();
+ return DEFAULT_CONFIG.getPageSize().getAbortThreshold();
}
@Override
diff --git a/src/java/org/apache/cassandra/db/guardrails/GuardrailsConfig.java
b/src/java/org/apache/cassandra/db/guardrails/GuardrailsConfig.java
index df00a8d..c34f224 100644
--- a/src/java/org/apache/cassandra/db/guardrails/GuardrailsConfig.java
+++ b/src/java/org/apache/cassandra/db/guardrails/GuardrailsConfig.java
@@ -18,6 +18,8 @@
package org.apache.cassandra.db.guardrails;
+import java.util.Set;
+
/**
* Configuration settings for guardrails.
*
@@ -49,29 +51,34 @@ public interface GuardrailsConfig
boolean getEnabled();
/**
- * @return The threshold to warn or abort when creating more tables than
threshold.
+ * @return The threshold to warn or abort when creating more user
keyspaces than threshold.
+ */
+ IntThreshold getKeyspaces();
+
+ /**
+ * @return The threshold to warn or abort when creating more user tables
than threshold.
*/
- Threshold.Config getTables();
+ IntThreshold getTables();
/**
* @return The threshold to warn or abort when creating more columns per
table than threshold.
*/
- Threshold.Config getColumnsPerTable();
+ IntThreshold getColumnsPerTable();
/**
* @return The threshold to warn or abort when creating more secondary
indexes per table than threshold.
*/
- Threshold.Config getSecondaryIndexesPerTable();
+ IntThreshold getSecondaryIndexesPerTable();
/**
* @return The threshold to warn or abort when creating more materialized
views per table than threshold.
*/
- Threshold.Config getMaterializedViewsPerTable();
+ IntThreshold getMaterializedViewsPerTable();
/**
* @return The table properties that are ignored/disallowed when creating
or altering a table.
*/
- Values.Config<String> getTableProperties();
+ TableProperties getTableProperties();
/**
* Returns whether user-provided timestamps are allowed.
@@ -83,5 +90,38 @@ public interface GuardrailsConfig
/**
* @return The threshold to warn or abort when page size exceeds given
size.
*/
- Threshold.Config getPageSize();
+ IntThreshold getPageSize();
+
+ /**
+ * Configuration of {@code int}-based thresholds to check if the guarded
value should trigger a warning or abort the
+ * operation.
+ */
+ public interface IntThreshold
+ {
+ /**
+ * @return The threshold to warn when the guarded value exceeds it. A
negative value means disabled.
+ */
+ public int getWarnThreshold();
+
+ /**
+ * @return The threshold to abort the operation when the guarded value
exceeds it. A negative value means disabled.
+ */
+ public int getAbortThreshold();
+ }
+
+ /**
+ * Configuration class containing the sets of table properties to ignore
and/or reject.
+ */
+ public interface TableProperties
+ {
+ /**
+ * @return The values to be ignored.
+ */
+ Set<String> getIgnored();
+
+ /**
+ * @return The values to be rejected.
+ */
+ Set<String> getDisallowed();
+ }
}
diff --git a/src/java/org/apache/cassandra/db/guardrails/GuardrailsMBean.java
b/src/java/org/apache/cassandra/db/guardrails/GuardrailsMBean.java
index 14ea9b0..c3509ee 100644
--- a/src/java/org/apache/cassandra/db/guardrails/GuardrailsMBean.java
+++ b/src/java/org/apache/cassandra/db/guardrails/GuardrailsMBean.java
@@ -49,6 +49,24 @@ public interface GuardrailsMBean
void setEnabled(boolean enabled);
/**
+ * @return The threshold to warn when creating more user keyspaces than
threshold.
+ * -1 means disabled.
+ */
+ int getKeyspacesWarnThreshold();
+
+ /**
+ * @return The threshold to prevent creating more user keyspaces than
threshold.
+ * -1 means disabled.
+ */
+ int getKeyspacesAbortThreshold();
+
+ /**
+ * @param warn The threshold to warn when creating more user keyspaces
than threshold. -1 means disabled.
+ * @param abort The threshold to prevent creating more user keyspaces than
threshold. -1 means disabled.
+ */
+ void setKeyspacesThreshold(int warn, int abort);
+
+ /**
* @return The threshold to warn when creating more tables than threshold.
* -1 means disabled.
*/
diff --git a/src/java/org/apache/cassandra/db/guardrails/Threshold.java
b/src/java/org/apache/cassandra/db/guardrails/Threshold.java
index 7115b9c..d0fd8eb 100644
--- a/src/java/org/apache/cassandra/db/guardrails/Threshold.java
+++ b/src/java/org/apache/cassandra/db/guardrails/Threshold.java
@@ -18,7 +18,7 @@
package org.apache.cassandra.db.guardrails;
-import java.util.function.Function;
+import java.util.function.ToLongFunction;
import javax.annotation.Nullable;
import org.apache.cassandra.service.ClientState;
@@ -33,18 +33,23 @@ import org.apache.cassandra.service.ClientState;
*/
public class Threshold extends Guardrail
{
- private final Function<ClientState, Config> configProvider;
+ private final ToLongFunction<ClientState> warnThreshold;
+ private final ToLongFunction<ClientState> abortThreshold;
private final ErrorMessageProvider messageProvider;
/**
* Creates a new threshold guardrail.
*
- * @param configProvider a {@link ClientState}-based provider of {@link
Config}s.
+ * @param warnThreshold a {@link ClientState}-based provider of the
value above which a warning should be triggered.
+ * @param abortThreshold 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 Threshold(Function<ClientState, Config> configProvider,
ErrorMessageProvider messageProvider)
+ public Threshold(ToLongFunction<ClientState> warnThreshold,
+ ToLongFunction<ClientState> abortThreshold,
+ ErrorMessageProvider messageProvider)
{
- this.configProvider = configProvider;
+ this.warnThreshold = warnThreshold;
+ this.abortThreshold = abortThreshold;
this.messageProvider = messageProvider;
}
@@ -56,15 +61,15 @@ public class Threshold extends Guardrail
thresholdValue);
}
- private long abortValue(Config config)
+ private long abortValue(ClientState state)
{
- long abortValue = config.getAbortThreshold();
+ long abortValue = abortThreshold.applyAsLong(state);
return abortValue < 0 ? Long.MAX_VALUE : abortValue;
}
- private long warnValue(Config config)
+ private long warnValue(ClientState state)
{
- long warnValue = config.getWarnThreshold();
+ long warnValue = warnThreshold.applyAsLong(state);
return warnValue < 0 ? Long.MAX_VALUE : warnValue;
}
@@ -74,8 +79,7 @@ public class Threshold extends Guardrail
if (!super.enabled(state))
return false;
- Config config = configProvider.apply(state);
- return config.getAbortThreshold() >= 0 || config.getWarnThreshold() >=
0;
+ return abortThreshold.applyAsLong(state) >= 0 ||
warnThreshold.applyAsLong(state) >= 0;
}
/**
@@ -93,16 +97,14 @@ public class Threshold extends Guardrail
if (!enabled(state))
return;
- Config config = configProvider.apply(state);
-
- long abortValue = abortValue(config);
+ long abortValue = abortValue(state);
if (value > abortValue)
{
triggerAbort(value, abortValue, what);
return;
}
- long warnValue = warnValue(config);
+ long warnValue = warnValue(state);
if (value > warnValue)
triggerWarn(value, warnValue, what);
}
@@ -133,21 +135,4 @@ public class Threshold extends Guardrail
*/
String createMessage(boolean isWarning, String what, long value, long
threshold);
}
-
- /**
- * Configuration class containing the thresholds to be used to check if
the guarded value should trigger a warning
- * or abort the operation.
- */
- public interface Config
- {
- /**
- * @return The threshold to warn when the guarded value exceeds it. A
negative value means disabled.
- */
- public long getWarnThreshold();
-
- /**
- * @return The threshold to abort the operation when the guarded value
exceeds it. A negative value means disabled.
- */
- public long getAbortThreshold();
- }
}
diff --git a/src/java/org/apache/cassandra/db/guardrails/Values.java
b/src/java/org/apache/cassandra/db/guardrails/Values.java
index 969b1f6..66508a1 100644
--- a/src/java/org/apache/cassandra/db/guardrails/Values.java
+++ b/src/java/org/apache/cassandra/db/guardrails/Values.java
@@ -37,18 +37,23 @@ import static java.lang.String.format;
*/
public class Values<T> extends Guardrail
{
- private final Function<ClientState, Config<T>> configProvider;
+ private final Function<ClientState, Set<T>> ignoredValues;
+ private final Function<ClientState, Set<T>> disallowedValues;
private final String what;
/**
* Creates a new values guardrail.
*
- * @param configProvider a {@link ClientState}-based provider of {@link
Config}s.
- * @param what The feature that is guarded by this guardrail
(for reporting in error messages).
+ * @param ignoredValues a {@link ClientState}-based of the values that
are ignored.
+ * @param disallowedValues a {@link ClientState}-based of the values that
are disallowed.
+ * @param what The feature that is guarded by this guardrail
(for reporting in error messages).
*/
- public Values(Function<ClientState, Config<T>> configProvider, String what)
+ public Values(Function<ClientState, Set<T>> ignoredValues,
+ Function<ClientState, Set<T>> disallowedValues,
+ String what)
{
- this.configProvider = configProvider;
+ this.ignoredValues = ignoredValues;
+ this.disallowedValues = disallowedValues;
this.what = what;
}
@@ -67,37 +72,19 @@ public class Values<T> extends Guardrail
if (!enabled(state))
return;
- Config<T> config = configProvider.apply(state);
-
- Set<T> disallowed = config.getDisallowed();
+ Set<T> disallowed = disallowedValues.apply(state);
Set<T> toDisallow = Sets.intersection(values, disallowed);
if (!toDisallow.isEmpty())
abort(format("Provided values %s are not allowed for %s
(disallowed values are: %s)",
-
toDisallow.stream().sorted().collect(Collectors.toList()), what,
disallowed.toString()));
+
toDisallow.stream().sorted().collect(Collectors.toList()), what, disallowed));
- Set<T> ignored = config.getIgnored();
+ Set<T> ignored = ignoredValues.apply(state);
Set<T> toIgnore = Sets.intersection(values, ignored);
if (!toIgnore.isEmpty())
{
warn(format("Ignoring provided values %s as they are not supported
for %s (ignored values are: %s)",
-
toIgnore.stream().sorted().collect(Collectors.toList()), what,
ignored.toString()));
+
toIgnore.stream().sorted().collect(Collectors.toList()), what, ignored));
toIgnore.forEach(ignoreAction);
}
}
-
- /**
- * Configuration class containing the sets of values to ignore and/or
reject.
- */
- public interface Config<T>
- {
- /**
- * @return The values to be ignored.
- */
- Set<T> getIgnored();
-
- /**
- * @return The values to be rejected.
- */
- Set<T> getDisallowed();
- }
}
diff --git a/src/java/org/apache/cassandra/service/StorageService.java
b/src/java/org/apache/cassandra/service/StorageService.java
index 8d07784..38fa191 100644
--- a/src/java/org/apache/cassandra/service/StorageService.java
+++ b/src/java/org/apache/cassandra/service/StorageService.java
@@ -6166,11 +6166,13 @@ public class StorageService extends
NotificationBroadcasterSupport implements IE
DatabaseDescriptor.setAutoOptimisePreviewRepairStreams(enabled);
}
+ @Deprecated
public int getTableCountWarnThreshold()
{
return DatabaseDescriptor.tableCountWarnThreshold();
}
+ @Deprecated
public void setTableCountWarnThreshold(int value)
{
if (value < 0)
@@ -6179,11 +6181,13 @@ public class StorageService extends
NotificationBroadcasterSupport implements IE
DatabaseDescriptor.setTableCountWarnThreshold(value);
}
+ @Deprecated
public int getKeyspaceCountWarnThreshold()
{
return DatabaseDescriptor.keyspaceCountWarnThreshold();
}
+ @Deprecated
public void setKeyspaceCountWarnThreshold(int value)
{
if (value < 0)
diff --git a/src/java/org/apache/cassandra/service/StorageServiceMBean.java
b/src/java/org/apache/cassandra/service/StorageServiceMBean.java
index dcc1b1e..0f3ac51 100644
--- a/src/java/org/apache/cassandra/service/StorageServiceMBean.java
+++ b/src/java/org/apache/cassandra/service/StorageServiceMBean.java
@@ -895,9 +895,14 @@ public interface StorageServiceMBean extends
NotificationEmitter
public boolean autoOptimisePreviewRepairStreams();
public void setAutoOptimisePreviewRepairStreams(boolean enabled);
+ // warning thresholds will be replaced by equivalent guardrails
+ @Deprecated
int getTableCountWarnThreshold();
+ @Deprecated
void setTableCountWarnThreshold(int value);
+ @Deprecated
int getKeyspaceCountWarnThreshold();
+ @Deprecated
void setKeyspaceCountWarnThreshold(int value);
public void setCompactionTombstoneWarningThreshold(int count);
diff --git
a/test/unit/org/apache/cassandra/config/DatabaseDescriptorRefTest.java
b/test/unit/org/apache/cassandra/config/DatabaseDescriptorRefTest.java
index 7c398c4..9fd1128 100644
--- a/test/unit/org/apache/cassandra/config/DatabaseDescriptorRefTest.java
+++ b/test/unit/org/apache/cassandra/config/DatabaseDescriptorRefTest.java
@@ -93,7 +93,10 @@ public class DatabaseDescriptorRefTest
"org.apache.cassandra.config.EncryptionOptions$ServerEncryptionOptions$OutgoingEncryptedPortSource",
"org.apache.cassandra.db.guardrails.GuardrailsConfig",
"org.apache.cassandra.db.guardrails.GuardrailsConfigMBean",
+ "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$IntThreshold",
"org.apache.cassandra.config.GuardrailsOptions$TableProperties",
"org.apache.cassandra.config.GuardrailsOptions$Threshold",
diff --git
a/test/unit/org/apache/cassandra/db/guardrails/GuardrailKeyspacesTest.java
b/test/unit/org/apache/cassandra/db/guardrails/GuardrailKeyspacesTest.java
new file mode 100644
index 0000000..281b197
--- /dev/null
+++ b/test/unit/org/apache/cassandra/db/guardrails/GuardrailKeyspacesTest.java
@@ -0,0 +1,117 @@
+/*
+ * 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 org.junit.Test;
+
+import org.apache.cassandra.config.DatabaseDescriptor;
+import org.apache.cassandra.schema.Schema;
+
+import static java.lang.String.format;
+
+/**
+ * Tests the guardrail for the max number of user keyspaces, {@link
Guardrails#keyspaces}.
+ */
+public class GuardrailKeyspacesTest extends ThresholdTester
+{
+ private static final int WARN_THRESHOLD = 3; // CQLTester creates two
keyspaces
+ private static final int ABORT_THRESHOLD = WARN_THRESHOLD + 1;
+
+ public GuardrailKeyspacesTest()
+ {
+ super(WARN_THRESHOLD,
+ ABORT_THRESHOLD,
+ DatabaseDescriptor.getGuardrailsConfig().getKeyspaces(),
+ Guardrails::setKeyspacesThreshold,
+ Guardrails::getKeyspacesWarnThreshold,
+ Guardrails::getKeyspacesAbortThreshold);
+ }
+
+ @Override
+ protected long currentValue()
+ {
+ return Schema.instance.getUserKeyspaces().size();
+ }
+
+ @Test
+ public void testCreateKeyspace() throws Throwable
+ {
+ // create keyspaces until hitting the two warn/abort thresholds
+ String k1 = assertCreateKeyspaceValid();
+ String k2 = assertCreateKeyspaceWarns();
+ assertCreateKeyspaceAborts();
+
+ // drop a keyspace and hit the warn/abort threshold again
+ dropKeyspace(k2);
+ String k3 = assertCreateKeyspaceWarns();
+ assertCreateKeyspaceAborts();
+
+ // drop two keyspaces and hit the warn/abort threshold again
+ dropKeyspace(k1);
+ dropKeyspace(k3);
+ assertCreateKeyspaceValid();
+ assertCreateKeyspaceWarns();
+ assertCreateKeyspaceAborts();
+
+ // test excluded users
+ testExcludedUsers(this::createKeyspaceQuery,
+ this::createKeyspaceQuery,
+ this::createKeyspaceQuery);
+ }
+
+ private void dropKeyspace(String keyspaceName)
+ {
+ schemaChange(format("DROP KEYSPACE %s", keyspaceName));
+ }
+
+ private String assertCreateKeyspaceValid() throws Throwable
+ {
+ String keyspaceName = createKeyspaceName();
+ assertThresholdValid(createKeyspaceQuery(keyspaceName));
+ return keyspaceName;
+ }
+
+ private String assertCreateKeyspaceWarns() throws Throwable
+ {
+ String keyspaceName = createKeyspaceName();
+ assertThresholdWarns(format("Creating keyspace %s, current number of
keyspaces %d exceeds warning threshold of %d",
+ keyspaceName, currentValue() + 1,
WARN_THRESHOLD),
+ createKeyspaceQuery(keyspaceName));
+ return keyspaceName;
+ }
+
+ private void assertCreateKeyspaceAborts() throws Throwable
+ {
+ String keyspaceName = createKeyspaceName();
+ assertThresholdAborts(format("Cannot have more than %d keyspaces,
aborting the creation of keyspace %s",
+ ABORT_THRESHOLD, keyspaceName),
+ createKeyspaceQuery(keyspaceName));
+ }
+
+ private String createKeyspaceQuery()
+ {
+ return createKeyspaceQuery(createKeyspaceName());
+ }
+
+ private String createKeyspaceQuery(String keyspaceName)
+ {
+ return format("CREATE KEYSPACE %s WITH replication={ 'class' :
'SimpleStrategy', 'replication_factor' : 1 }",
+ keyspaceName);
+ }
+}
diff --git
a/test/unit/org/apache/cassandra/db/guardrails/GuardrailTablePropertiesTest.java
b/test/unit/org/apache/cassandra/db/guardrails/GuardrailTablePropertiesTest.java
index 818a0b6..c4ea369 100644
---
a/test/unit/org/apache/cassandra/db/guardrails/GuardrailTablePropertiesTest.java
+++
b/test/unit/org/apache/cassandra/db/guardrails/GuardrailTablePropertiesTest.java
@@ -30,6 +30,7 @@ import com.google.common.collect.ImmutableSet;
import org.junit.Before;
import org.junit.Test;
+import org.apache.cassandra.config.DatabaseDescriptor;
import org.apache.cassandra.cql3.statements.schema.TableAttributes;
import static java.lang.String.format;
@@ -45,6 +46,10 @@ public class GuardrailTablePropertiesTest extends
GuardrailTester
"WHERE pk IS NOT null and ck IS
NOT null PRIMARY KEY(ck, pk) %s";
private static final String ALTER_VIEW = "ALTER MATERIALIZED VIEW %s.%s
WITH %s";
+ private static final String PROPERTY_NAME =
DatabaseDescriptor.getGuardrailsConfig().getTableProperties().getName();
+ private static final String IGNORED_PROPERTY_NAME = PROPERTY_NAME +
".ignored";
+ private static final String DISALLOWED_PROPERTY_NAME = PROPERTY_NAME +
".disallowed";
+
@Before
public void before()
{
@@ -62,9 +67,9 @@ public class GuardrailTablePropertiesTest extends
GuardrailTester
@Test
public void testConfigValidation()
{
- String message = "Invalid value for %s properties: null is not
allowed";
- assertInvalidProperty(Guardrails::setTablePropertiesIgnored,
(Set<String>) null, message, "ignored");
- assertInvalidProperty(Guardrails::setTablePropertiesDisallowed,
(Set<String>) null, message, "disallowed");
+ String message = "Invalid value for %s: null is not allowed";
+ assertInvalidProperty(Guardrails::setTablePropertiesIgnored,
(Set<String>) null, message, IGNORED_PROPERTY_NAME);
+ assertInvalidProperty(Guardrails::setTablePropertiesDisallowed,
(Set<String>) null, message, DISALLOWED_PROPERTY_NAME);
assertValidProperty(Collections.emptySet());
assertValidProperty(TableAttributes.allKeywords());
@@ -82,9 +87,9 @@ public class GuardrailTablePropertiesTest extends
GuardrailTester
private void assertInvalidProperty(Set<String> properties, Set<String>
rejected)
{
- String message = "Invalid value for %s properties: '%s' do not parse
as valid table properties";
- assertInvalidProperty(Guardrails::setTablePropertiesIgnored,
properties, message, "ignored", rejected);
- assertInvalidProperty(Guardrails::setTablePropertiesDisallowed,
properties, message, "disallowed", rejected);
+ String message = "Invalid value for %s: '%s' do not parse as valid
table properties";
+ assertInvalidProperty(Guardrails::setTablePropertiesIgnored,
properties, message, IGNORED_PROPERTY_NAME, rejected);
+ assertInvalidProperty(Guardrails::setTablePropertiesDisallowed,
properties, message, DISALLOWED_PROPERTY_NAME, rejected);
}
@Test
diff --git
a/test/unit/org/apache/cassandra/db/guardrails/GuardrailTablesLimitTest.java
b/test/unit/org/apache/cassandra/db/guardrails/GuardrailTablesTest.java
similarity index 96%
rename from
test/unit/org/apache/cassandra/db/guardrails/GuardrailTablesLimitTest.java
rename to test/unit/org/apache/cassandra/db/guardrails/GuardrailTablesTest.java
index 96f1681..7a32b78 100644
--- a/test/unit/org/apache/cassandra/db/guardrails/GuardrailTablesLimitTest.java
+++ b/test/unit/org/apache/cassandra/db/guardrails/GuardrailTablesTest.java
@@ -26,14 +26,14 @@ import org.apache.cassandra.db.Keyspace;
import static java.lang.String.format;
/**
- * Tests the guardrail for the max number of user tables, {@link
Guardrails#tablesLimit}.
+ * Tests the guardrail for the max number of user tables, {@link
Guardrails#tables}.
*/
-public class GuardrailTablesLimitTest extends ThresholdTester
+public class GuardrailTablesTest extends ThresholdTester
{
private static final int TABLES_LIMIT_WARN_THRESHOLD = 1;
private static final int TABLES_LIMIT_ABORT_THRESHOLD = 2;
- public GuardrailTablesLimitTest()
+ public GuardrailTablesTest()
{
super(TABLES_LIMIT_WARN_THRESHOLD,
TABLES_LIMIT_ABORT_THRESHOLD,
diff --git
a/test/unit/org/apache/cassandra/db/guardrails/GuardrailsConfigProviderTest.java
b/test/unit/org/apache/cassandra/db/guardrails/GuardrailsConfigProviderTest.java
index 20e1aea..24be9a9 100644
---
a/test/unit/org/apache/cassandra/db/guardrails/GuardrailsConfigProviderTest.java
+++
b/test/unit/org/apache/cassandra/db/guardrails/GuardrailsConfigProviderTest.java
@@ -34,7 +34,8 @@ public class GuardrailsConfigProviderTest extends
GuardrailTester
{
String name = getClass().getCanonicalName() + '$' +
CustomProvider.class.getSimpleName();
GuardrailsConfigProvider provider =
GuardrailsConfigProvider.build(name);
- Threshold guard = new Threshold(state ->
provider.getOrCreate(state).getTables(),
+ Threshold guard = new Threshold(state ->
provider.getOrCreate(state).getTables().getWarnThreshold(),
+ state ->
provider.getOrCreate(state).getTables().getAbortThreshold(),
(isWarn, what, v, t) -> format("%s:
for %s, %s > %s",
isWarn
? "Warning" : "Aborting", what, v, t));
diff --git a/test/unit/org/apache/cassandra/db/guardrails/GuardrailsTest.java
b/test/unit/org/apache/cassandra/db/guardrails/GuardrailsTest.java
index 13d9ee3..edc4c23 100644
--- a/test/unit/org/apache/cassandra/db/guardrails/GuardrailsTest.java
+++ b/test/unit/org/apache/cassandra/db/guardrails/GuardrailsTest.java
@@ -35,11 +35,13 @@ import static org.junit.Assert.assertTrue;
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(state -> new ThresholdConfig(),
errorMessageProvider));
+ testDisabledThreshold(new Threshold(state -> DISABLED, state ->
DISABLED, errorMessageProvider));
}
private void testDisabledThreshold(Threshold guard) throws Throwable
@@ -56,7 +58,8 @@ public class GuardrailsTest extends GuardrailTester
@Test
public void testThreshold() throws Throwable
{
- Threshold guard = new Threshold(state -> new ThresholdConfig(10, 100),
+ Threshold guard = new Threshold(state -> 10,
+ state -> 100,
(isWarn, what, v, t) -> format("%s:
for %s, %s > %s",
isWarn
? "Warning" : "Aborting", what, v, t));
@@ -73,7 +76,8 @@ public class GuardrailsTest extends GuardrailTester
@Test
public void testWarnOnlyThreshold() throws Throwable
{
- Threshold guard = new Threshold(state -> new ThresholdConfig(10,
ThresholdConfig.DISABLED),
+ Threshold guard = new Threshold(state -> 10,
+ state -> DISABLED,
(isWarn, what, v, t) -> format("%s:
for %s, %s > %s",
isWarn
? "Warning" : "Aborting", what, v, t));
@@ -86,7 +90,8 @@ public class GuardrailsTest extends GuardrailTester
@Test
public void testAbortOnlyThreshold() throws Throwable
{
- Threshold guard = new Threshold(state -> new
ThresholdConfig(ThresholdConfig.DISABLED, 10),
+ Threshold guard = new Threshold(state -> DISABLED,
+ state -> 10,
(isWarn, what, v, t) -> format("%s:
for %s, %s > %s",
isWarn
? "Warning" : "Aborting", what, v, t));
@@ -99,7 +104,8 @@ public class GuardrailsTest extends GuardrailTester
@Test
public void testThresholdUsers() throws Throwable
{
- Threshold guard = new Threshold(state -> new ThresholdConfig(10, 100),
+ Threshold guard = new Threshold(state -> 10,
+ state -> 100,
(isWarn, what, v, t) -> format("%s:
for %s, %s > %s",
isWarn
? "Warning" : "Aborting", what, v, t));
@@ -152,7 +158,8 @@ public class GuardrailsTest extends GuardrailTester
public void testDisallowedValues() throws Throwable
{
// Using a sorted set below to ensure the order in the error message
checked below are not random
- Values<Integer> disallowed = new Values<>(state -> new
ValuesConfig(Collections.emptySet(), insertionOrderedSet(4, 6, 20)),
+ Values<Integer> disallowed = new Values<>(state ->
Collections.emptySet(),
+ state ->
insertionOrderedSet(4, 6, 20),
"integer");
Consumer<Integer> action = i -> Assert.fail("The ignore action
shouldn't have been triggered");
@@ -174,7 +181,8 @@ public class GuardrailsTest extends GuardrailTester
@Test
public void testDisallowedValuesUsers() throws Throwable
{
- Values<Integer> disallowed = new Values<>(state -> new
ValuesConfig(Collections.emptySet(), Collections.singleton(2)),
+ Values<Integer> disallowed = new Values<>(state ->
Collections.emptySet(),
+ state ->
Collections.singleton(2),
"integer");
Consumer<Integer> action = i -> Assert.fail("The ignore action
shouldn't have been triggered");
@@ -207,7 +215,8 @@ public class GuardrailsTest extends GuardrailTester
public void testIgnoredValues() throws Throwable
{
// Using a sorted set below to ensure the order in the error message
checked below are not random
- Values<Integer> ignored = new Values<>(state -> new
ValuesConfig(insertionOrderedSet(4, 6, 20), Collections.emptySet()),
+ Values<Integer> ignored = new Values<>(state -> insertionOrderedSet(4,
6, 20),
+ state -> Collections.emptySet(),
"integer");
Set<Integer> triggeredOn = set();
@@ -245,56 +254,4 @@ public class GuardrailsTest extends GuardrailTester
{
return new LinkedHashSet<>(Arrays.asList(values));
}
-
- private static class ThresholdConfig implements Threshold.Config
- {
- public static final int DISABLED = -1;
-
- private final int warn;
- private final int abort;
-
- public ThresholdConfig()
- {
- this.warn = DISABLED;
- this.abort = DISABLED;
- }
-
- public ThresholdConfig(int warn, int abort)
- {
- this.warn = warn;
- this.abort = abort;
- }
-
- public long getWarnThreshold()
- {
- return warn;
- }
-
- public long getAbortThreshold()
- {
- return abort;
- }
- }
-
- private static class ValuesConfig implements Values.Config<Integer>
- {
- private final Set<Integer> ignored;
- private final Set<Integer> disallowed;
-
- public ValuesConfig(Set<Integer> ignored, Set<Integer> disallowed)
- {
- this.ignored = ignored;
- this.disallowed = disallowed;
- }
-
- public Set<Integer> getIgnored()
- {
- return ignored;
- }
-
- public Set<Integer> getDisallowed()
- {
- return disallowed;
- }
- }
}
diff --git a/test/unit/org/apache/cassandra/db/guardrails/ThresholdTester.java
b/test/unit/org/apache/cassandra/db/guardrails/ThresholdTester.java
index fdaa50b..6974e46 100644
--- a/test/unit/org/apache/cassandra/db/guardrails/ThresholdTester.java
+++ b/test/unit/org/apache/cassandra/db/guardrails/ThresholdTester.java
@@ -37,6 +37,7 @@ import static org.junit.Assert.fail;
*/
public abstract class ThresholdTester extends GuardrailTester
{
+ private final String name;
private final long warnThreshold;
private final long abortThreshold;
private final GuardrailsOptions.Threshold config;
@@ -51,6 +52,7 @@ public abstract class ThresholdTester extends GuardrailTester
ToLongFunction<Guardrails> warnGetter,
ToLongFunction<Guardrails> abortGetter)
{
+ this.name = config.getName();
this.warnThreshold = warnThreshold;
this.abortThreshold = abortThreshold;
this.config = config;
@@ -90,7 +92,7 @@ public abstract class ThresholdTester extends GuardrailTester
@Test
public void testConfigValidation()
{
- testValidationOfThresholdProperties("warn threshold", "abort
threshold");
+ testValidationOfThresholdProperties(name + ".warn_threshold", name +
".abort_threshold");
}
protected void testValidationOfThresholdProperties(String warnName, String
abortName)
@@ -102,7 +104,8 @@ public abstract class ThresholdTester extends
GuardrailTester
setter.accept(guardrails(), -1L, -1L);
Assertions.assertThatThrownBy(() -> setter.accept(guardrails(), 2L,
1L))
- .hasMessageContaining("The warn threshold 2 should be lower
than the abort threshold 1");
+ .hasMessageContaining(format("The warn threshold 2 for %s
should be lower than the abort threshold 1",
+ name));
}
protected void assertThresholdValid(String query) throws Throwable
diff --git
a/test/unit/org/apache/cassandra/schema/CreateTableValidationTest.java
b/test/unit/org/apache/cassandra/schema/CreateTableValidationTest.java
index f2abc7c..5541e35 100644
--- a/test/unit/org/apache/cassandra/schema/CreateTableValidationTest.java
+++ b/test/unit/org/apache/cassandra/schema/CreateTableValidationTest.java
@@ -58,6 +58,7 @@ public class CreateTableValidationTest extends CQLTester
createTable("CREATE TABLE %s (a int PRIMARY KEY, b int) WITH
bloom_filter_fp_chance = 0.1");
}
+ @Deprecated // these warning thresholds will be replaced by equivalent
guardrails
@Test
public void testCreateKeyspaceTableWarning() throws IOException
{
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]