Repository: cassandra Updated Branches: refs/heads/trunk c6778c5af -> d62b2cf7c
Freeze implicitly frozen types in 2.x -> 3.x schema migration Patch by Tyler Hobbs; reviewed by Benjamin Lerer for CASSANDRA-11609 Project: http://git-wip-us.apache.org/repos/asf/cassandra/repo Commit: http://git-wip-us.apache.org/repos/asf/cassandra/commit/d62b2cf7 Tree: http://git-wip-us.apache.org/repos/asf/cassandra/tree/d62b2cf7 Diff: http://git-wip-us.apache.org/repos/asf/cassandra/diff/d62b2cf7 Branch: refs/heads/trunk Commit: d62b2cf7c77b01723c4d312bcc249c91a73b4e45 Parents: c6778c5 Author: Tyler Hobbs <[email protected]> Authored: Fri Apr 29 15:51:34 2016 -0500 Committer: Tyler Hobbs <[email protected]> Committed: Fri Apr 29 15:51:34 2016 -0500 ---------------------------------------------------------------------- .../org/apache/cassandra/db/marshal/AbstractType.java | 13 +++++++++++++ .../org/apache/cassandra/db/marshal/ListType.java | 9 +++++++++ src/java/org/apache/cassandra/db/marshal/MapType.java | 14 ++++++++++++++ src/java/org/apache/cassandra/db/marshal/SetType.java | 9 +++++++++ .../org/apache/cassandra/db/marshal/UserType.java | 12 ++++++++++++ .../apache/cassandra/schema/LegacySchemaMigrator.java | 5 +++++ 6 files changed, 62 insertions(+) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/cassandra/blob/d62b2cf7/src/java/org/apache/cassandra/db/marshal/AbstractType.java ---------------------------------------------------------------------- diff --git a/src/java/org/apache/cassandra/db/marshal/AbstractType.java b/src/java/org/apache/cassandra/db/marshal/AbstractType.java index 1b94a74..7a67433 100644 --- a/src/java/org/apache/cassandra/db/marshal/AbstractType.java +++ b/src/java/org/apache/cassandra/db/marshal/AbstractType.java @@ -333,6 +333,19 @@ public abstract class AbstractType<T> implements Comparator<ByteBuffer> } /** + * Returns an AbstractType instance that is equivalent to this one, but with all nested UDTs explicitly frozen and + * all collections in UDTs explicitly frozen. + * + * This is only necessary for 2.x -> 3.x schema migrations, and can be removed in Cassandra 4.0. + * + * See CASSANDRA-11609 + */ + public AbstractType<?> freezeNestedUDTs() + { + return this; + } + + /** * Returns {@code true} for types where empty should be handled like {@code null} like {@link Int32Type}. */ public boolean isEmptyValueMeaningless() http://git-wip-us.apache.org/repos/asf/cassandra/blob/d62b2cf7/src/java/org/apache/cassandra/db/marshal/ListType.java ---------------------------------------------------------------------- diff --git a/src/java/org/apache/cassandra/db/marshal/ListType.java b/src/java/org/apache/cassandra/db/marshal/ListType.java index 4480dcb..b3fc4f5 100644 --- a/src/java/org/apache/cassandra/db/marshal/ListType.java +++ b/src/java/org/apache/cassandra/db/marshal/ListType.java @@ -110,6 +110,15 @@ public class ListType<T> extends CollectionType<List<T>> } @Override + public AbstractType<?> freezeNestedUDTs() + { + if (elements.isUDT() && elements.isMultiCell()) + return getInstance(elements.freeze(), isMultiCell); + else + return getInstance(elements.freezeNestedUDTs(), isMultiCell); + } + + @Override public boolean isMultiCell() { return isMultiCell; http://git-wip-us.apache.org/repos/asf/cassandra/blob/d62b2cf7/src/java/org/apache/cassandra/db/marshal/MapType.java ---------------------------------------------------------------------- diff --git a/src/java/org/apache/cassandra/db/marshal/MapType.java b/src/java/org/apache/cassandra/db/marshal/MapType.java index 425ffc2..3c5af99 100644 --- a/src/java/org/apache/cassandra/db/marshal/MapType.java +++ b/src/java/org/apache/cassandra/db/marshal/MapType.java @@ -117,6 +117,20 @@ public class MapType<K, V> extends CollectionType<Map<K, V>> } @Override + public AbstractType<?> freezeNestedUDTs() + { + AbstractType<?> keyType = (keys.isUDT() && keys.isMultiCell()) + ? keys.freeze() + : keys.freezeNestedUDTs(); + + AbstractType<?> valueType = (values.isUDT() && values.isMultiCell()) + ? values.freeze() + : values.freezeNestedUDTs(); + + return getInstance(keyType, valueType, isMultiCell); + } + + @Override public boolean isCompatibleWithFrozen(CollectionType<?> previous) { assert !isMultiCell; http://git-wip-us.apache.org/repos/asf/cassandra/blob/d62b2cf7/src/java/org/apache/cassandra/db/marshal/SetType.java ---------------------------------------------------------------------- diff --git a/src/java/org/apache/cassandra/db/marshal/SetType.java b/src/java/org/apache/cassandra/db/marshal/SetType.java index 22577b3..46c0741 100644 --- a/src/java/org/apache/cassandra/db/marshal/SetType.java +++ b/src/java/org/apache/cassandra/db/marshal/SetType.java @@ -105,6 +105,15 @@ public class SetType<T> extends CollectionType<Set<T>> } @Override + public AbstractType<?> freezeNestedUDTs() + { + if (elements.isUDT() && elements.isMultiCell()) + return getInstance(elements.freeze(), isMultiCell); + else + return getInstance(elements.freezeNestedUDTs(), isMultiCell); + } + + @Override public boolean isCompatibleWithFrozen(CollectionType<?> previous) { assert !isMultiCell; http://git-wip-us.apache.org/repos/asf/cassandra/blob/d62b2cf7/src/java/org/apache/cassandra/db/marshal/UserType.java ---------------------------------------------------------------------- diff --git a/src/java/org/apache/cassandra/db/marshal/UserType.java b/src/java/org/apache/cassandra/db/marshal/UserType.java index 72ed895..433cb87 100644 --- a/src/java/org/apache/cassandra/db/marshal/UserType.java +++ b/src/java/org/apache/cassandra/db/marshal/UserType.java @@ -21,6 +21,7 @@ import java.nio.ByteBuffer; import java.nio.charset.CharacterCodingException; import java.nio.charset.StandardCharsets; import java.util.*; +import java.util.stream.Collectors; import com.google.common.base.Objects; @@ -303,6 +304,17 @@ public class UserType extends TupleType } @Override + public AbstractType<?> freezeNestedUDTs() + { + // the behavior here doesn't exactly match the method name: we want to freeze everything inside of UDTs + List<AbstractType<?>> newTypes = fieldTypes().stream() + .map(subtype -> (subtype.isFreezable() && subtype.isMultiCell() ? subtype.freeze() : subtype)) + .collect(Collectors.toList()); + + return new UserType(keyspace, name, fieldNames, newTypes, isMultiCell); + } + + @Override public int hashCode() { return Objects.hashCode(keyspace, name, fieldNames, types, isMultiCell); http://git-wip-us.apache.org/repos/asf/cassandra/blob/d62b2cf7/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 9d277d6..ebe8006 100644 --- a/src/java/org/apache/cassandra/schema/LegacySchemaMigrator.java +++ b/src/java/org/apache/cassandra/schema/LegacySchemaMigrator.java @@ -683,6 +683,11 @@ public final class LegacySchemaMigrator AbstractType<?> validator = parseType(row.getString("validator")); + // In the 2.x schema we didn't store UDT's with a FrozenType wrapper because they were implicitly frozen. After + // CASSANDRA-7423 (non-frozen UDTs), this is no longer true, so we need to freeze nested UDTs to properly + // migrate the schema. See CASSANDRA-11609. + validator = validator.freezeNestedUDTs(); + return new ColumnDefinition(keyspace, table, name, validator, componentIndex, kind); }
