diff --git a/CHANGES.txt b/CHANGES.txt index 2602ec4b23..c69b0e1234 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -25,6 +25,8 @@ Merged from 4.0: * Fix cassandra-stress in simplenative mode with prepared statements (CASSANDRA-18744) * Fix filtering system ks sstables for relocation on startup (CASSANDRA-18963) * Remove completed coordinator sessions (CASSANDRA-18903) +Merged from 4.1: + * Fix StackOverflowError on ALTER after many previous schema changes (CASSANDRA-19166) Merged from 3.0: * Do not set RPC_READY to false on transports shutdown in order to not fail counter updates for deployments with coordinator and storage nodes with transports turned off (CASSANDRA-18935) diff --git a/src/java/org/apache/cassandra/schema/TableMetadataRefCache.java b/src/java/org/apache/cassandra/schema/TableMetadataRefCache.java index d947d1d690..ab5f283a42 100644 --- a/src/java/org/apache/cassandra/schema/TableMetadataRefCache.java +++ b/src/java/org/apache/cassandra/schema/TableMetadataRefCache.java @@ -18,7 +18,6 @@ package org.apache.cassandra.schema; -import java.util.Collections; import java.util.Map; import com.google.common.collect.MapDifference; @@ -26,6 +25,9 @@ import com.google.common.collect.Maps; import org.apache.cassandra.utils.Pair; +import static java.util.Collections.emptyMap; +import static java.util.Collections.unmodifiableMap; + /** * Manages the cached {@link TableMetadataRef} objects which holds the references to {@link TableMetadata} objects. *

@@ -35,7 +37,7 @@ import org.apache.cassandra.utils.Pair; */ class TableMetadataRefCache { - public final static TableMetadataRefCache EMPTY = new TableMetadataRefCache(Collections.emptyMap(), Collections.emptyMap(), Collections.emptyMap()); + public final static TableMetadataRefCache EMPTY = new TableMetadataRefCache(emptyMap(), emptyMap(), emptyMap()); // UUID -> mutable metadata ref map. We have to update these in place every time a table changes. private final Map metadataRefs; @@ -46,13 +48,13 @@ class TableMetadataRefCache // (keyspace name, index name) -> mutable metadata ref map. We have to update these in place every time an index changes. private final Map, TableMetadataRef> indexMetadataRefs; - public TableMetadataRefCache(Map metadataRefs, + private TableMetadataRefCache(Map metadataRefs, Map, TableMetadataRef> metadataRefsByName, Map, TableMetadataRef> indexMetadataRefs) { - this.metadataRefs = Collections.unmodifiableMap(metadataRefs); - this.metadataRefsByName = Collections.unmodifiableMap(metadataRefsByName); - this.indexMetadataRefs = Collections.unmodifiableMap(indexMetadataRefs); + this.metadataRefs = metadataRefs; + this.metadataRefsByName = metadataRefsByName; + this.indexMetadataRefs = indexMetadataRefs; } /** @@ -107,7 +109,11 @@ class TableMetadataRefCache .map(MapDifference.ValueDifference::rightValue) .forEach(indexTable -> indexMetadataRefs.get(Pair.create(indexTable.keyspace, indexTable.indexName().get())).set(indexTable)); - return new TableMetadataRefCache(metadataRefs, metadataRefsByName, indexMetadataRefs); + // Avoid re-wrapping the map if no changes + return new TableMetadataRefCache( + hasCreatedOrDroppedTablesOrViews ? unmodifiableMap(metadataRefs) : metadataRefs, + hasCreatedOrDroppedTablesOrViews ? unmodifiableMap(metadataRefsByName) : metadataRefsByName, + hasCreatedOrDroppedIndexes ? unmodifiableMap(indexMetadataRefs) : indexMetadataRefs); } private void putRef(Map metadataRefs,