diff --git a/src/java/org/apache/cassandra/config/CassandraRelevantProperties.java b/src/java/org/apache/cassandra/config/CassandraRelevantProperties.java index 3e67502f8f25..fec54f8ffdf6 100644 --- a/src/java/org/apache/cassandra/config/CassandraRelevantProperties.java +++ b/src/java/org/apache/cassandra/config/CassandraRelevantProperties.java @@ -18,7 +18,10 @@ package org.apache.cassandra.config; +import java.util.Arrays; +import java.util.List; import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; import org.apache.cassandra.exceptions.ConfigurationException; import org.apache.cassandra.metrics.TableMetrics; @@ -520,7 +523,13 @@ public enum CassandraRelevantProperties * This is to remain compatible with older workflows that first change the replication before adding the nodes. * Otherwise, it will validate that the names match existing DCs before allowing replication change. */ - DATACENTER_SKIP_NAME_VALIDATION("cassandra.dc_skip_name_validation", "false"); + DATACENTER_SKIP_NAME_VALIDATION("cassandra.dc_skip_name_validation", "false"), + + /** + * This is a list of table attributes to ignore. This is useful for handling compatibilty while + * upgrading to a newer version of Cassandra. + */ + TABLE_ATTRIBUTES_IGNORE_KEYS("cassandra.table_attributes_ignore_keys", ""); CassandraRelevantProperties(String key, String defaultVal) { @@ -676,6 +685,16 @@ public long getLong(int overrideDefaultValue) return LONG_CONVERTER.convert(value); } + /** + * Gets the value of a system property as a list of lists, delimited by commas. + * @return system property value if it exists, defaultValue otherwise. + */ + public List getListOfStrings() + { + String value = System.getProperty(key); + return LIST_OF_STRINGS_CONVERTER.convert(value == null ? defaultVal : value); + } + /** * Sets the value into system properties. * @param value to set @@ -753,6 +772,16 @@ private interface PropertyConverter } }; + private static final PropertyConverter> LIST_OF_STRINGS_CONVERTER = value -> + { + return Arrays.asList(value.split(",")) + .stream() + .filter(s -> !s.isBlank()) + .collect(Collectors.toList()); + }; + + + private static final PropertyConverter DOUBLE_CONVERTER = value -> { try diff --git a/src/java/org/apache/cassandra/cql3/statements/PropertyDefinitions.java b/src/java/org/apache/cassandra/cql3/statements/PropertyDefinitions.java index 2d832cbc771b..ce686bb93a6b 100644 --- a/src/java/org/apache/cassandra/cql3/statements/PropertyDefinitions.java +++ b/src/java/org/apache/cassandra/cql3/statements/PropertyDefinitions.java @@ -46,7 +46,7 @@ public void addProperty(String name, Map value) throws SyntaxExc throw new SyntaxException(String.format("Multiple definition for property '%s'", name)); } - public void validate(Set keywords, Set obsolete) throws SyntaxException + public void validate(Set keywords, Set obsolete, Set keywordsFromNewVersions) throws SyntaxException { for (String name : properties.keySet()) { @@ -55,6 +55,8 @@ public void validate(Set keywords, Set obsolete) throws SyntaxEx if (obsolete.contains(name)) logger.warn("Ignoring obsolete property {}", name); + else if (keywordsFromNewVersions.contains(name)) + logger.warn("Ignoring property {} that is not supported in this version", name); else throw new SyntaxException(String.format("Unknown property '%s'", name)); } diff --git a/src/java/org/apache/cassandra/cql3/statements/schema/TableAttributes.java b/src/java/org/apache/cassandra/cql3/statements/schema/TableAttributes.java index 112d0cfd7604..f04ddf41a1b9 100644 --- a/src/java/org/apache/cassandra/cql3/statements/schema/TableAttributes.java +++ b/src/java/org/apache/cassandra/cql3/statements/schema/TableAttributes.java @@ -26,6 +26,9 @@ import com.google.common.collect.ImmutableSet; import com.google.common.collect.Sets; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import org.apache.cassandra.cql3.CQL3Type; import org.apache.cassandra.cql3.ColumnIdentifier; import org.apache.cassandra.cql3.functions.types.utils.Bytes; @@ -45,9 +48,12 @@ import org.apache.cassandra.service.reads.repair.ReadRepairStrategy; import static java.lang.String.format; +import static org.apache.cassandra.config.CassandraRelevantProperties.TABLE_ATTRIBUTES_IGNORE_KEYS; public final class TableAttributes extends PropertyDefinitions { + private static final Logger logger = LoggerFactory.getLogger(TableAttributes.class); + public static final String ID = "id"; public static final Set validKeywords; private static final Set obsoleteKeywords = ImmutableSet.of( @@ -56,6 +62,11 @@ public final class TableAttributes extends PropertyDefinitions "dse_edge_label_property" ); + private static final Set keywordsFromNewVersions = ImmutableSet.builder() + .add("allow_auto_snapshot") + .addAll(TABLE_ATTRIBUTES_IGNORE_KEYS.getListOfStrings()) + .build(); + private static final Set UNSUPPORTED_DSE_COMPACTION_STRATEGIES = ImmutableSet.of( "org.apache.cassandra.db.compaction.TieredCompactionStrategy", "TieredCompactionStrategy", @@ -70,13 +81,14 @@ public final class TableAttributes extends PropertyDefinitions validBuilder.add(option.toString()); validBuilder.add(ID); validKeywords = validBuilder.build(); + logger.debug("Ignored keyworks for compatibility with newer versions: {}", keywordsFromNewVersions); } private final Map droppedColumnRecords = new HashMap<>(); public void validate() { - validate(validKeywords, obsoleteKeywords); + validate(validKeywords, obsoleteKeywords, keywordsFromNewVersions); build(TableParams.builder()).validate(); } @@ -137,7 +149,7 @@ boolean hasUnsupportedDseCompaction() public static Set allKeywords() { - return Sets.union(validKeywords, obsoleteKeywords); + return Sets.union(Sets.union(validKeywords, obsoleteKeywords), keywordsFromNewVersions); } private TableParams build(TableParams.Builder builder)