Merge branch 'cassandra-5.0' into trunk

This commit is contained in:
David Capwell 2025-11-07 11:52:26 -08:00
commit 9a534ba06f
5 changed files with 57 additions and 6 deletions

View File

@ -329,6 +329,7 @@ Merged from 4.1:
* Enforce CQL message size limit on multiframe messages (CASSANDRA-20052)
* Fix race condition in DecayingEstimatedHistogramReservoir during rescale (CASSANDRA-19365)
Merged from 4.0:
* Leveled Compaction doesn't validate maxBytesForLevel when the table is altered/created (CASSANDRA-20570)
* Updated dtest-api to 0.0.18 and removed JMX-related classes that now live in the dtest-api (CASSANDRA-20884)
* Fixed incorrect error message constant for keyspace name length validation (CASSANDRA-20915)
* Prevent too long table names not fitting file names (CASSANDRA-20389)

View File

@ -18,6 +18,7 @@
package org.apache.cassandra.db.compaction;
import java.util.*;
import java.math.BigInteger;
import com.google.common.annotations.VisibleForTesting;
@ -43,6 +44,7 @@ import org.apache.cassandra.io.sstable.ISSTableScanner;
import org.apache.cassandra.io.sstable.format.SSTableReader;
import static org.apache.cassandra.config.CassandraRelevantProperties.TOLERATE_SSTABLE_SIZE;
import static org.apache.cassandra.db.compaction.LeveledGenerations.MAX_LEVEL_COUNT;
public class LeveledCompactionStrategy extends AbstractCompactionStrategy
{
@ -569,10 +571,14 @@ public class LeveledCompactionStrategy extends AbstractCompactionStrategy
{
Map<String, String> uncheckedOptions = AbstractCompactionStrategy.validateOptions(options);
int ssSize;
int fanoutSize;
// Validate the sstable_size option
String size = options.containsKey(SSTABLE_SIZE_OPTION) ? options.get(SSTABLE_SIZE_OPTION) : "1";
try
{
int ssSize = Integer.parseInt(size);
ssSize = Integer.parseInt(size);
if (ssSize < 1)
{
throw new ConfigurationException(String.format("%s must be larger than 0, but was %s", SSTABLE_SIZE_OPTION, ssSize));
@ -589,7 +595,7 @@ public class LeveledCompactionStrategy extends AbstractCompactionStrategy
String levelFanoutSize = options.containsKey(LEVEL_FANOUT_SIZE_OPTION) ? options.get(LEVEL_FANOUT_SIZE_OPTION) : String.valueOf(DEFAULT_LEVEL_FANOUT_SIZE);
try
{
int fanoutSize = Integer.parseInt(levelFanoutSize);
fanoutSize = Integer.parseInt(levelFanoutSize);
if (fanoutSize < 1)
{
throw new ConfigurationException(String.format("%s must be larger than 0, but was %s", LEVEL_FANOUT_SIZE_OPTION, fanoutSize));
@ -597,7 +603,23 @@ public class LeveledCompactionStrategy extends AbstractCompactionStrategy
}
catch (NumberFormatException ex)
{
throw new ConfigurationException(String.format("%s is not a parsable int (base10) for %s", size, LEVEL_FANOUT_SIZE_OPTION), ex);
throw new ConfigurationException(String.format("%s is not a parsable int (base10) for %s", levelFanoutSize, LEVEL_FANOUT_SIZE_OPTION), ex);
}
// Validate max Bytes for a level
try
{
long maxSSTableSizeInBytes = Math.multiplyExact(ssSize, 1024L * 1024L); // Convert MB to Bytes
BigInteger fanoutPower = BigInteger.valueOf(fanoutSize).pow(MAX_LEVEL_COUNT - 1);
BigInteger maxBytes = fanoutPower.multiply(BigInteger.valueOf(maxSSTableSizeInBytes));
BigInteger longMaxValue = BigInteger.valueOf(Long.MAX_VALUE);
if (maxBytes.compareTo(longMaxValue) > 0)
throw new ConfigurationException(String.format("At most %s bytes may be in a compaction level; " +
"your maxSSTableSize must be absurdly high to compute %s", Long.MAX_VALUE, maxBytes));
}
catch (ArithmeticException ex)
{
throw new ConfigurationException(String.format("sstable_size_in_mb=%d is too large; resulting bytes exceed Long.MAX_VALUE (%d)", ssSize, Long.MAX_VALUE), ex);
}
uncheckedOptions.remove(LEVEL_FANOUT_SIZE_OPTION);

View File

@ -975,6 +975,24 @@ public class LeveledCompactionStrategyTest
}
}
@Test()
public void testInvalidFanoutAndSSTableSize()
{
try
{
Map<String, String> options = new HashMap<>();
options.put("class", "LeveledCompactionStrategy");
options.put("fanout_size", "90");
options.put("sstable_size_in_mb", "1089");
LeveledCompactionStrategy.validateOptions(options);
Assert.fail("fanout_sizeed and sstable_size_in_mb are invalid, but did not throw ConfigurationException");
}
catch (ConfigurationException e)
{
assertTrue(e.getMessage().contains("your maxSSTableSize must be absurdly high to compute"));
}
}
@Test
public void testReduceScopeL0()
{

View File

@ -134,6 +134,13 @@ public class CreateTableValidationTest extends CQLTester
String.format("CREATE TABLE %s.\" \" (key int PRIMARY KEY, val int)", KEYSPACE));
}
@Test
public void testInvalidCompactionOptions()
{
expectedFailure(ConfigurationException.class, "CREATE TABLE %s (k int PRIMARY KEY, v int) WITH compaction = {'class': 'LeveledCompactionStrategy', 'fanout_size': '90', 'sstable_size_in_mb': '1089'}",
"your maxSSTableSize must be absurdly high to compute");
}
private void expectedFailure(final Class<? extends RequestValidationException> exceptionType, String statement, String errorMsg)
{

View File

@ -52,7 +52,6 @@ import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Sets;
import accord.utils.SortedArrays.SortedArrayList;
import org.apache.cassandra.db.compaction.LeveledManifest;
import org.apache.cassandra.schema.*;
import org.apache.cassandra.service.consensus.migration.ConsensusMigrationState;
import org.apache.cassandra.tcm.extensions.ExtensionKey;
@ -143,6 +142,7 @@ import static org.apache.cassandra.utils.Generators.SMALL_TIME_SPAN_NANOS;
import static org.apache.cassandra.utils.Generators.TIMESTAMP_NANOS;
import static org.apache.cassandra.utils.Generators.TINY_TIME_SPAN_NANOS;
import static org.apache.cassandra.utils.Generators.directAndHeapBytes;
import static org.junit.Assert.assertTrue;
public final class CassandraGenerators
{
@ -585,11 +585,14 @@ public final class CassandraGenerators
try
{
// see org.apache.cassandra.db.compaction.LeveledGenerations.MAX_LEVEL_COUNT for why 8 is hard coded here
LeveledManifest.maxBytesForLevel(8, value, maxSSTableSizeInBytes);
// LeveledManifest.maxBytesForLevel(8, value, maxSSTableSizeInBytes);
options.put(LeveledCompactionStrategy.LEVEL_FANOUT_SIZE_OPTION, value.toString());
LeveledCompactionStrategy.validateOptions(options);
break; // value is good, keep it
}
catch (RuntimeException e)
catch (ConfigurationException e)
{
assertTrue(e.getMessage().contains("your maxSSTableSize must be absurdly high to compute"));
// this value is too large... lets shrink it
if (value.intValue() == 1)
throw new AssertionError("There is no possible fanout size that works with maxSSTableSizeInMB=" + maxSSTableSizeInMB);