Better handle missing partition columns in system_schema.columns Provide the user workaround if schema table is corrupted.
patch by Jay Zhuang; reviewed by Aleksey Yeschenko for CASSANDRA-14379 Project: http://git-wip-us.apache.org/repos/asf/cassandra/repo Commit: http://git-wip-us.apache.org/repos/asf/cassandra/commit/eb68c312 Tree: http://git-wip-us.apache.org/repos/asf/cassandra/tree/eb68c312 Diff: http://git-wip-us.apache.org/repos/asf/cassandra/diff/eb68c312 Branch: refs/heads/cassandra-3.11 Commit: eb68c3126270e27fd9c88ef867bbcb8c7942a8e8 Parents: 733f6b0 Author: Jay Zhuang <z...@uber.com> Authored: Wed Apr 4 13:49:08 2018 -0700 Committer: Jay Zhuang <jay.zhu...@yahoo.com> Committed: Wed May 2 10:59:47 2018 -0700 ---------------------------------------------------------------------- CHANGES.txt | 1 + .../apache/cassandra/schema/SchemaKeyspace.java | 32 +++++++++++++++----- .../cassandra/schema/SchemaKeyspaceTest.java | 29 ++++++++++++++++++ 3 files changed, 54 insertions(+), 8 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/cassandra/blob/eb68c312/CHANGES.txt ---------------------------------------------------------------------- diff --git a/CHANGES.txt b/CHANGES.txt index 9992802..39edeb1 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,4 +1,5 @@ 3.0.17 + * Better handle missing partition columns in system_schema.columns (CASSANDRA-14379) * Delay hints store excise by write timeout to avoid race with decommission (CASSANDRA-13740) * Deprecate background repair and probablistic read_repair_chance table options (CASSANDRA-13910) http://git-wip-us.apache.org/repos/asf/cassandra/blob/eb68c312/src/java/org/apache/cassandra/schema/SchemaKeyspace.java ---------------------------------------------------------------------- diff --git a/src/java/org/apache/cassandra/schema/SchemaKeyspace.java b/src/java/org/apache/cassandra/schema/SchemaKeyspace.java index 578f501..81cc2e1 100644 --- a/src/java/org/apache/cassandra/schema/SchemaKeyspace.java +++ b/src/java/org/apache/cassandra/schema/SchemaKeyspace.java @@ -25,6 +25,7 @@ import java.util.*; import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; +import com.google.common.annotations.VisibleForTesting; import com.google.common.collect.*; import com.google.common.collect.Maps; import org.slf4j.Logger; @@ -960,14 +961,24 @@ public final class SchemaKeyspace } catch (MissingColumns exc) { - if (!IGNORE_CORRUPTED_SCHEMA_TABLES) + String errorMsg = String.format("No partition columns found for table %s.%s in %s.%s. This may be due to " + + "corruption or concurrent dropping and altering of a table. If this table is supposed " + + "to be dropped, {}run the following query to cleanup: " + + "\"DELETE FROM %s.%s WHERE keyspace_name = '%s' AND table_name = '%s'; " + + "DELETE FROM %s.%s WHERE keyspace_name = '%s' AND table_name = '%s';\" " + + "If the table is not supposed to be dropped, restore %s.%s sstables from backups.", + keyspaceName, tableName, NAME, COLUMNS, + NAME, TABLES, keyspaceName, tableName, + NAME, COLUMNS, keyspaceName, tableName, + NAME, COLUMNS); + + if (IGNORE_CORRUPTED_SCHEMA_TABLES) { - logger.error("No columns found for table {}.{} in {}.{}. This may be due to " + - "corruption or concurrent dropping and altering of a table. If this table " + - "is supposed to be dropped, restart cassandra with -Dcassandra.ignore_corrupted_schema_tables=true " + - "and run the following query: \"DELETE FROM {}.{} WHERE keyspace_name = '{}' AND table_name = '{}';\"." + - "If the table is not supposed to be dropped, restore {}.{} sstables from backups.", - keyspaceName, tableName, NAME, COLUMNS, NAME, TABLES, keyspaceName, tableName, NAME, COLUMNS); + logger.error(errorMsg, "", exc); + } + else + { + logger.error(errorMsg, "restart cassandra with -Dcassandra.ignore_corrupted_schema_tables=true and "); throw exc; } } @@ -1043,6 +1054,10 @@ public final class SchemaKeyspace List<ColumnDefinition> columns = new ArrayList<>(); columnRows.forEach(row -> columns.add(createColumnFromRow(row, types))); + + if (columns.stream().noneMatch(ColumnDefinition::isPartitionKey)) + throw new MissingColumns("No partition key columns found in schema table for " + keyspace + "." + table); + return columns; } @@ -1466,7 +1481,8 @@ public final class SchemaKeyspace .collect(toList()); } - private static class MissingColumns extends RuntimeException + @VisibleForTesting + static class MissingColumns extends RuntimeException { MissingColumns(String message) { http://git-wip-us.apache.org/repos/asf/cassandra/blob/eb68c312/test/unit/org/apache/cassandra/schema/SchemaKeyspaceTest.java ---------------------------------------------------------------------- diff --git a/test/unit/org/apache/cassandra/schema/SchemaKeyspaceTest.java b/test/unit/org/apache/cassandra/schema/SchemaKeyspaceTest.java index b2e3535..f76fc4f 100644 --- a/test/unit/org/apache/cassandra/schema/SchemaKeyspaceTest.java +++ b/test/unit/org/apache/cassandra/schema/SchemaKeyspaceTest.java @@ -52,6 +52,7 @@ import org.apache.cassandra.thrift.ThriftConversion; import org.apache.cassandra.utils.ByteBufferUtil; import org.apache.cassandra.utils.FBUtilities; +import static org.apache.cassandra.cql3.QueryProcessor.executeOnceInternal; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; @@ -205,4 +206,32 @@ public class SchemaKeyspaceTest assertEquals(cfm.params, params); assertEquals(new HashSet<>(cfm.allColumns()), columns); } + + @Test(expected = SchemaKeyspace.MissingColumns.class) + public void testSchemaNoPartition() + { + String testKS = "test_schema_no_partition"; + String testTable = "invalid_table"; + SchemaLoader.createKeyspace(testKS, + KeyspaceParams.simple(1), + SchemaLoader.standardCFMD(testKS, testTable)); + // Delete partition column in the schema + String query = String.format("DELETE FROM %s.%s WHERE keyspace_name=? and table_name=? and column_name=?", SchemaKeyspace.NAME, SchemaKeyspace.COLUMNS); + executeOnceInternal(query, testKS, testTable, "key"); + SchemaKeyspace.fetchNonSystemKeyspaces(); + } + + @Test(expected = SchemaKeyspace.MissingColumns.class) + public void testSchemaNoColumn() + { + String testKS = "test_schema_no_Column"; + String testTable = "invalid_table"; + SchemaLoader.createKeyspace(testKS, + KeyspaceParams.simple(1), + SchemaLoader.standardCFMD(testKS, testTable)); + // Delete all colmns in the schema + String query = String.format("DELETE FROM %s.%s WHERE keyspace_name=? and table_name=?", SchemaKeyspace.NAME, SchemaKeyspace.COLUMNS); + executeOnceInternal(query, testKS, testTable); + SchemaKeyspace.fetchNonSystemKeyspaces(); + } } --------------------------------------------------------------------- To unsubscribe, e-mail: commits-unsubscr...@cassandra.apache.org For additional commands, e-mail: commits-h...@cassandra.apache.org