Uploaded image for project: 'Cassandra'
  1. Cassandra
  2. CASSANDRA-15926

When schema does not match sstable serialization header can fail when merging rows

    XMLWordPrintableJSON

    Details

    • Type: Improvement
    • Status: Open
    • Priority: Normal
    • Resolution: Unresolved
    • Fix Version/s: None
    • Labels:
      None
    • Change Category:
      Semantic
    • Complexity:
      Normal
    • Platform:
      All
    • Impacts:
      None

      Description

      If the table schema had timeuuid and then an alter is done to change the column to uuid, then the on-disk serialization header won’t match the table schema; this is problematic as there isn’t logic to migrate the column from the old type to the new type.

      The ALTER TABLE command does not directly allow this type of schema change (though possible before 3.0.11, see CASSANDRA-12443), but this is possible if the following is done

      INSERT INTO system_schema.columns (keyspace_name, table_name, column_name, clustering_order, column_name_bytes, kind, position, type) VALUES (‘ks', ’table', ‘col', 'none', bytes, 'regular', -1, 'uuid’);
      ALTER TABLE ks.table WITH comment = 'something’; — this will trigger the schema to migrate across the cluster
      

      The below is a test to show this

      package org.apache.cassandra.distributed.test;
      
      import java.util.UUID;
      
      import org.junit.Test;
      
      import org.apache.cassandra.distributed.Cluster;
      import org.apache.cassandra.distributed.impl.IInvokableInstance;
      import org.apache.cassandra.utils.UUIDGen;
      
      public class AlterWithOnDiskMismatch extends DistributedTestBase
      {
          @Test
          public void alterTypeMixedSSTablesNoConflict() throws Throwable
          {
              try (Cluster cluster = init(Cluster.create(1)))
              {
                  IInvokableInstance node = cluster.get(1);
      
                  cluster.schemaChange("CREATE TABLE " + KEYSPACE + ".mismatch (key text primary key, value timeuuid)");
      
                  // write valid timeuuid then flush
                  node.executeInternal("INSERT INTO " + KEYSPACE + ".mismatch (key, value) VALUES (?, ?)", "k1", UUIDGen.getTimeUUID());
                  node.flush(KEYSPACE);
      
                  // alter schema
                  Object[] columns = node.executeInternal("SELECT keyspace_name, table_name, column_name, clustering_order, column_name_bytes, kind, position, type " +
                                       "FROM system_schema.columns WHERE keyspace_name=? AND table_name=? AND column_name=?", KEYSPACE, "mismatch", "value")[0];
      
                  columns[columns.length - 1] = "uuid";
                  node.executeInternal("INSERT INTO system_schema.columns (keyspace_name, table_name, column_name, clustering_order, column_name_bytes, kind, position, type) VALUES (?, ?, ?, ?, ?, ?, ?, ?)", columns);
                  cluster.schemaChange("ALTER TABLE " + KEYSPACE + ".mismatch WITH comment='upgrade'");
      
                  node.executeInternal("INSERT INTO " + KEYSPACE + ".mismatch (key, value) VALUES (?, ?)", "k2", UUID.randomUUID());
                  node.flush(KEYSPACE);
      
                  node.forceCompact(KEYSPACE, "mismatch");
              }
          }
      
          @Test
          public void alterTypeMixedSSTablesConflict() throws Throwable
          {
              try (Cluster cluster = init(Cluster.create(1)))
              {
                  IInvokableInstance node = cluster.get(1);
      
                  cluster.schemaChange("CREATE TABLE " + KEYSPACE + ".mismatch (key text primary key, value timeuuid)");
      
                  // write valid timeuuid then flush
                  node.executeInternal("INSERT INTO " + KEYSPACE + ".mismatch (key, value) VALUES (?, ?)", "k1", UUIDGen.getTimeUUID());
                  node.flush(KEYSPACE);
      
                  // alter schema
                  Object[] columns = node.executeInternal("SELECT keyspace_name, table_name, column_name, clustering_order, column_name_bytes, kind, position, type " +
                                                          "FROM system_schema.columns WHERE keyspace_name=? AND table_name=? AND column_name=?", KEYSPACE, "mismatch", "value")[0];
      
                  columns[columns.length - 1] = "uuid";
                  node.executeInternal("INSERT INTO system_schema.columns (keyspace_name, table_name, column_name, clustering_order, column_name_bytes, kind, position, type) VALUES (?, ?, ?, ?, ?, ?, ?, ?)", columns);
                  cluster.schemaChange("ALTER TABLE " + KEYSPACE + ".mismatch WITH comment='upgrade'");
      
                  node.executeInternal("INSERT INTO " + KEYSPACE + ".mismatch (key, value) VALUES (?, ?)", "k1", UUID.randomUUID());
                  node.flush(KEYSPACE);
      
                  node.forceCompact(KEYSPACE, "mismatch");
              }
          }
      }
      

      The following is the exception

      java.lang.IllegalArgumentException: Trying to compare 2 different types: org.apache.cassandra.db.marshal.TimeUUIDType and org.apache.cassandra.db.marshal.UUIDType
      	at org.apache.cassandra.db.rows.AbstractTypeVersionComparator.compare(AbstractTypeVersionComparator.java:42)
      	at org.apache.cassandra.db.rows.AbstractTypeVersionComparator.compare(AbstractTypeVersionComparator.java:30)
      	at org.apache.cassandra.db.rows.Row$Merger$ColumnDataReducer.useColumnDefinition(Row.java:650)
      	at org.apache.cassandra.db.rows.Row$Merger$ColumnDataReducer.reduce(Row.java:634)
      	at org.apache.cassandra.db.rows.Row$Merger$ColumnDataReducer.reduce(Row.java:605)
      	at org.apache.cassandra.utils.MergeIterator$ManyToOne.consume(MergeIterator.java:216)
      

        Attachments

          Activity

            People

            • Assignee:
              Unassigned
              Reporter:
              dcapwell David Capwell
            • Votes:
              0 Vote for this issue
              Watchers:
              2 Start watching this issue

              Dates

              • Created:
                Updated: