1818package org .apache .cassandra .db .compaction ;
1919
2020import java .util .*;
21+ import java .math .BigInteger ;
2122
2223
2324import com .google .common .annotations .VisibleForTesting ;
4344import org .apache .cassandra .io .sstable .ISSTableScanner ;
4445import org .apache .cassandra .io .sstable .format .SSTableReader ;
4546
47+ import static org .apache .cassandra .db .compaction .LeveledGenerations .MAX_LEVEL_COUNT ;
48+
4649public class LeveledCompactionStrategy extends AbstractCompactionStrategy
4750{
4851 private static final Logger logger = LoggerFactory .getLogger (LeveledCompactionStrategy .class );
@@ -565,10 +568,14 @@ public static Map<String, String> validateOptions(Map<String, String> options) t
565568 {
566569 Map <String , String > uncheckedOptions = AbstractCompactionStrategy .validateOptions (options );
567570
571+ int ssSize ;
572+ int fanoutSize ;
573+
574+ // Validate the sstable_size option
568575 String size = options .containsKey (SSTABLE_SIZE_OPTION ) ? options .get (SSTABLE_SIZE_OPTION ) : "1" ;
569576 try
570577 {
571- int ssSize = Integer .parseInt (size );
578+ ssSize = Integer .parseInt (size );
572579 if (ssSize < 1 )
573580 {
574581 throw new ConfigurationException (String .format ("%s must be larger than 0, but was %s" , SSTABLE_SIZE_OPTION , ssSize ));
@@ -585,15 +592,31 @@ public static Map<String, String> validateOptions(Map<String, String> options) t
585592 String levelFanoutSize = options .containsKey (LEVEL_FANOUT_SIZE_OPTION ) ? options .get (LEVEL_FANOUT_SIZE_OPTION ) : String .valueOf (DEFAULT_LEVEL_FANOUT_SIZE );
586593 try
587594 {
588- int fanoutSize = Integer .parseInt (levelFanoutSize );
595+ fanoutSize = Integer .parseInt (levelFanoutSize );
589596 if (fanoutSize < 1 )
590597 {
591598 throw new ConfigurationException (String .format ("%s must be larger than 0, but was %s" , LEVEL_FANOUT_SIZE_OPTION , fanoutSize ));
592599 }
593600 }
594601 catch (NumberFormatException ex )
595602 {
596- throw new ConfigurationException (String .format ("%s is not a parsable int (base10) for %s" , size , LEVEL_FANOUT_SIZE_OPTION ), ex );
603+ throw new ConfigurationException (String .format ("%s is not a parsable int (base10) for %s" , levelFanoutSize , LEVEL_FANOUT_SIZE_OPTION ), ex );
604+ }
605+
606+ // Validate max Bytes for a level
607+ try
608+ {
609+ long maxSSTableSizeInBytes = Math .multiplyExact (ssSize , 1024L * 1024L ); // Convert MB to Bytes
610+ BigInteger fanoutPower = BigInteger .valueOf (fanoutSize ).pow (MAX_LEVEL_COUNT - 1 );
611+ BigInteger maxBytes = fanoutPower .multiply (BigInteger .valueOf (maxSSTableSizeInBytes ));
612+ BigInteger longMaxValue = BigInteger .valueOf (Long .MAX_VALUE );
613+ if (maxBytes .compareTo (longMaxValue ) > 0 )
614+ throw new ConfigurationException (String .format ("At most %s bytes may be in a compaction level; " +
615+ "your maxSSTableSize must be absurdly high to compute %s" , Long .MAX_VALUE , maxBytes ));
616+ }
617+ catch (ArithmeticException ex )
618+ {
619+ 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 );
597620 }
598621
599622 uncheckedOptions .remove (LEVEL_FANOUT_SIZE_OPTION );
0 commit comments