diff --git a/CHANGES.txt b/CHANGES.txt index 8198ece74cab..996c938f00b7 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,4 +1,5 @@ 5.0 + * Disable the deprecated keyspace/table thresholds and convert them to guardrails (CASSANDRA-18617) * Deprecate CloudstackSnitch and remove duplicate code in snitches (CASSANDRA-18438) * Add support for vectors in UDFs (CASSANDRA-18613) * Improve vector value validation errors (CASSANDRA-18652) diff --git a/NEWS.txt b/NEWS.txt index db77d36eba6a..195cefc25a6f 100644 --- a/NEWS.txt +++ b/NEWS.txt @@ -439,7 +439,7 @@ Deprecation No change of functionality in the new one, only name change for clarity in regards to units and to follow naming standartization. - 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 + deprecated in favour of the new `keyspaces_warn_threshold` and `tables_warn_threshold` 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. diff --git a/conf/cassandra.yaml b/conf/cassandra.yaml index 942812a7e1e1..92e092af75da 100644 --- a/conf/cassandra.yaml +++ b/conf/cassandra.yaml @@ -1685,13 +1685,6 @@ repaired_data_tracking_for_partition_reads_enabled: false # mismatches are less actionable than confirmed ones. 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 keyspaces_warn_threshold and tables_warn_threshold -# table_count_warn_threshold: 150 -# keyspace_count_warn_threshold: 40 - # configure the read and write consistency levels for modifications to auth tables # auth_read_consistency_level: LOCAL_QUORUM # auth_write_consistency_level: EACH_QUORUM diff --git a/src/java/org/apache/cassandra/auth/AuthKeyspace.java b/src/java/org/apache/cassandra/auth/AuthKeyspace.java index f0a3da891c4b..75d9871d0370 100644 --- a/src/java/org/apache/cassandra/auth/AuthKeyspace.java +++ b/src/java/org/apache/cassandra/auth/AuthKeyspace.java @@ -17,8 +17,11 @@ */ package org.apache.cassandra.auth; +import java.util.Set; import java.util.concurrent.TimeUnit; +import com.google.common.collect.ImmutableSet; + import org.apache.cassandra.config.CassandraRelevantProperties; import org.apache.cassandra.cql3.statements.schema.CreateTableStatement; import org.apache.cassandra.config.DatabaseDescriptor; @@ -55,6 +58,7 @@ private AuthKeyspace() public static final String ROLE_PERMISSIONS = "role_permissions"; public static final String RESOURCE_ROLE_INDEX = "resource_role_permissons_index"; public static final String NETWORK_PERMISSIONS = "network_permissions"; + public static final Set TABLE_NAMES = ImmutableSet.of(ROLES, ROLE_MEMBERS, ROLE_PERMISSIONS, RESOURCE_ROLE_INDEX, NETWORK_PERMISSIONS); public static final long SUPERUSER_SETUP_DELAY = SUPERUSER_SETUP_DELAY_MS.getLong(); diff --git a/src/java/org/apache/cassandra/config/Config.java b/src/java/org/apache/cassandra/config/Config.java index 5651c4683af3..b69955b7e9c4 100644 --- a/src/java/org/apache/cassandra/config/Config.java +++ b/src/java/org/apache/cassandra/config/Config.java @@ -826,18 +826,15 @@ public static void setClientMode(boolean clientMode) 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; public volatile SubnetGroups client_error_reporting_exclusions = new SubnetGroups(); public volatile SubnetGroups internode_error_reporting_exclusions = new SubnetGroups(); + @Replaces(oldName = "keyspace_count_warn_threshold", converter = Converters.KEYSPACE_COUNT_THRESHOLD_TO_GUARDRAIL, deprecated = true) public volatile int keyspaces_warn_threshold = -1; public volatile int keyspaces_fail_threshold = -1; + @Replaces(oldName = "table_count_warn_threshold", converter = Converters.TABLE_COUNT_THRESHOLD_TO_GUARDRAIL, deprecated = true) public volatile int tables_warn_threshold = -1; public volatile int tables_fail_threshold = -1; public volatile int columns_per_table_warn_threshold = -1; diff --git a/src/java/org/apache/cassandra/config/Converters.java b/src/java/org/apache/cassandra/config/Converters.java index 4b454e2f93a0..74ff7a2476a1 100644 --- a/src/java/org/apache/cassandra/config/Converters.java +++ b/src/java/org/apache/cassandra/config/Converters.java @@ -21,6 +21,8 @@ import java.util.concurrent.TimeUnit; import java.util.function.Function; +import org.apache.cassandra.schema.SchemaConstants; + import static org.apache.cassandra.config.DataRateSpec.DataRateUnit.MEBIBYTES_PER_SECOND; /** @@ -117,7 +119,13 @@ public enum Converters */ MEGABITS_TO_BYTES_PER_SECOND_DATA_RATE(Integer.class, DataRateSpec.LongBytesPerSecondBound.class, i -> DataRateSpec.LongBytesPerSecondBound.megabitsPerSecondInBytesPerSecond(i), - o -> o == null ? null : o.toMegabitsPerSecondAsInt()); + o -> o == null ? null : o.toMegabitsPerSecondAsInt()), + KEYSPACE_COUNT_THRESHOLD_TO_GUARDRAIL(int.class, int.class, + i -> i - SchemaConstants.getLocalAndReplicatedSystemKeyspaceNames().size(), + o -> o == null ? null : o + SchemaConstants.getLocalAndReplicatedSystemKeyspaceNames().size()), + TABLE_COUNT_THRESHOLD_TO_GUARDRAIL(int.class, int.class, + i -> i - SchemaConstants.getLocalAndReplicatedSystemTableNames().size(), + o -> o == null ? null : o + SchemaConstants.getLocalAndReplicatedSystemTableNames().size()); private final Class oldType; private final Class newType; private final Function convert; diff --git a/src/java/org/apache/cassandra/config/DatabaseDescriptor.java b/src/java/org/apache/cassandra/config/DatabaseDescriptor.java index ce834dd37736..5fdccbb8735f 100644 --- a/src/java/org/apache/cassandra/config/DatabaseDescriptor.java +++ b/src/java/org/apache/cassandra/config/DatabaseDescriptor.java @@ -4195,30 +4195,6 @@ public static void setAutoOptimisePreviewRepairStreams(boolean enabled) 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() { 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 ad6bcc472d79..13d52b1e156c 100644 --- a/src/java/org/apache/cassandra/cql3/statements/schema/CreateKeyspaceStatement.java +++ b/src/java/org/apache/cassandra/cql3/statements/schema/CreateKeyspaceStatement.java @@ -31,7 +31,6 @@ import org.apache.cassandra.auth.FunctionResource; 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; @@ -124,22 +123,6 @@ public void validate(ClientState state) Guardrails.keyspaces.guard(Schema.instance.getUserKeyspaces().size() + 1, keyspaceName, false, state); } - @Override - Set 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()) - { - String msg = String.format("Cluster already contains %d keyspaces. Having a large number of keyspaces will significantly slow down schema dependent cluster operations.", - keyspaceCount); - logger.warn(msg); - clientWarnings.add(msg); - } - - return clientWarnings; - } - public static final class Raw extends CQLStatement.Raw { public final String keyspaceName; 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 6e93929d788a..8d0c0b4d2c3a 100644 --- a/src/java/org/apache/cassandra/cql3/statements/schema/CreateTableStatement.java +++ b/src/java/org/apache/cassandra/cql3/statements/schema/CreateTableStatement.java @@ -34,7 +34,6 @@ import org.apache.cassandra.auth.DataResource; import org.apache.cassandra.auth.IResource; import org.apache.cassandra.auth.Permission; -import org.apache.cassandra.config.DatabaseDescriptor; import org.apache.cassandra.cql3.*; import org.apache.cassandra.cql3.functions.masking.ColumnMask; import org.apache.cassandra.db.Keyspace; @@ -426,22 +425,6 @@ else if (!builder.hasRegularColumns()) } } - @Override - public Set 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()) - { - String msg = String.format("Cluster already contains %d tables in %d keyspaces. Having a large number of tables will significantly slow down schema dependent cluster operations.", - tableCount, - Schema.instance.getKeyspaces().size()); - logger.warn(msg); - return ImmutableSet.of(msg); - } - return ImmutableSet.of(); - } - private static class DefaultNames { private static final String DEFAULT_CLUSTERING_NAME = "column"; diff --git a/src/java/org/apache/cassandra/db/SystemKeyspace.java b/src/java/org/apache/cassandra/db/SystemKeyspace.java index 5d81a151abee..d2f6a891452d 100644 --- a/src/java/org/apache/cassandra/db/SystemKeyspace.java +++ b/src/java/org/apache/cassandra/db/SystemKeyspace.java @@ -191,6 +191,12 @@ private SystemKeyspace() BUILT_VIEWS, PREPARED_STATEMENTS, REPAIRS, TOP_PARTITIONS, LEGACY_PEERS, LEGACY_PEER_EVENTS, LEGACY_TRANSFERRED_RANGES, LEGACY_AVAILABLE_RANGES, LEGACY_SIZE_ESTIMATES, LEGACY_SSTABLE_ACTIVITY); + public static final Set TABLE_NAMES = ImmutableSet.of( + BATCHES, PAXOS, PAXOS_REPAIR_HISTORY, BUILT_INDEXES, LOCAL, PEERS_V2, PEER_EVENTS_V2, + COMPACTION_HISTORY, SSTABLE_ACTIVITY_V2, TABLE_ESTIMATES, AVAILABLE_RANGES_V2, TRANSFERRED_RANGES_V2, VIEW_BUILDS_IN_PROGRESS, + BUILT_VIEWS, PREPARED_STATEMENTS, REPAIRS, TOP_PARTITIONS, LEGACY_PEERS, LEGACY_PEER_EVENTS, + LEGACY_TRANSFERRED_RANGES, LEGACY_AVAILABLE_RANGES, LEGACY_SIZE_ESTIMATES, LEGACY_SSTABLE_ACTIVITY); + public static final TableMetadata Batches = parse(BATCHES, "batches awaiting replay", diff --git a/src/java/org/apache/cassandra/schema/SchemaConstants.java b/src/java/org/apache/cassandra/schema/SchemaConstants.java index d9fc4935fa73..2c36d3e35b6b 100644 --- a/src/java/org/apache/cassandra/schema/SchemaConstants.java +++ b/src/java/org/apache/cassandra/schema/SchemaConstants.java @@ -27,7 +27,10 @@ import com.google.common.collect.ImmutableSet; import com.google.common.collect.Sets; +import org.apache.cassandra.auth.AuthKeyspace; import org.apache.cassandra.db.Digest; +import org.apache.cassandra.db.SystemKeyspace; +import org.apache.cassandra.tracing.TraceKeyspace; /** * When adding new String keyspace names here, double check if it needs to be added to PartitionDenylist.canDenylistKeyspace @@ -126,4 +129,28 @@ public static Set getSystemKeyspaces() { return Sets.union(Sets.union(LOCAL_SYSTEM_KEYSPACE_NAMES, REPLICATED_SYSTEM_KEYSPACE_NAMES), VIRTUAL_SYSTEM_KEYSPACE_NAMES); } + + /** + * Returns the set of local and replicated system keyspace names + * @return all local and replicated system keyspace names + */ + public static Set getLocalAndReplicatedSystemKeyspaceNames() + { + return Sets.union(LOCAL_SYSTEM_KEYSPACE_NAMES, REPLICATED_SYSTEM_KEYSPACE_NAMES); + } + + /** + * Returns the set of all local and replicated system table names + * @return all local and replicated system table names + */ + public static Set getLocalAndReplicatedSystemTableNames() + { + return ImmutableSet.builder() + .addAll(SystemKeyspace.TABLE_NAMES) + .addAll(SchemaKeyspaceTables.ALL) + .addAll(TraceKeyspace.TABLE_NAMES) + .addAll(AuthKeyspace.TABLE_NAMES) + .addAll(SystemDistributedKeyspace.TABLE_NAMES) + .build(); + } } diff --git a/src/java/org/apache/cassandra/schema/SystemDistributedKeyspace.java b/src/java/org/apache/cassandra/schema/SystemDistributedKeyspace.java index c11b2c4c9485..e97e6ca00a6b 100644 --- a/src/java/org/apache/cassandra/schema/SystemDistributedKeyspace.java +++ b/src/java/org/apache/cassandra/schema/SystemDistributedKeyspace.java @@ -31,6 +31,7 @@ import java.util.concurrent.TimeUnit; import com.google.common.base.Joiner; +import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.ImmutableMap; import com.google.common.collect.Sets; @@ -93,6 +94,8 @@ private SystemDistributedKeyspace() public static final String PARTITION_DENYLIST_TABLE = "partition_denylist"; + public static final Set TABLE_NAMES = ImmutableSet.of(REPAIR_HISTORY, PARENT_REPAIR_HISTORY, VIEW_BUILD_STATUS, PARTITION_DENYLIST_TABLE); + private static final TableMetadata RepairHistory = parse(REPAIR_HISTORY, "Repair history", diff --git a/src/java/org/apache/cassandra/service/StorageService.java b/src/java/org/apache/cassandra/service/StorageService.java index b562e629f68d..72f8758fb8e7 100644 --- a/src/java/org/apache/cassandra/service/StorageService.java +++ b/src/java/org/apache/cassandra/service/StorageService.java @@ -107,6 +107,7 @@ import org.apache.cassandra.config.CassandraRelevantProperties; import org.apache.cassandra.config.Config; import org.apache.cassandra.config.Config.PaxosStatePurging; +import org.apache.cassandra.config.Converters; import org.apache.cassandra.config.DataStorageSpec; import org.apache.cassandra.config.DatabaseDescriptor; import org.apache.cassandra.config.DurationSpec; @@ -6970,7 +6971,7 @@ public void setAutoOptimisePreviewRepairStreams(boolean enabled) @Deprecated public int getTableCountWarnThreshold() { - return DatabaseDescriptor.tableCountWarnThreshold(); + return (int) Converters.TABLE_COUNT_THRESHOLD_TO_GUARDRAIL.unconvert(Guardrails.instance.getTablesWarnThreshold()); } @Deprecated @@ -6979,13 +6980,14 @@ public void setTableCountWarnThreshold(int value) if (value < 0) throw new IllegalStateException("Table count warn threshold should be positive, not "+value); logger.info("Changing table count warn threshold from {} to {}", getTableCountWarnThreshold(), value); - DatabaseDescriptor.setTableCountWarnThreshold(value); + Guardrails.instance.setTablesThreshold((int) Converters.TABLE_COUNT_THRESHOLD_TO_GUARDRAIL.convert(value), + Guardrails.instance.getTablesFailThreshold()); } @Deprecated public int getKeyspaceCountWarnThreshold() { - return DatabaseDescriptor.keyspaceCountWarnThreshold(); + return (int) Converters.KEYSPACE_COUNT_THRESHOLD_TO_GUARDRAIL.unconvert(Guardrails.instance.getKeyspacesWarnThreshold()); } @Deprecated @@ -6994,7 +6996,8 @@ public void setKeyspaceCountWarnThreshold(int value) if (value < 0) throw new IllegalStateException("Keyspace count warn threshold should be positive, not "+value); logger.info("Changing keyspace count warn threshold from {} to {}", getKeyspaceCountWarnThreshold(), value); - DatabaseDescriptor.setKeyspaceCountWarnThreshold(value); + Guardrails.instance.setKeyspacesThreshold((int) Converters.KEYSPACE_COUNT_THRESHOLD_TO_GUARDRAIL.convert(value), + Guardrails.instance.getKeyspacesFailThreshold()); } @Override diff --git a/src/java/org/apache/cassandra/tracing/TraceKeyspace.java b/src/java/org/apache/cassandra/tracing/TraceKeyspace.java index c6ca1f28a06d..3fe32b824e88 100644 --- a/src/java/org/apache/cassandra/tracing/TraceKeyspace.java +++ b/src/java/org/apache/cassandra/tracing/TraceKeyspace.java @@ -21,6 +21,8 @@ import java.nio.ByteBuffer; import java.util.*; +import com.google.common.collect.ImmutableSet; + import org.apache.cassandra.config.CassandraRelevantProperties; import org.apache.cassandra.cql3.statements.schema.CreateTableStatement; import org.apache.cassandra.config.DatabaseDescriptor; @@ -66,6 +68,7 @@ private TraceKeyspace() public static final String SESSIONS = "sessions"; public static final String EVENTS = "events"; + public static final Set TABLE_NAMES = ImmutableSet.of(SESSIONS, EVENTS); private static final TableMetadata Sessions = parse(SESSIONS, diff --git a/test/unit/org/apache/cassandra/cql3/SystemKeyspaceTablesNamesTest.java b/test/unit/org/apache/cassandra/cql3/SystemKeyspaceTablesNamesTest.java new file mode 100644 index 000000000000..fa7404c87ccd --- /dev/null +++ b/test/unit/org/apache/cassandra/cql3/SystemKeyspaceTablesNamesTest.java @@ -0,0 +1,103 @@ +/* + * 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.cql3; + +import java.util.Set; +import java.util.stream.Collectors; + +import com.google.common.collect.ImmutableSet; +import com.google.common.collect.Sets; +import org.junit.BeforeClass; +import org.junit.Test; + +import org.apache.cassandra.auth.AuthKeyspace; +import org.apache.cassandra.db.SystemKeyspace; +import org.apache.cassandra.schema.KeyspaceMetadata; +import org.apache.cassandra.schema.Schema; +import org.apache.cassandra.schema.SchemaConstants; +import org.apache.cassandra.schema.SchemaKeyspaceTables; +import org.apache.cassandra.schema.SystemDistributedKeyspace; +import org.apache.cassandra.tracing.TraceKeyspace; + +import static java.lang.String.format; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +public class SystemKeyspaceTablesNamesTest extends CQLTester +{ + @BeforeClass + public static void setUp() + { + // Needed for distributed keyspaces + requireNetwork(); + } + + @Test + public void testSystemKeyspaceTableNames() + { + assertExpectedTablesInKeyspace(SchemaConstants.SYSTEM_KEYSPACE_NAME, + "SystemKeyspace.TABLE_NAMES", + SystemKeyspace.TABLE_NAMES); + } + + @Test + public void testSystemSchemaKeyspaceTableNames() + { + assertExpectedTablesInKeyspace(SchemaConstants.SCHEMA_KEYSPACE_NAME, + "SchemaKeyspaceTables.ALL", + ImmutableSet.copyOf(SchemaKeyspaceTables.ALL)); + } + + @Test + public void testSystemTraceKeyspaceTableNames() + { + assertExpectedTablesInKeyspace(SchemaConstants.TRACE_KEYSPACE_NAME, + "TraceKeyspace.TABLE_NAMES", + TraceKeyspace.TABLE_NAMES); + } + + @Test + public void testSystemAuthKeyspaceTableNames() + { + assertExpectedTablesInKeyspace(SchemaConstants.AUTH_KEYSPACE_NAME, + "AuthKeyspace.TABLE_NAMES", + AuthKeyspace.TABLE_NAMES); + } + + @Test + public void testSystemDistributedKeyspaceTableNames() + { + assertExpectedTablesInKeyspace(SchemaConstants.DISTRIBUTED_KEYSPACE_NAME, + "SystemDistributedKeyspace.TABLE_NAMES", + SystemDistributedKeyspace.TABLE_NAMES); + } + + private static void assertExpectedTablesInKeyspace(String keyspaceName, String expectedTableSource, Set expectedTables) + { + KeyspaceMetadata keyspace = Schema.instance.getKeyspaceMetadata(keyspaceName); + assertNotNull(keyspace); + Set actualKeyspaceTables = keyspace.tables.stream().map(t -> t.name).collect(Collectors.toSet()); + + Sets.SetView diff = Sets.difference(actualKeyspaceTables, expectedTables); + assertTrue(format("The following tables are missing from %s: %s", expectedTableSource, diff), diff.isEmpty()); + + diff = Sets.difference(expectedTables, actualKeyspaceTables); + assertTrue(format("The following tables are in %s but should not be: %s", expectedTableSource, diff), diff.isEmpty()); + } +} diff --git a/test/unit/org/apache/cassandra/db/guardrails/GuardrailKeyspacesTest.java b/test/unit/org/apache/cassandra/db/guardrails/GuardrailKeyspacesTest.java index 6c600933b7de..b0843d4b99c6 100644 --- a/test/unit/org/apache/cassandra/db/guardrails/GuardrailKeyspacesTest.java +++ b/test/unit/org/apache/cassandra/db/guardrails/GuardrailKeyspacesTest.java @@ -18,9 +18,15 @@ package org.apache.cassandra.db.guardrails; + +import java.util.concurrent.TimeUnit; + +import org.junit.After; import org.junit.Test; +import org.apache.cassandra.config.Converters; import org.apache.cassandra.schema.Schema; +import org.awaitility.Awaitility; import static java.lang.String.format; @@ -48,8 +54,37 @@ protected long currentValue() return Schema.instance.getUserKeyspaces().size(); } + @After + public void afterTest() throws Throwable + { + // CQLTester deletes keyspaces after tests, but does so asynchronously + super.afterTest(); + + // Wait until only cql_test_keyspace remains + Awaitility.await() + .atMost(10, TimeUnit.MINUTES) + .pollDelay(0, TimeUnit.MILLISECONDS) + .pollInterval(10, TimeUnit.MILLISECONDS) + .until(() -> Schema.instance.getUserKeyspaces().size() == 1); + } + @Test public void testCreateKeyspace() throws Throwable + { + assertCreateKeyspace(); + } + + @Test + public void testCreateKeyspaceWithDeprecatedKeyspaceCountThreshold() throws Throwable + { + // Convert and set a deprecated threshold value based on the total number of keyspaces, not just user keyspaces + int convertedValue = (int) Converters.KEYSPACE_COUNT_THRESHOLD_TO_GUARDRAIL.convert(Schema.instance.getKeyspaces().size()); + Guardrails.instance.setKeyspacesThreshold(convertedValue + 1, convertedValue + 2); + + assertCreateKeyspace(); + } + + private void assertCreateKeyspace() throws Throwable { // create keyspaces until hitting the two warn/fail thresholds String k1 = assertCreateKeyspaceValid(); diff --git a/test/unit/org/apache/cassandra/db/guardrails/GuardrailTablesTest.java b/test/unit/org/apache/cassandra/db/guardrails/GuardrailTablesTest.java index 7e69636600df..cd57e36ed6d5 100644 --- a/test/unit/org/apache/cassandra/db/guardrails/GuardrailTablesTest.java +++ b/test/unit/org/apache/cassandra/db/guardrails/GuardrailTablesTest.java @@ -20,7 +20,9 @@ import org.junit.Test; +import org.apache.cassandra.config.Converters; import org.apache.cassandra.db.Keyspace; +import org.apache.cassandra.schema.Schema; import static java.lang.String.format; @@ -45,11 +47,26 @@ public GuardrailTablesTest() @Override protected long currentValue() { - return Keyspace.open(keyspace()).getColumnFamilyStores().size(); + return Keyspace.open(KEYSPACE_PER_TEST).getColumnFamilyStores().size(); } @Test - public void testCreateTable() throws Throwable + public void testCreateTableWithGuardrailThreshold() throws Throwable + { + assertCreateTable(); + } + + @Test + public void testCreateTableWithDeprecatedTableCountThreshold() throws Throwable + { + // Convert and set a deprecated threshold value based on the total number of tables, not just user tables + int convertedValue = (int) Converters.TABLE_COUNT_THRESHOLD_TO_GUARDRAIL.convert(Schema.instance.getNumberOfTables()); + Guardrails.instance.setTablesThreshold(convertedValue + 1, TABLES_LIMIT_FAIL_THRESHOLD); + + assertCreateTable(); + } + + private void assertCreateTable() throws Throwable { // create tables until hitting the two warn/fail thresholds String t1 = assertCreateTableValid(); @@ -77,7 +94,7 @@ public void testCreateTable() throws Throwable @Override protected void dropTable(String tableName) { - dropFormattedTable(format("DROP TABLE %s.%s", keyspace(), tableName)); + dropFormattedTable(format("DROP TABLE %s.%s", KEYSPACE_PER_TEST, tableName)); } private String assertCreateTableValid() throws Throwable @@ -111,6 +128,6 @@ private String createTableQuery() private String createTableQuery(String tableName) { - return format("CREATE TABLE %s.%s (k1 int, v int, PRIMARY KEY((k1)))", keyspace(), tableName); + return format("CREATE TABLE %s.%s (k1 int, v int, PRIMARY KEY((k1)))", KEYSPACE_PER_TEST, tableName); } } diff --git a/test/unit/org/apache/cassandra/schema/CreateTableValidationTest.java b/test/unit/org/apache/cassandra/schema/CreateTableValidationTest.java index 9682b4f57d4c..4ccb706461bc 100644 --- a/test/unit/org/apache/cassandra/schema/CreateTableValidationTest.java +++ b/test/unit/org/apache/cassandra/schema/CreateTableValidationTest.java @@ -18,23 +18,13 @@ */ package org.apache.cassandra.schema; -import java.io.IOException; -import java.util.List; - -import org.apache.cassandra.config.DatabaseDescriptor; import org.apache.cassandra.cql3.CQLTester; -import org.apache.cassandra.cql3.QueryOptions; import org.apache.cassandra.exceptions.ConfigurationException; import org.apache.cassandra.exceptions.InvalidRequestException; -import org.apache.cassandra.transport.Message; -import org.apache.cassandra.transport.ProtocolVersion; -import org.apache.cassandra.transport.SimpleClient; -import org.apache.cassandra.transport.messages.QueryMessage; import org.junit.Test; import static org.assertj.core.api.Assertions.assertThatExceptionOfType; -import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; public class CreateTableValidationTest extends CQLTester @@ -60,53 +50,6 @@ public void testInvalidBloomFilterFPRatio() throws Throwable 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 - { - requireNetwork(); - int tableCountWarn = DatabaseDescriptor.tableCountWarnThreshold(); - int keyspaceCountWarn = DatabaseDescriptor.keyspaceCountWarnThreshold(); - DatabaseDescriptor.setTableCountWarnThreshold(Schema.instance.getNumberOfTables()); - DatabaseDescriptor.setKeyspaceCountWarnThreshold(Schema.instance.getKeyspaces().size()); - - try (SimpleClient client = newSimpleClient(ProtocolVersion.CURRENT).connect(false)) - { - String createKeyspace = "CREATE KEYSPACE createkswarning%d WITH REPLICATION={'class':'org.apache.cassandra.locator.NetworkTopologyStrategy','datacenter1':'2'}"; - QueryMessage query = new QueryMessage(String.format(createKeyspace, 1), QueryOptions.DEFAULT); - Message.Response resp = client.execute(query); - List warns = resp.getWarnings(); - warns.removeIf(w -> w.contains("is higher than the number of nodes")); - assertTrue(warns.size() > 0); - assertTrue(warns.get(0).contains("Having a large number of keyspaces will significantly")); - - DatabaseDescriptor.setKeyspaceCountWarnThreshold(Schema.instance.getKeyspaces().size() + 2); - query = new QueryMessage(String.format(createKeyspace, 2), QueryOptions.DEFAULT); - resp = client.execute(query); - warns = resp.getWarnings(); - if (warns != null) - warns.removeIf(w -> w.contains("is higher than the number of nodes")); - assertTrue(warns == null || warns.isEmpty()); - - query = new QueryMessage(String.format("CREATE TABLE %s.%s (id int primary key, x int)", KEYSPACE, "test1"), QueryOptions.DEFAULT); - resp = client.execute(query); - warns = resp.getWarnings(); - warns.removeIf(w -> w.contains("is higher than the number of nodes")); - assertTrue(warns.size() > 0); - assertTrue(warns.get(0).contains("Having a large number of tables")); - - DatabaseDescriptor.setTableCountWarnThreshold(Schema.instance.getNumberOfTables() + 1); - query = new QueryMessage(String.format("CREATE TABLE %s.%s (id int primary key, x int)", KEYSPACE, "test2"), QueryOptions.DEFAULT); - resp = client.execute(query); - assertTrue(resp.getWarnings() == null || resp.getWarnings().isEmpty()); - } - finally - { - DatabaseDescriptor.setTableCountWarnThreshold(tableCountWarn); - DatabaseDescriptor.setKeyspaceCountWarnThreshold(keyspaceCountWarn); - } - } - @Test public void testCreateTableOnSelectedClusteringColumn() {