Repository: cassandra Updated Branches: refs/heads/cassandra-2.1 c8d163f73 -> 5aca7d79a
Add new JMX methods to change local compaction strategy Patch by marcuse; reviewed by iamaleksey for CASSANDRA-9965 Project: http://git-wip-us.apache.org/repos/asf/cassandra/repo Commit: http://git-wip-us.apache.org/repos/asf/cassandra/commit/5aca7d79 Tree: http://git-wip-us.apache.org/repos/asf/cassandra/tree/5aca7d79 Diff: http://git-wip-us.apache.org/repos/asf/cassandra/diff/5aca7d79 Branch: refs/heads/cassandra-2.1 Commit: 5aca7d79aaf88f9c34dcae52f24bb62a28add91e Parents: c8d163f Author: Marcus Eriksson <marc...@apache.org> Authored: Tue Aug 4 20:31:25 2015 +0200 Committer: Marcus Eriksson <marc...@apache.org> Committed: Mon Aug 10 09:02:47 2015 +0200 ---------------------------------------------------------------------- CHANGES.txt | 1 + NEWS.txt | 3 +- .../org/apache/cassandra/config/CFMetaData.java | 10 ++- .../apache/cassandra/db/ColumnFamilyStore.java | 35 +++++++++ .../cassandra/db/ColumnFamilyStoreMBean.java | 21 +++++ .../compaction/AbstractCompactionStrategy.java | 2 +- .../compaction/WrappingCompactionStrategy.java | 51 +++++++++--- .../db/compaction/CompactionsCQLTest.java | 82 +++++++++++++++++++- 8 files changed, 190 insertions(+), 15 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/cassandra/blob/5aca7d79/CHANGES.txt ---------------------------------------------------------------------- diff --git a/CHANGES.txt b/CHANGES.txt index 7151883..462de44 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,4 +1,5 @@ 2.1.9 + * Add new JMX methods to change local compaction strategy (CASSANDRA-9965) * Write hints for paxos commits (CASSANDRA-7342) * (cqlsh) Fix timestamps before 1970 on Windows, always use UTC for timestamp display (CASSANDRA-10000) http://git-wip-us.apache.org/repos/asf/cassandra/blob/5aca7d79/NEWS.txt ---------------------------------------------------------------------- diff --git a/NEWS.txt b/NEWS.txt index 0b64e31..f6e2665 100644 --- a/NEWS.txt +++ b/NEWS.txt @@ -24,7 +24,8 @@ Upgrading - Commit log files are no longer recycled by default, due to negative performance implications. This can be enabled again with the commitlog_segment_recycling option in your cassandra.yaml - + - JMX methods set/getCompactionStrategyClass have been deprecated, use + set/getLocalCompactionStrategy/set/getLocalCompactionStrategyJson instead 2.1.8 ===== http://git-wip-us.apache.org/repos/asf/cassandra/blob/5aca7d79/src/java/org/apache/cassandra/config/CFMetaData.java ---------------------------------------------------------------------- diff --git a/src/java/org/apache/cassandra/config/CFMetaData.java b/src/java/org/apache/cassandra/config/CFMetaData.java index 4bc5f1b..2c6a30c 100644 --- a/src/java/org/apache/cassandra/config/CFMetaData.java +++ b/src/java/org/apache/cassandra/config/CFMetaData.java @@ -1283,7 +1283,9 @@ public final class CFMetaData return strategyClass; } - public AbstractCompactionStrategy createCompactionStrategyInstance(ColumnFamilyStore cfs) + public static AbstractCompactionStrategy createCompactionStrategyInstance(Class<? extends AbstractCompactionStrategy> compactionStrategyClass, + ColumnFamilyStore cfs, + Map<String, String> compactionStrategyOptions) { try { @@ -1297,6 +1299,12 @@ public final class CFMetaData } } + @Deprecated + public AbstractCompactionStrategy createCompactionStrategyInstance(ColumnFamilyStore cfs) + { + return createCompactionStrategyInstance(compactionStrategyClass, cfs, compactionStrategyOptions); + } + // converts CFM to thrift CfDef public org.apache.cassandra.thrift.CfDef toThrift() { http://git-wip-us.apache.org/repos/asf/cassandra/blob/5aca7d79/src/java/org/apache/cassandra/db/ColumnFamilyStore.java ---------------------------------------------------------------------- diff --git a/src/java/org/apache/cassandra/db/ColumnFamilyStore.java b/src/java/org/apache/cassandra/db/ColumnFamilyStore.java index 6777e7a..f8d796e 100644 --- a/src/java/org/apache/cassandra/db/ColumnFamilyStore.java +++ b/src/java/org/apache/cassandra/db/ColumnFamilyStore.java @@ -252,6 +252,41 @@ public class ColumnFamilyStore implements ColumnFamilyStoreMBean }; } + public void setLocalCompactionStrategyJson(String options) + { + setLocalCompactionStrategy(FBUtilities.fromJsonMap(options)); + } + + public String getLocalCompactionStrategyJson() + { + return FBUtilities.json(getLocalCompactionStrategy()); + } + + public void setLocalCompactionStrategy(Map<String, String> options) + { + try + { + Map<String, String> optionsCopy = new HashMap<>(options); + Class<? extends AbstractCompactionStrategy> compactionStrategyClass = CFMetaData.createCompactionStrategy(optionsCopy.get("class")); + optionsCopy.remove("class"); + CFMetaData.validateCompactionOptions(compactionStrategyClass, optionsCopy); + compactionStrategyWrapper.setNewLocalCompactionStrategy(compactionStrategyClass, optionsCopy); + } + catch (Throwable t) + { + logger.error("Could not set new local compaction strategy", t); + // dont propagate the ConfigurationException over jmx, user will only see a ClassNotFoundException + throw new IllegalArgumentException("Could not set new local compaction strategy: "+t.getMessage()); + } + } + + public Map<String, String> getLocalCompactionStrategy() + { + Map<String, String> options = new HashMap<>(compactionStrategyWrapper.options); + options.put("class", compactionStrategyWrapper.getName()); + return options; + } + public void setCompactionStrategyClass(String compactionStrategyClass) { try http://git-wip-us.apache.org/repos/asf/cassandra/blob/5aca7d79/src/java/org/apache/cassandra/db/ColumnFamilyStoreMBean.java ---------------------------------------------------------------------- diff --git a/src/java/org/apache/cassandra/db/ColumnFamilyStoreMBean.java b/src/java/org/apache/cassandra/db/ColumnFamilyStoreMBean.java index 4df593b..e292be4 100644 --- a/src/java/org/apache/cassandra/db/ColumnFamilyStoreMBean.java +++ b/src/java/org/apache/cassandra/db/ColumnFamilyStoreMBean.java @@ -311,14 +311,35 @@ public interface ColumnFamilyStoreMBean public void setMaximumCompactionThreshold(int threshold); /** + * Sets the compaction strategy locally for this node + * + * Note that this will be set until an ALTER with compaction = {..} is executed or the node is restarted + * + * @param options compaction options with the same syntax as when doing ALTER ... WITH compaction = {..} + */ + public void setLocalCompactionStrategyJson(String options); + public String getLocalCompactionStrategyJson(); + + /** + * Sets the compaction strategy locally for this node + * + * Note that this will be set until an ALTER with compaction = {..} is executed or the node is restarted + * + * @param options compaction options map + */ + public void setLocalCompactionStrategy(Map<String, String> options); + public Map<String, String> getLocalCompactionStrategy(); + /** * Sets the compaction strategy by class name * @param className the name of the compaction strategy class */ + @Deprecated public void setCompactionStrategyClass(String className); /** * Gets the compaction strategy class name */ + @Deprecated public String getCompactionStrategyClass(); /** http://git-wip-us.apache.org/repos/asf/cassandra/blob/5aca7d79/src/java/org/apache/cassandra/db/compaction/AbstractCompactionStrategy.java ---------------------------------------------------------------------- diff --git a/src/java/org/apache/cassandra/db/compaction/AbstractCompactionStrategy.java b/src/java/org/apache/cassandra/db/compaction/AbstractCompactionStrategy.java index 73cda77..77ca404 100644 --- a/src/java/org/apache/cassandra/db/compaction/AbstractCompactionStrategy.java +++ b/src/java/org/apache/cassandra/db/compaction/AbstractCompactionStrategy.java @@ -60,7 +60,7 @@ public abstract class AbstractCompactionStrategy protected static final String UNCHECKED_TOMBSTONE_COMPACTION_OPTION = "unchecked_tombstone_compaction"; protected static final String COMPACTION_ENABLED = "enabled"; - protected Map<String, String> options; + public Map<String, String> options; protected final ColumnFamilyStore cfs; protected float tombstoneThreshold; http://git-wip-us.apache.org/repos/asf/cassandra/blob/5aca7d79/src/java/org/apache/cassandra/db/compaction/WrappingCompactionStrategy.java ---------------------------------------------------------------------- diff --git a/src/java/org/apache/cassandra/db/compaction/WrappingCompactionStrategy.java b/src/java/org/apache/cassandra/db/compaction/WrappingCompactionStrategy.java index 0fed733..ae67599 100644 --- a/src/java/org/apache/cassandra/db/compaction/WrappingCompactionStrategy.java +++ b/src/java/org/apache/cassandra/db/compaction/WrappingCompactionStrategy.java @@ -22,6 +22,7 @@ import java.util.Arrays; import java.util.Collection; import java.util.HashSet; import java.util.List; +import java.util.Map; import java.util.Set; import java.util.concurrent.Callable; @@ -47,6 +48,16 @@ public final class WrappingCompactionStrategy extends AbstractCompactionStrategy private static final Logger logger = LoggerFactory.getLogger(WrappingCompactionStrategy.class); private volatile AbstractCompactionStrategy repaired; private volatile AbstractCompactionStrategy unrepaired; + /* + We keep a copy of the schema compaction options and class here to be able to decide if we + should update the compaction strategy in maybeReloadCompactionStrategy() due to an ALTER. + + If a user changes the local compaction strategy and then later ALTERs a compaction option, + we will use the new compaction options. + */ + private Map<String, String> schemaCompactionOptions; + private Class<?> schemaCompactionStrategyClass; + public WrappingCompactionStrategy(ColumnFamilyStore cfs) { super(cfs, cfs.metadata.compactionStrategyOptions); @@ -146,10 +157,9 @@ public final class WrappingCompactionStrategy extends AbstractCompactionStrategy public synchronized void maybeReloadCompactionStrategy(CFMetaData metadata) { - if (repaired != null && repaired.getClass().equals(metadata.compactionStrategyClass) - && unrepaired != null && unrepaired.getClass().equals(metadata.compactionStrategyClass) - && repaired.options.equals(metadata.compactionStrategyOptions) - && unrepaired.options.equals(metadata.compactionStrategyOptions)) + // compare the old schema configuration to the new one, ignore any locally set changes. + if (metadata.compactionStrategyClass.equals(schemaCompactionStrategyClass) && + metadata.compactionStrategyOptions.equals(schemaCompactionOptions)) return; reloadCompactionStrategy(metadata); } @@ -157,13 +167,10 @@ public final class WrappingCompactionStrategy extends AbstractCompactionStrategy public synchronized void reloadCompactionStrategy(CFMetaData metadata) { boolean disabledWithJMX = !enabled && shouldBeEnabled(); - if (repaired != null) - repaired.shutdown(); - if (unrepaired != null) - unrepaired.shutdown(); - repaired = metadata.createCompactionStrategyInstance(cfs); - unrepaired = metadata.createCompactionStrategyInstance(cfs); - options = ImmutableMap.copyOf(metadata.compactionStrategyOptions); + setStrategy(metadata.compactionStrategyClass, metadata.compactionStrategyOptions); + schemaCompactionOptions = ImmutableMap.copyOf(metadata.compactionStrategyOptions); + schemaCompactionStrategyClass = repaired.getClass(); + if (disabledWithJMX || !shouldBeEnabled()) disable(); else @@ -393,4 +400,26 @@ public final class WrappingCompactionStrategy extends AbstractCompactionStrategy { return Arrays.asList(repaired, unrepaired); } + + public synchronized void setNewLocalCompactionStrategy(Class<? extends AbstractCompactionStrategy> compactionStrategyClass, Map<String, String> options) + { + logger.info("Switching local compaction strategy from {} to {} with options={}", repaired == null ? "null" : repaired.getClass(), compactionStrategyClass, options); + setStrategy(compactionStrategyClass, options); + if (shouldBeEnabled()) + enable(); + else + disable(); + startup(); + } + + private void setStrategy(Class<? extends AbstractCompactionStrategy> compactionStrategyClass, Map<String, String> options) + { + if (repaired != null) + repaired.shutdown(); + if (unrepaired != null) + unrepaired.shutdown(); + repaired = CFMetaData.createCompactionStrategyInstance(compactionStrategyClass, cfs, options); + unrepaired = CFMetaData.createCompactionStrategyInstance(compactionStrategyClass, cfs, options); + this.options = ImmutableMap.copyOf(options); + } } http://git-wip-us.apache.org/repos/asf/cassandra/blob/5aca7d79/test/unit/org/apache/cassandra/db/compaction/CompactionsCQLTest.java ---------------------------------------------------------------------- diff --git a/test/unit/org/apache/cassandra/db/compaction/CompactionsCQLTest.java b/test/unit/org/apache/cassandra/db/compaction/CompactionsCQLTest.java index 58fc062..2798689 100644 --- a/test/unit/org/apache/cassandra/db/compaction/CompactionsCQLTest.java +++ b/test/unit/org/apache/cassandra/db/compaction/CompactionsCQLTest.java @@ -17,12 +17,16 @@ */ package org.apache.cassandra.db.compaction; +import java.util.HashMap; +import java.util.Map; + import org.junit.Test; import org.apache.cassandra.cql3.CQLTester; import org.apache.cassandra.cql3.UntypedResultSet; import org.apache.cassandra.db.ColumnFamilyStore; import org.apache.cassandra.db.Keyspace; +import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; @@ -141,12 +145,88 @@ public class CompactionsCQLTest extends CQLTester assertTrue(minorWasTriggered(KEYSPACE, currentTable())); } + @Test + public void testSetLocalCompactionStrategy() throws Throwable + { + createTable("CREATE TABLE %s (id text PRIMARY KEY)"); + Map<String, String> localOptions = new HashMap<>(); + localOptions.put("class", "DateTieredCompactionStrategy"); + getCurrentColumnFamilyStore().setLocalCompactionStrategy(localOptions); + WrappingCompactionStrategy wrappingCompactionStrategy = (WrappingCompactionStrategy) getCurrentColumnFamilyStore().getCompactionStrategy(); + assertTrue(verifyStrategies(wrappingCompactionStrategy, DateTieredCompactionStrategy.class)); + // altering something non-compaction related + execute("ALTER TABLE %s WITH gc_grace_seconds = 1000"); + // should keep the local compaction strat + assertTrue(verifyStrategies(wrappingCompactionStrategy, DateTieredCompactionStrategy.class)); + // altering a compaction option + execute("ALTER TABLE %s WITH compaction = {'class':'SizeTieredCompactionStrategy', 'min_threshold':3}"); + // will use the new option + assertTrue(verifyStrategies(wrappingCompactionStrategy, SizeTieredCompactionStrategy.class)); + } + + + @Test + public void testSetLocalCompactionStrategyDisable() throws Throwable + { + createTable("CREATE TABLE %s (id text PRIMARY KEY)"); + Map<String, String> localOptions = new HashMap<>(); + localOptions.put("class", "DateTieredCompactionStrategy"); + localOptions.put("enabled", "false"); + getCurrentColumnFamilyStore().setLocalCompactionStrategy(localOptions); + assertFalse(getCurrentColumnFamilyStore().getCompactionStrategy().isEnabled()); + localOptions.clear(); + localOptions.put("class", "DateTieredCompactionStrategy"); + // localOptions.put("enabled", "true"); - this is default! + getCurrentColumnFamilyStore().setLocalCompactionStrategy(localOptions); + assertTrue(getCurrentColumnFamilyStore().getCompactionStrategy().isEnabled()); + } + + + @Test + public void testSetLocalCompactionStrategyEnable() throws Throwable + { + createTable("CREATE TABLE %s (id text PRIMARY KEY)"); + Map<String, String> localOptions = new HashMap<>(); + localOptions.put("class", "DateTieredCompactionStrategy"); + + getCurrentColumnFamilyStore().disableAutoCompaction(); + assertFalse(getCurrentColumnFamilyStore().getCompactionStrategy().isEnabled()); + + getCurrentColumnFamilyStore().setLocalCompactionStrategy(localOptions); + assertTrue(getCurrentColumnFamilyStore().getCompactionStrategy().isEnabled()); + + } + + + + @Test(expected = IllegalArgumentException.class) + public void testBadLocalCompactionStrategyOptions() + { + createTable("CREATE TABLE %s (id text PRIMARY KEY)"); + Map<String, String> localOptions = new HashMap<>(); + localOptions.put("class","SizeTieredCompactionStrategy"); + localOptions.put("sstable_size_in_mb","1234"); // not for STCS + getCurrentColumnFamilyStore().setLocalCompactionStrategy(localOptions); + } + + public boolean verifyStrategies(WrappingCompactionStrategy wrappingStrategy, Class<? extends AbstractCompactionStrategy> expected) + { + boolean found = false; + for (AbstractCompactionStrategy actualStrategy : wrappingStrategy.getWrappedStrategies()) + { + if (!actualStrategy.getClass().equals(expected)) + return false; + found = true; + } + return found; + } + private ColumnFamilyStore getCurrentColumnFamilyStore() { return Keyspace.open(KEYSPACE).getColumnFamilyStore(currentTable()); } - public boolean minorWasTriggered(String keyspace, String cf) throws Throwable + private boolean minorWasTriggered(String keyspace, String cf) throws Throwable { UntypedResultSet res = execute("SELECT * FROM system.compaction_history"); boolean minorWasTriggered = false;