Merge branch 'cassandra-4.1' into trunk
diff --git a/.build/build-rat.xml b/.build/build-rat.xml
index 5632664..6a3d72e 100644
--- a/.build/build-rat.xml
+++ b/.build/build-rat.xml
@@ -58,6 +58,8 @@
<exclude NAME="**/doc/antora.yml"/>
<exclude name="**/test/conf/cassandra.yaml"/>
<exclude name="**/test/conf/cassandra-old.yaml"/>
+ <exclude name="**/test/conf/cassandra-converters-special-cases-old-names.yaml"/>
+ <exclude name="**/test/conf/cassandra-converters-special-cases.yaml"/>
<exclude name="**/test/conf/cassandra_encryption.yaml"/>
<exclude name="**/test/conf/cdc.yaml"/>
<exclude name="**/test/conf/commitlog_compression_LZ4.yaml"/>
diff --git a/CHANGES.txt b/CHANGES.txt
index 47d08b3..7c9137f 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -20,6 +20,8 @@
* Add guardrail for ALTER TABLE ADD / DROP / REMOVE column operations (CASSANDRA-17495)
* Rename DisableFlag class to EnableFlag on guardrails (CASSANDRA-17544)
Merged from 4.1:
+ * Fix sstable_preemptive_open_interval disabled value. sstable_preemptive_open_interval = null backward compatible with
+ sstable_preemptive_open_interval_in_mb = -1 (CASSANDRA-17737)
* Remove usages of Path#toFile() in the snapshot apparatus (CASSANDRA-17769)
* Fix Settings Virtual Table to update paxos_variant after startup and rename enable_uuid_sstable_identifiers to
uuid_sstable_identifiers_enabled as per our config naming conventions (CASSANDRA-17738)
diff --git a/NEWS.txt b/NEWS.txt
index 1589219..fa12563 100644
--- a/NEWS.txt
+++ b/NEWS.txt
@@ -198,9 +198,13 @@
Upgrading
---------
+ - `sstable_preemptive_open_interval_in_mb` being negative for disabled is equivalent to `sstable_preemptive_open_interval`
+ being null again. In the JMX MBean `org.apache.cassandra.db:type=StorageService`, the setter method
+ `setSSTablePreemptiveOpenIntervalInMB`still takes `intervalInMB` negative numbers for disabled.
- `enable_uuid_sstable_identifiers` parameter from 4.1 alpha1 was renamed to `uuid_sstable_identifiers_enabled`.
- `index_summary_resize_interval_in_minutes = -1` is equivalent to index_summary_resize_interval being set to `null` or
- disabled. JMX MBean `IndexSummaryManager`, `setResizeIntervalInMinutes` method still takes `resizeIntervalInMinutes = -1` for disabled.
+ disabled. In the JMX MBean `org.apache.cassandra.db:type=IndexSummaryManager`, the setter method `setResizeIntervalInMinutes` still takes
+ `resizeIntervalInMinutes = -1` for disabled.
- min_tracked_partition_size_bytes parameter from 4.1 alpha1 was renamed to min_tracked_partition_size.
- Parameters of type data storage, duration and data rate cannot be set to Long.MAX_VALUE (former parameters of long type)
and Integer.MAX_VALUE (former parameters of int type). Those numbers are used during conversion between units to prevent
diff --git a/build.xml b/build.xml
index 7595c1b..ca346c9 100644
--- a/build.xml
+++ b/build.xml
@@ -627,7 +627,7 @@
<exclusion groupId="net.java.dev.jna" artifactId="jna" />
<exclusion groupId="net.java.dev.jna" artifactId="jna-platform" />
</dependency>
- <dependency groupId="com.google.code.findbugs" artifactId="jsr305" version="2.0.2" scope="provided"/>
+ <dependency groupId="com.google.code.findbugs" artifactId="jsr305" version="2.0.2"/>
<dependency groupId="com.clearspring.analytics" artifactId="stream" version="2.5.2">
<exclusion groupId="it.unimi.dsi" artifactId="fastutil" />
</dependency>
diff --git a/conf/cassandra.yaml b/conf/cassandra.yaml
index 9d0ce11..dd388f2 100644
--- a/conf/cassandra.yaml
+++ b/conf/cassandra.yaml
@@ -1004,6 +1004,8 @@
# are completely written, and used in place of the prior sstables for
# any range that has been written. This helps to smoothly transfer reads
# between the sstables, reducing page cache churn and keeping hot rows hot
+# Set sstable_preemptive_open_interval to null for disabled which is equivalent to
+# sstable_preemptive_open_interval_in_mb being negative
# Min unit: MiB
sstable_preemptive_open_interval: 50MiB
diff --git a/src/java/org/apache/cassandra/config/Config.java b/src/java/org/apache/cassandra/config/Config.java
index 0dc9cbc..834a3f6 100644
--- a/src/java/org/apache/cassandra/config/Config.java
+++ b/src/java/org/apache/cassandra/config/Config.java
@@ -28,6 +28,8 @@
import java.util.TreeMap;
import java.util.function.Supplier;
+import javax.annotation.Nullable;
+
import com.google.common.base.Joiner;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Sets;
@@ -426,7 +428,8 @@
@Replaces(oldName = "trickle_fsync_interval_in_kb", converter = Converters.KIBIBYTES_DATASTORAGE, deprecated = true)
public DataStorageSpec.IntKibibytesBound trickle_fsync_interval = new DataStorageSpec.IntKibibytesBound("10240KiB");
- @Replaces(oldName = "sstable_preemptive_open_interval_in_mb", converter = Converters.MEBIBYTES_DATA_STORAGE_INT, deprecated = true)
+ @Nullable
+ @Replaces(oldName = "sstable_preemptive_open_interval_in_mb", converter = Converters.NEGATIVE_MEBIBYTES_DATA_STORAGE_INT, deprecated = true)
public volatile DataStorageSpec.IntMebibytesBound sstable_preemptive_open_interval = new DataStorageSpec.IntMebibytesBound("50MiB");
public volatile boolean key_cache_migrate_during_compaction = true;
@@ -504,6 +507,7 @@
@Replaces(oldName = "index_summary_capacity_in_mb", converter = Converters.MEBIBYTES_DATA_STORAGE_LONG, deprecated = true)
public volatile DataStorageSpec.LongMebibytesBound index_summary_capacity;
+ @Nullable
@Replaces(oldName = "index_summary_resize_interval_in_minutes", converter = Converters.MINUTES_CUSTOM_DURATION, deprecated = true)
public volatile DurationSpec.IntMinutesBound index_summary_resize_interval = new DurationSpec.IntMinutesBound("60m");
diff --git a/src/java/org/apache/cassandra/config/Converters.java b/src/java/org/apache/cassandra/config/Converters.java
index d825cb9..d622397 100644
--- a/src/java/org/apache/cassandra/config/Converters.java
+++ b/src/java/org/apache/cassandra/config/Converters.java
@@ -40,10 +40,10 @@
IDENTITY(null, null, o -> o, o -> o),
MILLIS_DURATION_LONG(Long.class, DurationSpec.LongMillisecondsBound.class,
DurationSpec.LongMillisecondsBound::new,
- o -> o.toMilliseconds()),
+ o -> o == null ? null : o.toMilliseconds()),
MILLIS_DURATION_INT(Integer.class, DurationSpec.IntMillisecondsBound.class,
DurationSpec.IntMillisecondsBound::new,
- DurationSpec.IntMillisecondsBound::toMilliseconds),
+ o -> o == null ? null : o.toMilliseconds()),
MILLIS_DURATION_DOUBLE(Double.class, DurationSpec.IntMillisecondsBound.class,
o -> Double.isNaN(o) ? new DurationSpec.IntMillisecondsBound(0) :
new DurationSpec.IntMillisecondsBound(o, TimeUnit.MILLISECONDS),
@@ -57,10 +57,10 @@
o -> o == null ? -1 : o.toMilliseconds()),
SECONDS_DURATION(Integer.class, DurationSpec.IntSecondsBound.class,
DurationSpec.IntSecondsBound::new,
- DurationSpec.IntSecondsBound::toSeconds),
+ o -> o == null ? null : o.toSeconds()),
NEGATIVE_SECONDS_DURATION(Integer.class, DurationSpec.IntSecondsBound.class,
o -> o < 0 ? new DurationSpec.IntSecondsBound(0) : new DurationSpec.IntSecondsBound(o),
- DurationSpec.IntSecondsBound::toSeconds),
+ o -> o == null ? null : o.toSeconds()),
/**
* This converter is used to support backward compatibility for Duration parameters where we added the opportunity
* for the users to add a unit in the parameters' values but we didn't change the names. (key_cache_save_period,
@@ -69,26 +69,29 @@
*/
SECONDS_CUSTOM_DURATION(String.class, DurationSpec.IntSecondsBound.class,
DurationSpec.IntSecondsBound::inSecondsString,
- o -> Long.toString(o.toSeconds())),
+ o -> o == null ? null : Long.toString(o.toSeconds())),
/**
* This converter is used to support backward compatibility for parameters where in the past -1 was used as a value
* Example: index_summary_resize_interval_in_minutes = -1 and index_summary_resize_interval = null are equal.
*/
MINUTES_CUSTOM_DURATION(Integer.class, DurationSpec.IntMinutesBound.class,
- o -> o == -1 ? null : new DurationSpec.IntMinutesBound(o),
- o -> o == null ? -1 : o.toMinutes()),
+ o -> o == -1 ? null : new DurationSpec.IntMinutesBound(o),
+ o -> o == null ? -1 : o.toMinutes()),
MEBIBYTES_DATA_STORAGE_LONG(Long.class, DataStorageSpec.LongMebibytesBound.class,
DataStorageSpec.LongMebibytesBound::new,
- DataStorageSpec.LongMebibytesBound::toMebibytes),
+ o -> o == null ? null : o.toMebibytes()),
MEBIBYTES_DATA_STORAGE_INT(Integer.class, DataStorageSpec.IntMebibytesBound.class,
DataStorageSpec.IntMebibytesBound::new,
- DataStorageSpec.IntMebibytesBound::toMebibytes),
+ o -> o == null ? null : o.toMebibytes()),
+ NEGATIVE_MEBIBYTES_DATA_STORAGE_INT(Integer.class, DataStorageSpec.IntMebibytesBound.class,
+ o -> o < 0 ? null : new DataStorageSpec.IntMebibytesBound(o),
+ o -> o == null ? -1 : o.toMebibytes()),
KIBIBYTES_DATASTORAGE(Integer.class, DataStorageSpec.IntKibibytesBound.class,
DataStorageSpec.IntKibibytesBound::new,
- DataStorageSpec.IntKibibytesBound::toKibibytes),
+ o -> o == null ? null : o.toKibibytes()),
BYTES_DATASTORAGE(Integer.class, DataStorageSpec.IntBytesBound.class,
DataStorageSpec.IntBytesBound::new,
- DataStorageSpec.IntBytesBound::toBytes),
+ o -> o == null ? null : o.toBytes()),
/**
* This converter is used to support backward compatibility for parameters where in the past negative number was used as a value
* Example: native_transport_max_concurrent_requests_in_bytes_per_ip = -1 and native_transport_max_request_data_in_flight_per_ip = null
@@ -96,17 +99,17 @@
*/
BYTES_CUSTOM_DATASTORAGE(Long.class, DataStorageSpec.LongBytesBound.class,
o -> o == -1 ? null : new DataStorageSpec.LongBytesBound(o),
- DataStorageSpec.LongBytesBound::toBytes),
+ o -> o == null ? null : o.toBytes()),
MEBIBYTES_PER_SECOND_DATA_RATE(Integer.class, DataRateSpec.IntMebibytesPerSecondBound.class,
DataRateSpec.IntMebibytesPerSecondBound::new,
- DataRateSpec.IntMebibytesPerSecondBound::toMebibytesPerSecondAsInt),
+ o -> o == null ? null : o.toMebibytesPerSecondAsInt()),
/**
* This converter is a custom one to support backward compatibility for stream_throughput_outbound and
* inter_dc_stream_throughput_outbound which were provided in megatibs per second prior CASSANDRA-15234.
*/
MEGABITS_TO_MEBIBYTES_PER_SECOND_DATA_RATE(Integer.class, DataRateSpec.IntMebibytesPerSecondBound.class,
i -> DataRateSpec.IntMebibytesPerSecondBound.megabitsPerSecondInMebibytesPerSecond(i),
- DataRateSpec.IntMebibytesPerSecondBound::toMegabitsPerSecondAsInt);
+ o -> o == null ? null : o.toMegabitsPerSecondAsInt());
private final Class<?> oldType;
private final Class<?> newType;
private final Function<Object, Object> convert;
@@ -164,7 +167,6 @@
*/
public Object unconvert(Object value)
{
- if (value == null) return null;
return reverseConvert.apply(value);
}
}
diff --git a/src/java/org/apache/cassandra/config/DatabaseDescriptor.java b/src/java/org/apache/cassandra/config/DatabaseDescriptor.java
index 809eb8f..e025ecc 100644
--- a/src/java/org/apache/cassandra/config/DatabaseDescriptor.java
+++ b/src/java/org/apache/cassandra/config/DatabaseDescriptor.java
@@ -3081,14 +3081,21 @@
conf.key_cache_migrate_during_compaction = migrateCacheEntry;
}
+ /** This method can return negative number for disabled */
public static int getSSTablePreemptiveOpenIntervalInMiB()
{
+ if (conf.sstable_preemptive_open_interval == null)
+ return -1;
return conf.sstable_preemptive_open_interval.toMebibytes();
}
+ /** Negative number for disabled */
public static void setSSTablePreemptiveOpenIntervalInMiB(int mib)
{
- conf.sstable_preemptive_open_interval = new DataStorageSpec.IntMebibytesBound(mib);
+ if (mib < 0)
+ conf.sstable_preemptive_open_interval = null;
+ else
+ conf.sstable_preemptive_open_interval = new DataStorageSpec.IntMebibytesBound(mib);
}
public static boolean getTrickleFsync()
diff --git a/src/java/org/apache/cassandra/config/YamlConfigurationLoader.java b/src/java/org/apache/cassandra/config/YamlConfigurationLoader.java
index 09f3f1e..1dcd595 100644
--- a/src/java/org/apache/cassandra/config/YamlConfigurationLoader.java
+++ b/src/java/org/apache/cassandra/config/YamlConfigurationLoader.java
@@ -30,6 +30,8 @@
import java.util.Objects;
import java.util.Set;
+import javax.annotation.Nullable;
+
import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
@@ -363,10 +365,13 @@
return new ForwardingProperty(result.getName(), result)
{
+ boolean allowsNull = result.getAnnotation(Nullable.class) != null;
+
@Override
public void set(Object object, Object value) throws Exception
{
- if (value == null && get(object) != null)
+ // TODO: CASSANDRA-17785, add @Nullable to all nullable Config properties and remove value == null
+ if (value == null && get(object) != null && !allowsNull)
nullProperties.add(getName());
result.set(object, value);
diff --git a/src/java/org/apache/cassandra/service/StorageService.java b/src/java/org/apache/cassandra/service/StorageService.java
index 102f5ec..6bbc516 100644
--- a/src/java/org/apache/cassandra/service/StorageService.java
+++ b/src/java/org/apache/cassandra/service/StorageService.java
@@ -6020,11 +6020,13 @@
return DatabaseDescriptor.getPartitionerName();
}
+ /** Negative number for disabled */
public void setSSTablePreemptiveOpenIntervalInMB(int intervalInMB)
{
DatabaseDescriptor.setSSTablePreemptiveOpenIntervalInMiB(intervalInMB);
}
+ /** This method can return negative number for disabled */
public int getSSTablePreemptiveOpenIntervalInMB()
{
return DatabaseDescriptor.getSSTablePreemptiveOpenIntervalInMiB();
diff --git a/test/conf/cassandra-converters-special-cases-old-names.yaml b/test/conf/cassandra-converters-special-cases-old-names.yaml
new file mode 100644
index 0000000..144844b
--- /dev/null
+++ b/test/conf/cassandra-converters-special-cases-old-names.yaml
@@ -0,0 +1,7 @@
+#
+# This test config is used to test the Converters added for configuration backward compatibility in 4.1 post
+# CASSANDRA-15234. It tests setting old Config names (CASSANDRA-17737)
+#
+sstable_preemptive_open_interval_in_mb: -1
+index_summary_resize_interval_in_minutes: -1
+
diff --git a/test/conf/cassandra-converters-special-cases.yaml b/test/conf/cassandra-converters-special-cases.yaml
new file mode 100644
index 0000000..227c962
--- /dev/null
+++ b/test/conf/cassandra-converters-special-cases.yaml
@@ -0,0 +1,7 @@
+#
+# This test config is used to test the Converters added for configuration backward compatibility in 4.1 post
+# CASSANDRA-15234. It tests setting new Config names (CASSANDRA-17737)
+#
+sstable_preemptive_open_interval:
+index_summary_resize_interval:
+
diff --git a/test/unit/org/apache/cassandra/config/YamlConfigurationLoaderTest.java b/test/unit/org/apache/cassandra/config/YamlConfigurationLoaderTest.java
index f7bfd53..1e1dd96 100644
--- a/test/unit/org/apache/cassandra/config/YamlConfigurationLoaderTest.java
+++ b/test/unit/org/apache/cassandra/config/YamlConfigurationLoaderTest.java
@@ -24,6 +24,7 @@
import java.net.URL;
import java.util.Arrays;
import java.util.Collections;
+import java.util.HashMap;
import java.util.Map;
import java.util.function.Predicate;
@@ -111,6 +112,39 @@
}
@Test
+ public void readConvertersSpecialCasesFromConfig()
+ {
+ Config c = load("test/conf/cassandra-converters-special-cases.yaml");
+ assertThat(c.sstable_preemptive_open_interval).isNull();
+ assertThat(c.index_summary_resize_interval).isNull();
+
+ c = load("test/conf/cassandra-converters-special-cases-old-names.yaml");
+ assertThat(c.sstable_preemptive_open_interval).isNull();
+ assertThat(c.index_summary_resize_interval).isNull();
+ }
+
+ @Test
+ public void readConvertersSpecialCasesFromMap()
+ {
+ Map<String, Object> map = new HashMap<>();
+ map.put("sstable_preemptive_open_interval", null);
+ map.put("index_summary_resize_interval", null);
+
+ Config c = YamlConfigurationLoader.fromMap(map, true, Config.class);
+ assert c.sstable_preemptive_open_interval == null;
+ assert c.index_summary_resize_interval == null;
+
+ map = ImmutableMap.of(
+ "sstable_preemptive_open_interval_in_mb", "-1",
+ "index_summary_resize_interval_in_minutes", "-1"
+ );
+ c = YamlConfigurationLoader.fromMap(map, Config.class);
+
+ assertThat(c.sstable_preemptive_open_interval).isNull();
+ assertThat(c.index_summary_resize_interval).isNull();
+ }
+
+ @Test
public void readThresholdsFromConfig()
{
Config c = load("test/conf/cassandra.yaml");
@@ -311,6 +345,10 @@
assertThatThrownBy(() -> from("stream_throughput_outbound_megabits_per_sec", -2).stream_throughput_outbound.toMegabitsPerSecondAsInt())
.hasRootCauseInstanceOf(IllegalArgumentException.class)
.hasRootCauseMessage("Invalid data rate: value must be non-negative");
+
+ // NEGATIVE_MEBIBYTES_DATA_STORAGE_INT
+ assertThat(from("sstable_preemptive_open_interval_in_mb", "1").sstable_preemptive_open_interval.toMebibytes()).isEqualTo(1);
+ assertThat(from("sstable_preemptive_open_interval_in_mb", -2).sstable_preemptive_open_interval).isNull();
}
private static Config from(Object... values)
diff --git a/test/unit/org/apache/cassandra/db/virtual/SettingsTableTest.java b/test/unit/org/apache/cassandra/db/virtual/SettingsTableTest.java
index 98b29b5..26a9e88 100644
--- a/test/unit/org/apache/cassandra/db/virtual/SettingsTableTest.java
+++ b/test/unit/org/apache/cassandra/db/virtual/SettingsTableTest.java
@@ -56,6 +56,8 @@
config = new Config();
config.client_encryption_options.applyConfig();
config.server_encryption_options.applyConfig();
+ config.sstable_preemptive_open_interval = null;
+ config.index_summary_resize_interval = null;
table = new SettingsTable(KS_NAME, config);
VirtualKeyspaceRegistry.instance.register(new VirtualKeyspace(KS_NAME, ImmutableList.of(table)));
disablePreparedReuseForTest();
@@ -106,6 +108,22 @@
assertRowsNet(executeNet(q));
}
+ @Test
+ public void virtualTableBackwardCompatibility() throws Throwable
+ {
+ // test NEGATIVE_MEBIBYTES_DATA_STORAGE_INT converter
+ String q = "SELECT * FROM vts.settings WHERE name = 'sstable_preemptive_open_interval';";
+ assertRowsNet(executeNet(q), new Object[] {"sstable_preemptive_open_interval", null});
+ q = "SELECT * FROM vts.settings WHERE name = 'sstable_preemptive_open_interval_in_mb';";
+ assertRowsNet(executeNet(q), new Object[] {"sstable_preemptive_open_interval_in_mb", "-1"});
+
+ // test MINUTES_CUSTOM_DURATION - test to be added later whe
+ q = "SELECT * FROM vts.settings WHERE name = 'index_summary_resize_interval';";
+ assertRowsNet(executeNet(q), new Object[] {"index_summary_resize_interval", null});
+ q = "SELECT * FROM vts.settings WHERE name = 'index_summary_resize_interval_in_minutes';";
+ assertRowsNet(executeNet(q), new Object[] {"index_summary_resize_interval_in_minutes", "-1"});
+ }
+
private String getValue(Property prop)
{
Object v = prop.get(config);
diff --git a/test/unit/org/apache/cassandra/service/StorageServiceTest.java b/test/unit/org/apache/cassandra/service/StorageServiceTest.java
index e42e202..694c876 100644
--- a/test/unit/org/apache/cassandra/service/StorageServiceTest.java
+++ b/test/unit/org/apache/cassandra/service/StorageServiceTest.java
@@ -21,6 +21,7 @@
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.atomic.AtomicInteger;
+import org.junit.Assert;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
@@ -169,6 +170,13 @@
}
@Test
+ public void testSetGetSSTablePreemptiveOpenIntervalInMB()
+ {
+ StorageService.instance.setSSTablePreemptiveOpenIntervalInMB(-1);
+ Assert.assertEquals(-1, StorageService.instance.getSSTablePreemptiveOpenIntervalInMB());
+ }
+
+ @Test
public void testScheduledExecutorsShutdownOnDrain() throws Throwable
{
final AtomicInteger numberOfRuns = new AtomicInteger(0);