You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cassandra.apache.org by al...@apache.org on 2015/07/23 17:43:31 UTC

cassandra git commit: Fix migration of pk-only compact storage tables

Repository: cassandra
Updated Branches:
  refs/heads/trunk d9dfbddbe -> 2d55c1e84


Fix migration of pk-only compact storage tables

patch by Aleksey Yeschenko; reviewed by Sylvain Lebresne for
CASSANDRA-9874


Project: http://git-wip-us.apache.org/repos/asf/cassandra/repo
Commit: http://git-wip-us.apache.org/repos/asf/cassandra/commit/2d55c1e8
Tree: http://git-wip-us.apache.org/repos/asf/cassandra/tree/2d55c1e8
Diff: http://git-wip-us.apache.org/repos/asf/cassandra/diff/2d55c1e8

Branch: refs/heads/trunk
Commit: 2d55c1e8465015fd18cc71a1228489aaf5c6eea8
Parents: d9dfbdd
Author: Aleksey Yeschenko <al...@apache.org>
Authored: Thu Jul 23 16:06:02 2015 +0300
Committer: Aleksey Yeschenko <al...@apache.org>
Committed: Thu Jul 23 18:44:47 2015 +0300

----------------------------------------------------------------------
 CHANGES.txt                                     |   2 +-
 .../cassandra/schema/LegacySchemaMigrator.java  | 131 ++++++++++++-------
 .../schema/LegacySchemaMigratorTest.java        |  15 ++-
 3 files changed, 95 insertions(+), 53 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cassandra/blob/2d55c1e8/CHANGES.txt
----------------------------------------------------------------------
diff --git a/CHANGES.txt b/CHANGES.txt
index d405a4d..7f061c1 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -4,7 +4,7 @@
  * Change CREATE/ALTER TABLE syntax for compression (CASSANDRA-8384)
  * Cleanup crc and adler code for java 8 (CASSANDRA-9650)
  * Storage engine refactor (CASSANDRA-8099, 9743, 9746, 9759, 9781, 9808, 9825, 9848,
-   9705, 9859, 9867)
+   9705, 9859, 9867, 9874)
  * Update Guava to 18.0 (CASSANDRA-9653)
  * Bloom filter false positive ratio is not honoured (CASSANDRA-8413)
  * New option for cassandra-stress to leave a ratio of columns null (CASSANDRA-9522)

http://git-wip-us.apache.org/repos/asf/cassandra/blob/2d55c1e8/src/java/org/apache/cassandra/schema/LegacySchemaMigrator.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/schema/LegacySchemaMigrator.java b/src/java/org/apache/cassandra/schema/LegacySchemaMigrator.java
index f554ffb..7326fa9 100644
--- a/src/java/org/apache/cassandra/schema/LegacySchemaMigrator.java
+++ b/src/java/org/apache/cassandra/schema/LegacySchemaMigrator.java
@@ -296,7 +296,16 @@ public final class LegacySchemaMigrator
                                                                         needsUpgrade);
 
         if (needsUpgrade)
-            addDefinitionForUpgrade(columnDefs, ksName, cfName, isStaticCompactTable, isSuper, rawComparator, subComparator, defaultValidator);
+        {
+            addDefinitionForUpgrade(columnDefs,
+                                    ksName,
+                                    cfName,
+                                    isStaticCompactTable,
+                                    isSuper,
+                                    rawComparator,
+                                    subComparator,
+                                    defaultValidator);
+        }
 
         CFMetaData cfm = CFMetaData.create(ksName, cfName, cfId, isDense, isCompound, isSuper, isCounter, columnDefs);
 
@@ -355,7 +364,33 @@ public final class LegacySchemaMigrator
             return !hasKind(defs, ColumnDefinition.Kind.STATIC);
 
         // For dense compact tables, we need to upgrade if we don't have a compact value definition
-        return !hasKind(defs, ColumnDefinition.Kind.REGULAR);
+        return !hasRegularColumns(defs);
+    }
+
+    private static boolean hasRegularColumns(UntypedResultSet columnRows)
+    {
+        for (UntypedResultSet.Row row : columnRows)
+        {
+            /*
+             * We need to special case and ignore the empty compact column (pre-3.0, COMPACT STORAGE, primary-key only tables),
+             * since deserializeKind() will otherwise just return a REGULAR.
+             * We want the proper EmptyType regular column to be added by addDefinitionForUpgrade(), so we need
+             * checkNeedsUpgrade() to return true in this case.
+             * See CASSANDRA-9874.
+             */
+            if (isEmptyCompactValueColumn(row))
+                return false;
+
+            if (deserializeKind(row.getString("type")) == ColumnDefinition.Kind.REGULAR)
+                return true;
+        }
+
+        return false;
+    }
+
+    private static boolean isEmptyCompactValueColumn(UntypedResultSet.Row row)
+    {
+        return "compact_value".equals(row.getString("type")) && row.getString("column_name").isEmpty();
     }
 
     private static void addDefinitionForUpgrade(List<ColumnDefinition> defs,
@@ -389,10 +424,9 @@ public final class LegacySchemaMigrator
     private static boolean hasKind(UntypedResultSet defs, ColumnDefinition.Kind kind)
     {
         for (UntypedResultSet.Row row : defs)
-        {
             if (deserializeKind(row.getString("type")) == kind)
                 return true;
-        }
+
         return false;
     }
 
@@ -437,62 +471,59 @@ public final class LegacySchemaMigrator
                                                                       boolean needsUpgrade)
     {
         List<ColumnDefinition> columns = new ArrayList<>();
-        for (UntypedResultSet.Row row : rows)
-            columns.add(createColumnFromColumnRow(row, keyspace, table, rawComparator, rawSubComparator, isSuper, isCQLTable, isStaticCompactTable, needsUpgrade));
-        return columns;
-    }
-
-    private static ColumnDefinition createColumnFromColumnRow(UntypedResultSet.Row row,
-                                                              String keyspace,
-                                                              String table,
-                                                              AbstractType<?> rawComparator,
-                                                              AbstractType<?> rawSubComparator,
-                                                              boolean isSuper,
-                                                              boolean isCQLTable,
-                                                              boolean isStaticCompactTable,
-                                                              boolean needsUpgrade)
-    {
-        ColumnDefinition.Kind kind = deserializeKind(row.getString("type"));
-        if (needsUpgrade && isStaticCompactTable && kind == ColumnDefinition.Kind.REGULAR)
-            kind = ColumnDefinition.Kind.STATIC;
-
-        Integer componentIndex = null;
-        // Note that the component_index is not useful for non-primary key parts (it never really in fact since there is
-        // no particular ordering of non-PK columns, we only used to use it as a simplification but that's not needed
-        // anymore)
-        if (kind.isPrimaryKeyKind() && row.has("component_index"))
-            componentIndex = row.getInt("component_index");
-
-        // Note: we save the column name as string, but we should not assume that it is an UTF8 name, we
-        // we need to use the comparator fromString method
-        AbstractType<?> comparator = isCQLTable
-                                   ? UTF8Type.instance
-                                   : CompactTables.columnDefinitionComparator(kind, isSuper, rawComparator, rawSubComparator);
-        ColumnIdentifier name = ColumnIdentifier.getInterned(comparator.fromString(row.getString("column_name")), comparator);
-
-        AbstractType<?> validator = parseType(row.getString("validator"));
 
-        IndexType indexType = null;
-        if (row.has("index_type"))
-            indexType = IndexType.valueOf(row.getString("index_type"));
-
-        Map<String, String> indexOptions = null;
-        if (row.has("index_options"))
-            indexOptions = fromJsonMap(row.getString("index_options"));
-
-        String indexName = null;
-        if (row.has("index_name"))
-            indexName = row.getString("index_name");
+        for (UntypedResultSet.Row row : rows)
+        {
+            // Skip the empty compact value column. Make addDefinitionForUpgrade() re-add the proper REGULAR one.
+            if (isEmptyCompactValueColumn(row))
+                continue;
+
+            ColumnDefinition.Kind kind = deserializeKind(row.getString("type"));
+            if (needsUpgrade && isStaticCompactTable && kind == ColumnDefinition.Kind.REGULAR)
+                kind = ColumnDefinition.Kind.STATIC;
+
+            Integer componentIndex = null;
+            // Note that the component_index is not useful for non-primary key parts (it never really in fact since there is
+            // no particular ordering of non-PK columns, we only used to use it as a simplification but that's not needed
+            // anymore)
+            if (kind.isPrimaryKeyKind() && row.has("component_index"))
+                componentIndex = row.getInt("component_index");
+
+            // Note: we save the column name as string, but we should not assume that it is an UTF8 name, we
+            // we need to use the comparator fromString method
+            AbstractType<?> comparator = isCQLTable
+                                       ? UTF8Type.instance
+                                       : CompactTables.columnDefinitionComparator(kind, isSuper, rawComparator, rawSubComparator);
+            ColumnIdentifier name = ColumnIdentifier.getInterned(comparator.fromString(row.getString("column_name")), comparator);
+
+            AbstractType<?> validator = parseType(row.getString("validator"));
+
+            IndexType indexType = null;
+            if (row.has("index_type"))
+                indexType = IndexType.valueOf(row.getString("index_type"));
+
+            Map<String, String> indexOptions = null;
+            if (row.has("index_options"))
+                indexOptions = fromJsonMap(row.getString("index_options"));
+
+            String indexName = null;
+            if (row.has("index_name"))
+                indexName = row.getString("index_name");
+
+            columns.add(new ColumnDefinition(keyspace, table, name, validator, indexType, indexOptions, indexName, componentIndex, kind));
+        }
 
-        return new ColumnDefinition(keyspace, table, name, validator, indexType, indexOptions, indexName, componentIndex, kind);
+        return columns;
     }
 
     private static ColumnDefinition.Kind deserializeKind(String kind)
     {
         if ("clustering_key".equalsIgnoreCase(kind))
             return ColumnDefinition.Kind.CLUSTERING;
+
         if ("compact_value".equalsIgnoreCase(kind))
             return ColumnDefinition.Kind.REGULAR;
+
         return Enum.valueOf(ColumnDefinition.Kind.class, kind.toUpperCase());
     }
 

http://git-wip-us.apache.org/repos/asf/cassandra/blob/2d55c1e8/test/unit/org/apache/cassandra/schema/LegacySchemaMigratorTest.java
----------------------------------------------------------------------
diff --git a/test/unit/org/apache/cassandra/schema/LegacySchemaMigratorTest.java b/test/unit/org/apache/cassandra/schema/LegacySchemaMigratorTest.java
index eb5e5f5..82922e6 100644
--- a/test/unit/org/apache/cassandra/schema/LegacySchemaMigratorTest.java
+++ b/test/unit/org/apache/cassandra/schema/LegacySchemaMigratorTest.java
@@ -232,6 +232,13 @@ public class LegacySchemaMigratorTest
                                                                            + "PRIMARY KEY(bar, baz) ) "
                                                                            + "WITH COMPACT STORAGE", ks_cql),
 
+                                                        CFMetaData.compile("CREATE TABLE compact_pkonly ("
+                                                                           + "k int, "
+                                                                           + "c int, "
+                                                                           + "PRIMARY KEY (k, c)) "
+                                                                           + "WITH COMPACT STORAGE",
+                                                                           ks_cql),
+
                                                         CFMetaData.compile("CREATE TABLE foofoo ("
                                                                            + "bar text, "
                                                                            + "baz text, "
@@ -459,8 +466,12 @@ public class LegacySchemaMigratorTest
 
     private static void addColumnToSchemaMutation(CFMetaData table, ColumnDefinition column, long timestamp, Mutation mutation)
     {
-        RowUpdateBuilder adder = new RowUpdateBuilder(SystemKeyspace.LegacyColumns, timestamp, mutation)
-                                 .clustering(table.cfName, column.name.toString());
+        // We need to special case pk-only dense tables. See CASSANDRA-9874.
+        String name = table.isDense() && column.kind == ColumnDefinition.Kind.REGULAR && column.type instanceof EmptyType
+                    ? ""
+                    : column.name.toString();
+
+        RowUpdateBuilder adder = new RowUpdateBuilder(SystemKeyspace.LegacyColumns, timestamp, mutation).clustering(table.cfName, name);
 
         adder.add("validator", column.type.toString())
              .add("type", serializeKind(column.kind, table.isDense()))