diff --git a/CHANGES.txt b/CHANGES.txt index aa356a2da163..77da14491b7d 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,4 +1,5 @@ 7.0 + * Avoid metadata initialization during legacy table count threshold conversion (CASSANDRA-21156) * Allow CQLSSTableWriter to specify SSTable id generator to use (CASSANDRA-21012) * Reject LIKE patterns with a wildcard (%) anywhere other than the start or end (CASSANDRA-21068) * Support pluggable default role initialization (CASSANDRA-21546) diff --git a/src/java/org/apache/cassandra/auth/AuthKeyspace.java b/src/java/org/apache/cassandra/auth/AuthKeyspace.java index bcc91e5ee6f8..0f0e8b9a4f45 100644 --- a/src/java/org/apache/cassandra/auth/AuthKeyspace.java +++ b/src/java/org/apache/cassandra/auth/AuthKeyspace.java @@ -20,8 +20,6 @@ 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.config.DatabaseDescriptor; import org.apache.cassandra.cql3.statements.schema.CreateTableStatement; @@ -61,10 +59,7 @@ private AuthKeyspace() public static final String CIDR_PERMISSIONS = "cidr_permissions"; public static final String CIDR_GROUPS = "cidr_groups"; public static final String IDENTITY_TO_ROLES = "identity_to_role"; - public static final Set TABLE_NAMES = ImmutableSet.of(ROLES, ROLE_MEMBERS, ROLE_PERMISSIONS, - RESOURCE_ROLE_INDEX, NETWORK_PERMISSIONS, - CIDR_PERMISSIONS, CIDR_GROUPS, - IDENTITY_TO_ROLES); + public static final Set TABLE_NAMES = SchemaConstants.AUTH_KEYSPACE_TABLE_NAMES; public static final long SUPERUSER_SETUP_DELAY = SUPERUSER_SETUP_DELAY_MS.getLong(); diff --git a/src/java/org/apache/cassandra/db/SystemKeyspace.java b/src/java/org/apache/cassandra/db/SystemKeyspace.java index 8010d5b799c6..46e56342ed77 100644 --- a/src/java/org/apache/cassandra/db/SystemKeyspace.java +++ b/src/java/org/apache/cassandra/db/SystemKeyspace.java @@ -227,12 +227,7 @@ private SystemKeyspace() LEGACY_TRANSFERRED_RANGES, LEGACY_AVAILABLE_RANGES, LEGACY_SIZE_ESTIMATES, LEGACY_SSTABLE_ACTIVITY, METADATA_LOG, SNAPSHOT_TABLE_NAME, CONSENSUS_MIGRATION_STATE); - 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, - METADATA_LOG, SNAPSHOT_TABLE_NAME, CONSENSUS_MIGRATION_STATE); + public static final Set TABLE_NAMES = SchemaConstants.SYSTEM_KEYSPACE_TABLE_NAMES; public static final TableMetadata Batches = parse(BATCHES, diff --git a/src/java/org/apache/cassandra/schema/SchemaConstants.java b/src/java/org/apache/cassandra/schema/SchemaConstants.java index ada413537d15..85c77d6f174c 100644 --- a/src/java/org/apache/cassandra/schema/SchemaConstants.java +++ b/src/java/org/apache/cassandra/schema/SchemaConstants.java @@ -72,6 +72,69 @@ public final class SchemaConstants /* replicate system keyspace names (the ones with a "true" replication strategy) */ public static final Set REPLICATED_SYSTEM_KEYSPACE_NAMES = ImmutableSet.of(TRACE_KEYSPACE_NAME, AUTH_KEYSPACE_NAME, DISTRIBUTED_KEYSPACE_NAME, METADATA_KEYSPACE_NAME); + + public static final Set SYSTEM_KEYSPACE_TABLE_NAMES = + ImmutableSet.of(SystemKeyspace.BATCHES, + SystemKeyspace.PAXOS, + SystemKeyspace.PAXOS_REPAIR_HISTORY, + SystemKeyspace.BUILT_INDEXES, + SystemKeyspace.LOCAL, + SystemKeyspace.PEERS_V2, + SystemKeyspace.PEER_EVENTS_V2, + SystemKeyspace.COMPACTION_HISTORY, + SystemKeyspace.SSTABLE_ACTIVITY_V2, + SystemKeyspace.TABLE_ESTIMATES, + SystemKeyspace.AVAILABLE_RANGES_V2, + SystemKeyspace.TRANSFERRED_RANGES_V2, + SystemKeyspace.VIEW_BUILDS_IN_PROGRESS, + SystemKeyspace.BUILT_VIEWS, + SystemKeyspace.PREPARED_STATEMENTS, + SystemKeyspace.REPAIRS, + SystemKeyspace.TOP_PARTITIONS, + SystemKeyspace.LEGACY_PEERS, + SystemKeyspace.LEGACY_PEER_EVENTS, + SystemKeyspace.LEGACY_TRANSFERRED_RANGES, + SystemKeyspace.LEGACY_AVAILABLE_RANGES, + SystemKeyspace.LEGACY_SIZE_ESTIMATES, + SystemKeyspace.LEGACY_SSTABLE_ACTIVITY, + SystemKeyspace.METADATA_LOG, + SystemKeyspace.SNAPSHOT_TABLE_NAME, + SystemKeyspace.CONSENSUS_MIGRATION_STATE); + + public static final Set TRACE_KEYSPACE_TABLE_NAMES = + ImmutableSet.of(TraceKeyspace.SESSIONS, TraceKeyspace.EVENTS); + + public static final Set AUTH_KEYSPACE_TABLE_NAMES = + ImmutableSet.of(AuthKeyspace.ROLES, + AuthKeyspace.ROLE_MEMBERS, + AuthKeyspace.ROLE_PERMISSIONS, + AuthKeyspace.RESOURCE_ROLE_INDEX, + AuthKeyspace.NETWORK_PERMISSIONS, + AuthKeyspace.CIDR_PERMISSIONS, + AuthKeyspace.CIDR_GROUPS, + AuthKeyspace.IDENTITY_TO_ROLES); + + public static final Set DISTRIBUTED_KEYSPACE_TABLE_NAMES = + ImmutableSet.of(SystemDistributedKeyspace.REPAIR_HISTORY, + SystemDistributedKeyspace.PARENT_REPAIR_HISTORY, + SystemDistributedKeyspace.VIEW_BUILD_STATUS, + SystemDistributedKeyspace.PARTITION_DENYLIST_TABLE, + SystemDistributedKeyspace.AUTO_REPAIR_HISTORY, + SystemDistributedKeyspace.AUTO_REPAIR_PRIORITY, + SystemDistributedKeyspace.COMPRESSION_DICTIONARIES); + + public static final Set ACCORD_KEYSPACE_TABLE_NAMES = + ImmutableSet.of(AccordKeyspace.COMMANDS_FOR_KEY, AccordKeyspace.JOURNAL); + + public static final Set LOCAL_AND_REPLICATED_SYSTEM_TABLE_NAMES = + ImmutableSet.builder() + .addAll(SYSTEM_KEYSPACE_TABLE_NAMES) + .addAll(SchemaKeyspaceTables.ALL) + .addAll(TRACE_KEYSPACE_TABLE_NAMES) + .addAll(AUTH_KEYSPACE_TABLE_NAMES) + .addAll(DISTRIBUTED_KEYSPACE_TABLE_NAMES) + .addAll(ACCORD_KEYSPACE_TABLE_NAMES) + .build(); /** * The longest permissible KS or CF name. * @@ -195,13 +258,6 @@ public static Set getLocalAndReplicatedSystemKeyspaceNames() */ 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) - .addAll(AccordKeyspace.TABLE_NAMES) - .build(); + return LOCAL_AND_REPLICATED_SYSTEM_TABLE_NAMES; } } diff --git a/src/java/org/apache/cassandra/schema/SystemDistributedKeyspace.java b/src/java/org/apache/cassandra/schema/SystemDistributedKeyspace.java index 15f8ca6fbee5..afb2783de4ed 100644 --- a/src/java/org/apache/cassandra/schema/SystemDistributedKeyspace.java +++ b/src/java/org/apache/cassandra/schema/SystemDistributedKeyspace.java @@ -36,7 +36,6 @@ import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Joiner; import com.google.common.collect.ImmutableMap; -import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Sets; @@ -110,10 +109,7 @@ private SystemDistributedKeyspace() public static final String COMPRESSION_DICTIONARIES = "compression_dictionaries"; - public static final Set TABLE_NAMES = ImmutableSet.of(REPAIR_HISTORY, PARENT_REPAIR_HISTORY, - VIEW_BUILD_STATUS, PARTITION_DENYLIST_TABLE, - AUTO_REPAIR_HISTORY, AUTO_REPAIR_PRIORITY, - COMPRESSION_DICTIONARIES); + public static final Set TABLE_NAMES = SchemaConstants.DISTRIBUTED_KEYSPACE_TABLE_NAMES; public static final String REPAIR_HISTORY_CQL = "CREATE TABLE IF NOT EXISTS %s (" + "keyspace_name text," diff --git a/src/java/org/apache/cassandra/service/accord/AccordKeyspace.java b/src/java/org/apache/cassandra/service/accord/AccordKeyspace.java index 843e136d276d..a4e7e701932f 100644 --- a/src/java/org/apache/cassandra/service/accord/AccordKeyspace.java +++ b/src/java/org/apache/cassandra/service/accord/AccordKeyspace.java @@ -31,7 +31,6 @@ import com.google.common.annotations.VisibleForTesting; import com.google.common.collect.ImmutableMap; -import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import org.slf4j.Logger; @@ -133,7 +132,7 @@ public class AccordKeyspace public static final String COMMANDS_FOR_KEY = "commands_for_key"; public static final String JOURNAL_INDEX_NAME = "record"; - public static final Set TABLE_NAMES = ImmutableSet.of(COMMANDS_FOR_KEY, JOURNAL); + public static final Set TABLE_NAMES = SchemaConstants.ACCORD_KEYSPACE_TABLE_NAMES; private static final ClusteringIndexFilter FULL_PARTITION = new ClusteringIndexNamesFilter(BTreeSet.of(new ClusteringComparator(), Clustering.EMPTY), false); diff --git a/src/java/org/apache/cassandra/tracing/TraceKeyspace.java b/src/java/org/apache/cassandra/tracing/TraceKeyspace.java index 27985ed785d1..9563dde23841 100644 --- a/src/java/org/apache/cassandra/tracing/TraceKeyspace.java +++ b/src/java/org/apache/cassandra/tracing/TraceKeyspace.java @@ -23,8 +23,6 @@ import java.util.Map; import java.util.Set; -import com.google.common.collect.ImmutableSet; - import org.apache.cassandra.config.CassandraRelevantProperties; import org.apache.cassandra.config.DatabaseDescriptor; import org.apache.cassandra.cql3.statements.schema.CreateTableStatement; @@ -69,7 +67,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); + public static final Set TABLE_NAMES = SchemaConstants.TRACE_KEYSPACE_TABLE_NAMES; public static final String SESSIONS_CQL = "CREATE TABLE IF NOT EXISTS %s (" + "session_id uuid," diff --git a/test/unit/org/apache/cassandra/config/AccordJournalDaemonYamlInitializationTest.java b/test/unit/org/apache/cassandra/config/AccordJournalDaemonYamlInitializationTest.java new file mode 100644 index 000000000000..70f662414c09 --- /dev/null +++ b/test/unit/org/apache/cassandra/config/AccordJournalDaemonYamlInitializationTest.java @@ -0,0 +1,35 @@ +/* + * 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.config; + +import org.junit.Test; + +import static org.apache.cassandra.config.AccordJournalInitializationTestSupport.assertConfiguredJournalIndex; +import static org.apache.cassandra.config.AccordJournalInitializationTestSupport.assertFreshJvm; + +public class AccordJournalDaemonYamlInitializationTest +{ + @Test + public void testJournalIndexAfterDaemonYamlInitialization() + { + assertFreshJvm(); + DatabaseDescriptor.daemonInitialization(AccordJournalInitializationTestSupport::loadConfig); + assertConfiguredJournalIndex(); + } +} diff --git a/test/unit/org/apache/cassandra/config/AccordJournalInitializationTestSupport.java b/test/unit/org/apache/cassandra/config/AccordJournalInitializationTestSupport.java new file mode 100644 index 000000000000..44c882598a40 --- /dev/null +++ b/test/unit/org/apache/cassandra/config/AccordJournalInitializationTestSupport.java @@ -0,0 +1,88 @@ +/* + * 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.config; + +import java.io.IOException; +import java.io.InputStream; +import java.util.Map; + +import org.yaml.snakeyaml.Yaml; + +import org.apache.cassandra.schema.SchemaConstants; +import org.apache.cassandra.schema.TableMetadata; +import org.apache.cassandra.service.accord.AccordKeyspace; + +import static java.nio.charset.StandardCharsets.UTF_8; +import static org.apache.cassandra.config.AccordConfig.RangeIndexMode.journal_sai; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; + +/** Shared fixture for lifecycle tests kept in separate classes for Ant's perTest JVM isolation. */ +final class AccordJournalInitializationTestSupport +{ + private static final int LEGACY_TABLE_THRESHOLD = 400; + private static final int LEGACY_KEYSPACE_THRESHOLD = 20; + + private AccordJournalInitializationTestSupport() + { + } + + static void assertFreshJvm() + { + assertNull("This lifecycle test requires a fresh JVM", DatabaseDescriptor.getRawConfig()); + } + + @SuppressWarnings("unchecked") + static Config loadConfig() + { + // Parse legacy fields inside initialization, before DatabaseDescriptor can publish its Config. + try (InputStream input = AccordJournalInitializationTestSupport.class.getResourceAsStream("/cassandra.yaml")) + { + assertNotNull("Missing test cassandra.yaml", input); + Yaml yaml = new Yaml(); + Map config = yaml.load(input); + Map accord = (Map) config.get("accord"); + accord.put("range_index_mode", "journal_sai"); + config.put("table_count_warn_threshold", LEGACY_TABLE_THRESHOLD); + config.put("keyspace_count_warn_threshold", LEGACY_KEYSPACE_THRESHOLD); + return YamlConfigurationLoader.loadConfig(yaml.dump(config).getBytes(UTF_8)); + } + catch (IOException e) + { + throw new AssertionError("Unable to read test cassandra.yaml", e); + } + } + + static void assertConfiguredJournalIndex() + { + Config config = DatabaseDescriptor.getRawConfig(); + assertNotNull(config); + assertTrue(config.accord.enabled); + assertEquals(journal_sai, config.accord.range_index_mode); + assertEquals(LEGACY_TABLE_THRESHOLD - SchemaConstants.getLocalAndReplicatedSystemTableNames().size(), config.tables_warn_threshold); + assertEquals(LEGACY_KEYSPACE_THRESHOLD - SchemaConstants.getLocalAndReplicatedSystemKeyspaceNames().size(), config.keyspaces_warn_threshold); + + TableMetadata journal = AccordKeyspace.metadata().tables.getNullable(AccordKeyspace.JOURNAL); + assertNotNull(journal); + assertTrue("Configured journal_sai must retain its record index", + journal.indexes.get(AccordKeyspace.JOURNAL_INDEX_NAME).isPresent()); + } +} diff --git a/test/unit/org/apache/cassandra/config/AccordJournalToolYamlInitializationTest.java b/test/unit/org/apache/cassandra/config/AccordJournalToolYamlInitializationTest.java new file mode 100644 index 000000000000..0ab6cbb8408e --- /dev/null +++ b/test/unit/org/apache/cassandra/config/AccordJournalToolYamlInitializationTest.java @@ -0,0 +1,46 @@ +/* + * 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.config; + +import java.util.function.Supplier; + +import org.junit.Test; + +import static org.apache.cassandra.config.AccordJournalInitializationTestSupport.assertConfiguredJournalIndex; +import static org.apache.cassandra.config.AccordJournalInitializationTestSupport.assertFreshJvm; + +public class AccordJournalToolYamlInitializationTest +{ + @Test + public void testJournalIndexAfterToolYamlInitialization() + { + assertFreshJvm(); + Supplier previous = Config.getOverrideLoadConfig(); + Config.setOverrideLoadConfig(AccordJournalInitializationTestSupport::loadConfig); + try + { + DatabaseDescriptor.toolInitialization(); + assertConfiguredJournalIndex(); + } + finally + { + Config.setOverrideLoadConfig(previous); + } + } +} diff --git a/test/unit/org/apache/cassandra/config/TableCountThresholdToGuardrailConverterTest.java b/test/unit/org/apache/cassandra/config/TableCountThresholdToGuardrailConverterTest.java new file mode 100644 index 000000000000..534032aa1b32 --- /dev/null +++ b/test/unit/org/apache/cassandra/config/TableCountThresholdToGuardrailConverterTest.java @@ -0,0 +1,80 @@ +/* + * 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.config; + +import org.junit.BeforeClass; +import org.junit.Test; + +import org.apache.cassandra.schema.SchemaConstants; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; + +/** + * Tests for {@link Converters#TABLE_COUNT_THRESHOLD_TO_GUARDRAIL} and + * {@link Converters#KEYSPACE_COUNT_THRESHOLD_TO_GUARDRAIL} (CASSANDRA-21156). + * + * This test runs in a virgin JVM without {@link DatabaseDescriptor#daemonInitialization()} + * to guarantee that the converter can be called during pre-boot YAML parsing without + * triggering cyclic static initialization dependencies. + */ +public class TableCountThresholdToGuardrailConverterTest +{ + @BeforeClass + public static void loadConvertersBeforeSchemaConstants() + { + assertNull("This test requires a fresh JVM", DatabaseDescriptor.getRawConfig()); + // The conversion must initialize the system-name sets through the converters, not the test. + Converters.TABLE_COUNT_THRESHOLD_TO_GUARDRAIL.convert(1); + Converters.KEYSPACE_COUNT_THRESHOLD_TO_GUARDRAIL.convert(1); + assertNull(DatabaseDescriptor.getRawConfig()); + } + + @Test + public void testTableCountThresholdConversionWithoutDatabaseDescriptorInit() + { + int systemTableCount = SchemaConstants.getLocalAndReplicatedSystemTableNames().size(); + assertTrue("Expected non-zero system tables", systemTableCount > 0); + + assertThresholdBoundaries(Converters.TABLE_COUNT_THRESHOLD_TO_GUARDRAIL, systemTableCount); + } + + @Test + public void testKeyspaceCountThresholdConversion() + { + int systemKeyspaceCount = SchemaConstants.getLocalAndReplicatedSystemKeyspaceNames().size(); + assertTrue("Expected non-zero system keyspaces", systemKeyspaceCount > 0); + + assertThresholdBoundaries(Converters.KEYSPACE_COUNT_THRESHOLD_TO_GUARDRAIL, systemKeyspaceCount); + } + + private static void assertThresholdBoundaries(Converters converter, int systemCount) + { + assertEquals(0, converter.convert(systemCount)); + assertEquals(1, converter.convert(systemCount + 1)); + assertEquals(systemCount + 1, converter.unconvert(1)); + + int legacyThreshold = systemCount + 100; + Object guardrailThreshold = converter.convert(legacyThreshold); + assertEquals(100, guardrailThreshold); + assertEquals(legacyThreshold, converter.unconvert(guardrailThreshold)); + assertNull(converter.unconvert(null)); + } +} diff --git a/test/unit/org/apache/cassandra/schema/SystemTableNamesConsistencyTest.java b/test/unit/org/apache/cassandra/schema/SystemTableNamesConsistencyTest.java new file mode 100644 index 000000000000..e2740b840666 --- /dev/null +++ b/test/unit/org/apache/cassandra/schema/SystemTableNamesConsistencyTest.java @@ -0,0 +1,68 @@ +/* + * 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.schema; + +import java.util.HashSet; +import java.util.Set; + +import org.junit.BeforeClass; +import org.junit.Test; + +import org.apache.cassandra.auth.AuthKeyspace; +import org.apache.cassandra.config.DatabaseDescriptor; +import org.apache.cassandra.db.SystemKeyspace; +import org.apache.cassandra.service.accord.AccordKeyspace; +import org.apache.cassandra.tracing.TraceKeyspace; + +import static org.junit.Assert.assertEquals; + +/** + * Verifies that the table name constant sets registered in {@link SchemaConstants} + * match the actual keyspace table definitions (CASSANDRA-21156). + */ +public class SystemTableNamesConsistencyTest +{ + @BeforeClass + public static void setup() + { + DatabaseDescriptor.daemonInitialization(); + } + + @Test + public void testSystemTableNamesConsistency() + { + Set allTables = new HashSet<>(); + allTables.addAll(assertTableNames(SystemKeyspace.metadata(), SchemaConstants.SYSTEM_KEYSPACE_TABLE_NAMES)); + allTables.addAll(assertTableNames(SchemaKeyspace.metadata(), new HashSet<>(SchemaKeyspaceTables.ALL))); + allTables.addAll(assertTableNames(TraceKeyspace.metadata(), SchemaConstants.TRACE_KEYSPACE_TABLE_NAMES)); + allTables.addAll(assertTableNames(AuthKeyspace.metadata(), SchemaConstants.AUTH_KEYSPACE_TABLE_NAMES)); + allTables.addAll(assertTableNames(SystemDistributedKeyspace.metadata(), SchemaConstants.DISTRIBUTED_KEYSPACE_TABLE_NAMES)); + allTables.addAll(assertTableNames(AccordKeyspace.metadata(), SchemaConstants.ACCORD_KEYSPACE_TABLE_NAMES)); + assertEquals(allTables, SchemaConstants.getLocalAndReplicatedSystemTableNames()); + } + + private static Set assertTableNames(KeyspaceMetadata keyspace, Set expected) + { + Set actual = new HashSet<>(); + for (TableMetadata table : keyspace.tables) + actual.add(table.name); + assertEquals(keyspace.name, expected, actual); + return actual; + } +}