Author: jbellis
Date: Mon Sep 27 22:10:42 2010
New Revision: 1001929
URL: http://svn.apache.org/viewvc?rev=1001929&view=rev
Log:
sanity checks for compaction thresholds.
patch by jhermes; reviewed by jbellis for CASSANDRA-1527
Modified:
cassandra/trunk/conf/cassandra.yaml
cassandra/trunk/src/java/org/apache/cassandra/avro/CassandraServer.java
cassandra/trunk/src/java/org/apache/cassandra/config/CFMetaData.java
cassandra/trunk/src/java/org/apache/cassandra/config/DatabaseDescriptor.java
cassandra/trunk/src/java/org/apache/cassandra/db/ColumnFamilyStore.java
cassandra/trunk/src/java/org/apache/cassandra/db/ColumnFamilyStoreMBean.java
cassandra/trunk/src/java/org/apache/cassandra/db/CompactionManager.java
cassandra/trunk/test/unit/org/apache/cassandra/db/DefsTest.java
Modified: cassandra/trunk/conf/cassandra.yaml
URL:
http://svn.apache.org/viewvc/cassandra/trunk/conf/cassandra.yaml?rev=1001929&r1=1001928&r2=1001929&view=diff
==============================================================================
--- cassandra/trunk/conf/cassandra.yaml (original)
+++ cassandra/trunk/conf/cassandra.yaml Mon Sep 27 22:10:42 2010
@@ -1,6 +1,9 @@
# Cassandra storage config YAML
+
+#NOTE !!!!!!!! NOTE
# See http://wiki.apache.org/cassandra/StorageConfiguration for
-# explanations of configuration directives.
+# full explanations of configuration directives
+#NOTE !!!!!!!! NOTE
# The name of the cluster. This is mainly used to prevent machines in
# one logical cluster from joining another.
@@ -290,38 +293,48 @@ index_interval: 128
# - replication_factor: Number of replicas of each row
# - column_families: column families associated with this keyspace
#
-# ColumnFamily required parameters:
-# - name: name of the ColumnFamily. Must not contain the character "-".
-# - compare_with: tells Cassandra how to sort the columns for slicing
-# operations. The default is BytesType, which is a straightforward
-# lexical comparison of the bytes in each column. Other options are
-# AsciiType, UTF8Type, LexicalUUIDType, TimeUUIDType, LongType,
-# and IntegerType (a generic variable-length integer type).
-# You can also specify the fully-qualified class name to a class of
-# your choice extending org.apache.cassandra.db.marshal.AbstractType.
-#
-# ColumnFamily optional parameters:
-# - keys_cached: specifies the number of keys per sstable whose
-# locations we keep in memory in "mostly LRU" order. (JUST the key
-# locations, NOT any column values.) Specify a fraction (value less
-# than 1) or an absolute number of keys to cache. Defaults to 200000
-# keys.
-# - rows_cached: specifies the number of rows whose entire contents we
-# cache in memory. Do not use this on ColumnFamilies with large rows,
-# or ColumnFamilies with high write:read ratios. Specify a fraction
-# (value less than 1) or an absolute number of rows to cache.
-# Defaults to 0. (i.e. row caching is off by default)
-# - comment: used to attach additional human-readable information about
-# the column family to its definition.
-# - read_repair_chance: specifies the probability with which read
-# repairs should be invoked on non-quorum reads. must be between 0
-# and 1. defaults to 1.0 (always read repair).
-# - preload_row_cache: If true, will populate row cache on startup.
-# Defaults to false.
-# - gc_grace_seconds: specifies the time to wait before garbage
-# collecting tombstones (deletion markers). defaults to 864000 (10
-# days). See http://wiki.apache.org/cassandra/DistributedDeletes
-#
+# ColumnFamily required parameters:
+# - name: name of the ColumnFamily. Must not contain the character "-".
+# - compare_with: tells Cassandra how to sort the columns for slicing
+# operations. The default is BytesType, which is a straightforward
+# lexical comparison of the bytes in each column. Other options are
+# AsciiType, UTF8Type, LexicalUUIDType, TimeUUIDType, LongType,
+# and IntegerType (a generic variable-length integer type).
+# You can also specify the fully-qualified class name to a class of
+# your choice extending org.apache.cassandra.db.marshal.AbstractType.
+#
+# ColumnFamily optional parameters:
+# - keys_cached: specifies the number of keys per sstable whose
+# locations we keep in memory in "mostly LRU" order. (JUST the key
+# locations, NOT any column values.) Specify a fraction (value less
+# than 1) or an absolute number of keys to cache. Defaults to 200000
+# keys.
+# - rows_cached: specifies the number of rows whose entire contents we
+# cache in memory. Do not use this on ColumnFamilies with large rows,
+# or ColumnFamilies with high write:read ratios. Specify a fraction
+# (value less than 1) or an absolute number of rows to cache.
+# Defaults to 0. (i.e. row caching is off by default)
+# - comment: used to attach additional human-readable information about
+# the column family to its definition.
+# - read_repair_chance: specifies the probability with which read
+# repairs should be invoked on non-quorum reads. must be between 0
+# and 1. defaults to 1.0 (always read repair).
+# - preload_row_cache: If true, will populate row cache on startup.
+# Defaults to false.
+# - gc_grace_seconds: specifies the time to wait before garbage
+# collecting tombstones (deletion markers). defaults to 864000 (10
+# days). See http://wiki.apache.org/cassandra/DistributedDeletes
+# - default_validation_class: specifies a validator class to use for
+# validating all the column values in the CF.
+# - min_compaction_threshold: the minimum number of SSTables needed
+# to start a minor compaction. increasing this will cause minor
+# compactions to start less frequently and be more intensive. setting
+# this to 0 disables minor compactions. defaults to 4.
+# - max_compaction_threshold: the maximum number of SSTables allowed
+# before a minor compaction is forced. decreasing this will cause
+# minor compactions to start more frequently and be less intensive.
+# setting this to 0 disables minor compactions. defaults to 32.
+#
# NOTE: this keyspace definition is for demonstration purposes only.
# Cassandra will not load these definitions during startup. See
# http://wiki.apache.org/cassandra/FAQ#no_keyspaces for an explanation.
Modified:
cassandra/trunk/src/java/org/apache/cassandra/avro/CassandraServer.java
URL:
http://svn.apache.org/viewvc/cassandra/trunk/src/java/org/apache/cassandra/avro/CassandraServer.java?rev=1001929&r1=1001928&r2=1001929&view=diff
==============================================================================
--- cassandra/trunk/src/java/org/apache/cassandra/avro/CassandraServer.java
(original)
+++ cassandra/trunk/src/java/org/apache/cassandra/avro/CassandraServer.java Mon
Sep 27 22:10:42 2010
@@ -840,6 +840,8 @@ public class CassandraServer implements
String validate = cf_def.default_validation_class == null ?
D_CF_COMPTYPE : cf_def.default_validation_class.toString();
String subCompare = cf_def.subcomparator_type == null ?
D_CF_SUBCOMPTYPE : cf_def.subcomparator_type.toString();
+ CFMetaData.validateMinMaxCompactionThresholds(cf_def);
+
return new CFMetaData(cf_def.keyspace.toString(),
cf_def.name.toString(),
ColumnFamilyType.create(cfType),
Modified: cassandra/trunk/src/java/org/apache/cassandra/config/CFMetaData.java
URL:
http://svn.apache.org/viewvc/cassandra/trunk/src/java/org/apache/cassandra/config/CFMetaData.java?rev=1001929&r1=1001928&r2=1001929&view=diff
==============================================================================
--- cassandra/trunk/src/java/org/apache/cassandra/config/CFMetaData.java
(original)
+++ cassandra/trunk/src/java/org/apache/cassandra/config/CFMetaData.java Mon
Sep 27 22:10:42 2010
@@ -480,6 +480,8 @@ public final class CFMetaData
}
else if (subcolumnComparator !=
DatabaseDescriptor.getComparator(cf_def.subcomparator_type.toString()))
throw new ConfigurationException("subcolumncomparators do not
match.");
+
+ validateMinMaxCompactionThresholds(cf_def);
return new CFMetaData(tableName,
cfName,
@@ -523,7 +525,9 @@ public final class CFMetaData
}
else if (subcolumnComparator !=
DatabaseDescriptor.getComparator(cf_def.subcomparator_type))
throw new ConfigurationException("subcolumncomparators do not
match.");
-
+
+ validateMinMaxCompactionThresholds(cf_def);
+
return new CFMetaData(tableName,
cfName,
cfType,
@@ -615,4 +619,64 @@ public final class CFMetaData
def.column_metadata = column_meta;
return def;
}
+
+ public static void
validateMinMaxCompactionThresholds(org.apache.cassandra.thrift.CfDef cf_def)
throws ConfigurationException
+ {
+ if (cf_def.isSetMin_compaction_threshold() &&
cf_def.isSetMax_compaction_threshold())
+ {
+ if ((cf_def.min_compaction_threshold >
cf_def.max_compaction_threshold) &&
+ cf_def.max_compaction_threshold != 0)
+ {
+ throw new ConfigurationException("min_compaction_threshold
cannot be greater than max_compaction_threshold");
+ }
+ }
+ else if (cf_def.isSetMin_compaction_threshold())
+ {
+ if (cf_def.min_compaction_threshold >
DEFAULT_MAX_COMPACTION_THRESHOLD)
+ {
+ throw new ConfigurationException("min_compaction_threshold
cannot be greather than max_compaction_threshold (default " +
+
DEFAULT_MAX_COMPACTION_THRESHOLD + ")");
+ }
+ }
+ else if (cf_def.isSetMax_compaction_threshold())
+ {
+ if (cf_def.max_compaction_threshold <
DEFAULT_MIN_COMPACTION_THRESHOLD && cf_def.max_compaction_threshold != 0) {
+ throw new ConfigurationException("max_compaction_threshold
cannot be less than min_compaction_threshold");
+ }
+ }
+ else
+ {
+ //Defaults are valid.
+ }
+ }
+
+ public static void
validateMinMaxCompactionThresholds(org.apache.cassandra.avro.CfDef cf_def)
throws ConfigurationException
+ {
+ if (cf_def.min_compaction_threshold != null &&
cf_def.max_compaction_threshold != null)
+ {
+ if ((cf_def.min_compaction_threshold >
cf_def.max_compaction_threshold) &&
+ cf_def.max_compaction_threshold != 0)
+ {
+ throw new ConfigurationException("min_compaction_threshold
cannot be greater than max_compaction_threshold");
+ }
+ }
+ else if (cf_def.min_compaction_threshold != null)
+ {
+ if (cf_def.min_compaction_threshold >
DEFAULT_MAX_COMPACTION_THRESHOLD)
+ {
+ throw new ConfigurationException("min_compaction_threshold
cannot be greather than max_compaction_threshold (default " +
+
DEFAULT_MAX_COMPACTION_THRESHOLD + ")");
+ }
+ }
+ else if (cf_def.max_compaction_threshold != null)
+ {
+ if (cf_def.max_compaction_threshold <
DEFAULT_MIN_COMPACTION_THRESHOLD && cf_def.max_compaction_threshold != 0) {
+ throw new ConfigurationException("max_compaction_threshold
cannot be less than min_compaction_threshold");
+ }
+ }
+ else
+ {
+ //Defaults are valid.
+ }
+ }
}
Modified:
cassandra/trunk/src/java/org/apache/cassandra/config/DatabaseDescriptor.java
URL:
http://svn.apache.org/viewvc/cassandra/trunk/src/java/org/apache/cassandra/config/DatabaseDescriptor.java?rev=1001929&r1=1001928&r2=1001929&view=diff
==============================================================================
---
cassandra/trunk/src/java/org/apache/cassandra/config/DatabaseDescriptor.java
(original)
+++
cassandra/trunk/src/java/org/apache/cassandra/config/DatabaseDescriptor.java
Mon Sep 27 22:10:42 2010
@@ -548,7 +548,16 @@ public class DatabaseDescriptor
{
throw new ConfigurationException("read_repair_chance must
be between 0.0 and 1.0");
}
-
+
+ if (cf.min_compaction_threshold < 0 ||
cf.max_compaction_threshold < 0)
+ {
+ throw new
ConfigurationException("min/max_compaction_thresholds must be non-negative
integers.");
+ }
+ if ((cf.min_compaction_threshold >
cf.max_compaction_threshold) && cf.max_compaction_threshold != 0)
+ {
+ throw new ConfigurationException("min_compaction_threshold
must be smaller than max_compaction_threshold, or either must be 0 (disabled)");
+ }
+
Map<byte[], ColumnDefinition> metadata = new TreeMap<byte[],
ColumnDefinition>(FBUtilities.byteArrayComparator);
for (RawColumnDefinition rcd : cf.column_metadata)
{
Modified:
cassandra/trunk/src/java/org/apache/cassandra/db/ColumnFamilyStore.java
URL:
http://svn.apache.org/viewvc/cassandra/trunk/src/java/org/apache/cassandra/db/ColumnFamilyStore.java?rev=1001929&r1=1001928&r2=1001929&view=diff
==============================================================================
--- cassandra/trunk/src/java/org/apache/cassandra/db/ColumnFamilyStore.java
(original)
+++ cassandra/trunk/src/java/org/apache/cassandra/db/ColumnFamilyStore.java Mon
Sep 27 22:10:42 2010
@@ -1637,6 +1637,10 @@ public class ColumnFamilyStore implement
public void setMinimumCompactionThreshold(int minCompactionThreshold)
{
+ //TODO: If someone complains this is too rude, make it more friendly.
+ if ((minCompactionThreshold > this.maxCompactionThreshold) &&
this.maxCompactionThreshold != 0) {
+ throw new RuntimeException("The min_compaction_threshold cannot be
larger than the max.");
+ }
this.minCompactionThreshold = minCompactionThreshold;
}
@@ -1647,6 +1651,10 @@ public class ColumnFamilyStore implement
public void setMaximumCompactionThreshold(int maxCompactionThreshold)
{
+ //TODO: If someone complains this is too rude, make it more friendly.
+ if (maxCompactionThreshold < this.minCompactionThreshold) {
+ throw new RuntimeException("The max_compaction_threshold cannot be
smaller than the min.");
+ }
this.maxCompactionThreshold = maxCompactionThreshold;
}
Modified:
cassandra/trunk/src/java/org/apache/cassandra/db/ColumnFamilyStoreMBean.java
URL:
http://svn.apache.org/viewvc/cassandra/trunk/src/java/org/apache/cassandra/db/ColumnFamilyStoreMBean.java?rev=1001929&r1=1001928&r2=1001929&view=diff
==============================================================================
---
cassandra/trunk/src/java/org/apache/cassandra/db/ColumnFamilyStoreMBean.java
(original)
+++
cassandra/trunk/src/java/org/apache/cassandra/db/ColumnFamilyStoreMBean.java
Mon Sep 27 22:10:42 2010
@@ -185,4 +185,9 @@ public interface ColumnFamilyStoreMBean
* Sets the maximum number of sstables in queue before compaction kicks off
*/
public void setMaximumCompactionThreshold(int threshold);
+
+ /**
+ * Disable automatic compaction.
+ */
+ public void disableAutoCompaction();
}
Modified:
cassandra/trunk/src/java/org/apache/cassandra/db/CompactionManager.java
URL:
http://svn.apache.org/viewvc/cassandra/trunk/src/java/org/apache/cassandra/db/CompactionManager.java?rev=1001929&r1=1001928&r2=1001929&view=diff
==============================================================================
--- cassandra/trunk/src/java/org/apache/cassandra/db/CompactionManager.java
(original)
+++ cassandra/trunk/src/java/org/apache/cassandra/db/CompactionManager.java Mon
Sep 27 22:10:42 2010
@@ -87,7 +87,7 @@ public class CompactionManager implement
Integer minThreshold = cfs.getMinimumCompactionThreshold();
Integer maxThreshold = cfs.getMaximumCompactionThreshold();
- if (minThreshold <= 0 || maxThreshold <= 0)
+ if (minThreshold == 0 || maxThreshold == 0)
{
logger.debug("Compaction is currently disabled.");
return 0;
@@ -114,18 +114,25 @@ public class CompactionManager implement
private void updateEstimateFor(ColumnFamilyStore cfs,
Set<List<SSTableReader>> buckets)
{
- Integer minct = cfs.getMinimumCompactionThreshold();
- Integer maxct = cfs.getMaximumCompactionThreshold();
+ Integer minThreshold = cfs.getMinimumCompactionThreshold();
+ Integer maxThreshold = cfs.getMaximumCompactionThreshold();
- int n = 0;
- for (List<SSTableReader> sstables : buckets)
+ if (minThreshold > 0 && maxThreshold > 0)
{
- if (sstables.size() >= minct)
+ int n = 0;
+ for (List<SSTableReader> sstables : buckets)
{
- n += 1 + sstables.size() / (maxct - minct);
+ if (sstables.size() >= minThreshold)
+ {
+ n += Math.ceil((double)sstables.size() / maxThreshold);
+ }
}
+ estimatedCompactions.put(cfs, n);
+ }
+ else
+ {
+ logger.debug("Compaction is currently disabled.");
}
- estimatedCompactions.put(cfs, n);
}
public Future<Object> submitCleanup(final ColumnFamilyStore cfStore)
Modified: cassandra/trunk/test/unit/org/apache/cassandra/db/DefsTest.java
URL:
http://svn.apache.org/viewvc/cassandra/trunk/test/unit/org/apache/cassandra/db/DefsTest.java?rev=1001929&r1=1001928&r2=1001929&view=diff
==============================================================================
--- cassandra/trunk/test/unit/org/apache/cassandra/db/DefsTest.java (original)
+++ cassandra/trunk/test/unit/org/apache/cassandra/db/DefsTest.java Mon Sep 27
22:10:42 2010
@@ -539,6 +539,8 @@ public class DefsTest extends CleanupHel
cf_def.setRow_cache_size(43.3);
cf_def.setColumn_metadata(new ArrayList<ColumnDef>());
cf_def.setDefault_validation_class("BytesType");
+ cf_def.setMin_compaction_threshold(5);
+ cf_def.setMax_compaction_threshold(31);
// test valid operations.
cf_def.setComment("Modified comment");
@@ -575,7 +577,17 @@ public class DefsTest extends CleanupHel
updateCfm = cf.apply(cf_def);
new UpdateColumnFamily(cf, updateCfm).apply();
cf = updateCfm;
-
+
+ cf_def.setMin_compaction_threshold(3);
+ updateCfm = cf.apply(cf_def);
+ new UpdateColumnFamily(cf, updateCfm).apply();
+ cf = updateCfm;
+
+ cf_def.setMax_compaction_threshold(33);
+ updateCfm = cf.apply(cf_def);
+ new UpdateColumnFamily(cf, updateCfm).apply();
+ cf = updateCfm;
+
// can't test changing the reconciler because there is only one impl.
// check the cumulative affect.
@@ -646,6 +658,28 @@ public class DefsTest extends CleanupHel
{
cf_def.setComparator_type(UTF8Type.class.getSimpleName());
}
+
+ try
+ {
+ cf_def.setMin_compaction_threshold(34);
+ updateCfm = cf.apply(cf_def);
+ throw new AssertionError("Should have blown up when min > max.");
+ }
+ catch (ConfigurationException expected)
+ {
+ cf_def.setMin_compaction_threshold(3);
+ }
+
+ try
+ {
+ cf_def.setMax_compaction_threshold(2);
+ updateCfm = cf.apply(cf_def);
+ throw new AssertionError("Should have blown up when max > min.");
+ }
+ catch (ConfigurationException expected)
+ {
+ cf_def.setMax_compaction_threshold(33);
+ }
}
private CFMetaData addTestCF(String ks, String cf, String comment)