From 9c796dfb272daa3ce57a2dc5cbeadd9273e1ac72 Mon Sep 17 00:00:00 2001 From: Francisco Guerrero Date: Fri, 28 Jul 2023 09:26:20 -0700 Subject: [PATCH] Skip ColumnFamilyStore#topPartitions initialization when client or tool mode This commit skips the initialization of `topPartitions` in `org.apache.cassandra.db.ColumnFamilyStore` when running in client or tool mode. The `TopPartitionTracker` class will attempt to query the system keyspace, which when running in client or tool mode will not be part of the KeyspaceMetadata. This causes a warning to be printed out with a stacktrace that can be misleading. The warning is similar to this: ``` WARN org.apache.cassandra.db.SystemKeyspace: Could not load stored top SIZES partitions for ... org.apache.cassandra.db.KeyspaceNotDefinedException: keyspace system does not exist at org.apache.cassandra.schema.Schema.validateTable(Schema.java:xxx) ~[?:?] at org.apache.cassandra.cql3.statements.SelectStatement$RawStatement.prepare(SelectStatement.java:xxx) ~[?:?] at org.apache.cassandra.cql3.statements.SelectStatement$RawStatement.prepare(SelectStatement.java:xxx) ~[?:?] at org.apache.cassandra.cql3.statements.SelectStatement$RawStatement.prepare(SelectStatement.java:xxx) ~[?:?] at org.apache.cassandra.cql3.QueryProcessor.parseAndPrepare(QueryProcessor.java:xxx) ~[?:?] ... ``` In this commit, we check whether we run in client or tool mode, and skip initialization of `topPartitions` in those cases. Patch by Francisco Guerrero; Reviewed by Dinesh Joshi, Yifan Cai for CASSANDRA-18697 --- CHANGES.txt | 1 + .../cassandra/db/ColumnFamilyStore.java | 2 +- .../db/ColumnFamilyStoreClientModeTest.java | 95 +++++++++++++++++++ 3 files changed, 97 insertions(+), 1 deletion(-) create mode 100644 test/unit/org/apache/cassandra/db/ColumnFamilyStoreClientModeTest.java diff --git a/CHANGES.txt b/CHANGES.txt index 3a60953d4d..5ce92be10e 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,4 +1,5 @@ 4.1.4 + * Skip ColumnFamilyStore#topPartitions initialization when client or tool mode (CASSANDRA-18697) Merged from 4.0: * Fix BulkLoader ignoring cipher suites options (CASSANDRA-18582) * Migrate Python optparse to argparse (CASSANDRA-17914) diff --git a/src/java/org/apache/cassandra/db/ColumnFamilyStore.java b/src/java/org/apache/cassandra/db/ColumnFamilyStore.java index 361952069a..eb6a6dd19c 100644 --- a/src/java/org/apache/cassandra/db/ColumnFamilyStore.java +++ b/src/java/org/apache/cassandra/db/ColumnFamilyStore.java @@ -549,7 +549,7 @@ public class ColumnFamilyStore implements ColumnFamilyStoreMBean, Memtable.Owner repairManager = new CassandraTableRepairManager(this); sstableImporter = new SSTableImporter(this); - if (SchemaConstants.isSystemKeyspace(keyspace.getName())) + if (DatabaseDescriptor.isClientOrToolInitialized() || SchemaConstants.isSystemKeyspace(keyspace.getName())) topPartitions = null; else topPartitions = new TopPartitionTracker(metadata()); diff --git a/test/unit/org/apache/cassandra/db/ColumnFamilyStoreClientModeTest.java b/test/unit/org/apache/cassandra/db/ColumnFamilyStoreClientModeTest.java new file mode 100644 index 0000000000..af77938fda --- /dev/null +++ b/test/unit/org/apache/cassandra/db/ColumnFamilyStoreClientModeTest.java @@ -0,0 +1,95 @@ +/* + * 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; + +import java.io.IOException; +import java.util.UUID; + +import org.apache.commons.lang3.ArrayUtils; +import org.junit.BeforeClass; +import org.junit.ClassRule; +import org.junit.Test; +import org.junit.rules.TemporaryFolder; + +import org.apache.cassandra.config.DatabaseDescriptor; +import org.apache.cassandra.cql3.statements.schema.CreateTableStatement; +import org.apache.cassandra.dht.Murmur3Partitioner; +import org.apache.cassandra.locator.SimpleSnitch; +import org.apache.cassandra.schema.KeyspaceMetadata; +import org.apache.cassandra.schema.KeyspaceParams; +import org.apache.cassandra.schema.Schema; +import org.apache.cassandra.schema.SchemaTransformations; +import org.apache.cassandra.schema.TableId; +import org.apache.cassandra.schema.TableMetadata; +import org.apache.cassandra.schema.TableMetadataRef; +import org.apache.cassandra.schema.Types; +import org.apache.cassandra.service.ClientState; + +import static org.apache.cassandra.cql3.CQLTester.KEYSPACE; +import static org.apache.cassandra.cql3.QueryProcessor.parseStatement; +import static org.junit.Assert.assertNull; + +/** + * Unit tests for {@link ColumnFamilyStore} when the library is running as tool + * or client mode. + */ +public class ColumnFamilyStoreClientModeTest +{ + public static final String TABLE = "test1"; + + @ClassRule + public static TemporaryFolder tempFolder = new TemporaryFolder(); + + @BeforeClass + public static void setUpClass() + { + DatabaseDescriptor.clientInitialization(); + DatabaseDescriptor.setEndpointSnitch(new SimpleSnitch()); + DatabaseDescriptor.getRawConfig().memtable_flush_writers = 1; + DatabaseDescriptor.getRawConfig().local_system_data_file_directory = tempFolder.toString(); + DatabaseDescriptor.getRawConfig().partitioner = "Murmur3Partitioner"; + DatabaseDescriptor.applyPartitioner(); + } + + @Test + public void testTopPartitionsAreNotInitialized() throws IOException + { + CreateTableStatement.Raw schemaStatement = parseStatement("CREATE TABLE " + KEYSPACE + '.' + TABLE + " (a int, b text, PRIMARY KEY (a))", CreateTableStatement.Raw.class, "CREATE TABLE"); + + Schema.instance.transform(SchemaTransformations.addKeyspace(KeyspaceMetadata.create(KEYSPACE, KeyspaceParams.simple(1)), true)); + + Types types = Types.rawBuilder(KEYSPACE).build(); + Schema.instance.transform(SchemaTransformations.addTypes(types, true)); + + ClientState state = ClientState.forInternalCalls(KEYSPACE); + CreateTableStatement statement = schemaStatement.prepare(state); + statement.validate(state); + + TableMetadata tableMetadata = statement.builder(types) + .id(TableId.fromUUID(UUID.nameUUIDFromBytes(ArrayUtils.addAll(schemaStatement.keyspace().getBytes(), schemaStatement.table().getBytes())))) + .partitioner(Murmur3Partitioner.instance) + .build(); + Keyspace.setInitialized(); + Directories directories = new Directories(tableMetadata, new Directories.DataDirectory[]{ new Directories.DataDirectory(new org.apache.cassandra.io.util.File(tempFolder.newFolder("datadir"))) }); + Keyspace ks = Keyspace.openWithoutSSTables(KEYSPACE); + ColumnFamilyStore cfs = ColumnFamilyStore.createColumnFamilyStore(ks, TABLE, TableMetadataRef.forOfflineTools(tableMetadata), directories, false, false, true); + + assertNull(cfs.topPartitions); + } +}