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
This commit is contained in:
Jay Zhuang 2018-04-04 13:49:08 -07:00 committed by Jay Zhuang
parent 733f6b0cf8
commit eb68c31262
3 changed files with 54 additions and 8 deletions

View File

@ -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)

View File

@ -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)
{

View File

@ -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();
}
}