modules/plugins/cassandra/src/main/java/org/rhq/plugins/cassandra/ColumnFamilyComponent.java | 77 ++++++++++ modules/plugins/cassandra/src/main/java/org/rhq/plugins/cassandra/ColumnFamilyDiscoveryComponent.java | 1 modules/plugins/cassandra/src/main/java/org/rhq/plugins/cassandra/KeyspaceComponent.java | 8 - modules/plugins/cassandra/src/main/java/org/rhq/plugins/cassandra/StorageServiceComponent.java | 14 + modules/plugins/cassandra/src/main/resources/META-INF/rhq-plugin.xml | 64 ++++++++ 5 files changed, 159 insertions(+), 5 deletions(-)
New commits: commit 6b04d51ecdd81026b68eb9fb59ba4f6ae4b86a4a Author: John Sanda jsanda@redhat.com Date: Wed Sep 19 17:02:33 2012 -0400
Adding repair operation for StorageService type
The Cassandra docs recommend running repair as a routine maintenance operation. See http://wiki.apache.org/cassandra/Operations#Frequency_of_nodetool_repair for details. Interestingly the JMX operations for repair are exposed on the storage service mbean. The frequencey of how often it is run should be determined in part by the value of gc_grace_seconds which is specified at the column family level.
From a user standpoint, it will be somewhat difficult to determine that minimum frequency as it will require querying the gc_grace_seconds config property for each column family; however, that property will likely remain the same across column families. We could expose the repair operation at the column family level, using a safe default interval <= gc_grace_seconds. This could result in multiple repairs running simultaneously. I am not sure whether or not this would/could be problematic.
diff --git a/modules/plugins/cassandra/src/main/java/org/rhq/plugins/cassandra/StorageServiceComponent.java b/modules/plugins/cassandra/src/main/java/org/rhq/plugins/cassandra/StorageServiceComponent.java index bcc0cb1..b1e388f 100644 --- a/modules/plugins/cassandra/src/main/java/org/rhq/plugins/cassandra/StorageServiceComponent.java +++ b/modules/plugins/cassandra/src/main/java/org/rhq/plugins/cassandra/StorageServiceComponent.java @@ -99,6 +99,10 @@ public class StorageServiceComponent extends MBeanResourceComponent { return setLog4jLevel(parameters); }
+ if (name.equals("repair")) { + return runRepair(parameters); + } + return super.invokeOperation(name, parameters); }
@@ -126,6 +130,16 @@ public class StorageServiceComponent extends MBeanResourceComponent { return new OperationResult(); }
+ private OperationResult repair(Configuration params) { + String keyspace = params.getSimpleValue("keyspace"); + EmsBean emsBean = getEmsBean(); + EmsOperation operation = emsBean.getOperation("forceTableRepair", String.class, boolean.class, String[].class); + + operation.invoke(keyspace, true, new String[] {}); + + return new OperationResult(); + } + @Override public Configuration loadResourceConfiguration() { Configuration config = super.loadResourceConfiguration(); diff --git a/modules/plugins/cassandra/src/main/resources/META-INF/rhq-plugin.xml b/modules/plugins/cassandra/src/main/resources/META-INF/rhq-plugin.xml index 8463a82..9b520b7 100644 --- a/modules/plugins/cassandra/src/main/resources/META-INF/rhq-plugin.xml +++ b/modules/plugins/cassandra/src/main/resources/META-INF/rhq-plugin.xml @@ -5,6 +5,7 @@ code base of Cassandra which comes from the cassandra-1.1 branch of the Cassandra git repo. The plugin will not yet work with 1.2.x Cassandra builds which come out of its trunk (i.e., master) branch." package="org.rhq.plugins.cassandra" + version="5.0.3" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="urn:xmlns:rhq-plugin" xmlns:c="urn:xmlns:rhq-configuration"> @@ -164,6 +165,18 @@ </parameters> </operation>
+ <operation name="repair" + description="Cassandra compares data on this node with the versions on other replicas to update any + out of sync copies of the data. This should be run infrequently as it is a disk IO and CPU intensive + operation. All data for each column that is being repaired is read. Unless you are not performing any + deletes, it is important to run regularly scheduled repairs to ensure that deleted data gets purged. + The frequency that this should be run should be less than the gc_grace_period for each column family. + The current implementation runs repair on all column families in the specified keyspace."> + <parameters> + <c:simple-property name="keyspace" required="true" type="string"/> + </parameters> + </operation> + <metric property="Token" dataType="trait" description="A string representation of this node's token"
commit 5041207a37b3fb7e6f90d36a6d4ab524aa6ceefc Author: John Sanda jsanda@redhat.com Date: Wed Sep 19 15:26:44 2012 -0400
Adding initial implementation of ConfigurationFacet for ColumnFamilyComponent
There are a number of column family configuration options that are not exposed through JMX. All of the properties/options can be seen from the Cassandra CLI. This commit adds initial support for loading/viewing and updating those configuration settings.
diff --git a/modules/plugins/cassandra/src/main/java/org/rhq/plugins/cassandra/ColumnFamilyComponent.java b/modules/plugins/cassandra/src/main/java/org/rhq/plugins/cassandra/ColumnFamilyComponent.java index 3ec51bf..f3f085d 100644 --- a/modules/plugins/cassandra/src/main/java/org/rhq/plugins/cassandra/ColumnFamilyComponent.java +++ b/modules/plugins/cassandra/src/main/java/org/rhq/plugins/cassandra/ColumnFamilyComponent.java @@ -25,10 +25,87 @@
package org.rhq.plugins.cassandra;
+import static org.rhq.core.domain.configuration.ConfigurationUpdateStatus.FAILURE; +import static org.rhq.core.domain.configuration.ConfigurationUpdateStatus.SUCCESS; +import static org.rhq.plugins.cassandra.CassandraUtil.getCluster; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import org.rhq.core.domain.configuration.Configuration; +import org.rhq.core.domain.configuration.PropertySimple; +import org.rhq.core.pluginapi.configuration.ConfigurationUpdateReport; +import org.rhq.core.pluginapi.inventory.ResourceContext; import org.rhq.plugins.jmx.MBeanResourceComponent;
+import me.prettyprint.hector.api.Cluster; +import me.prettyprint.hector.api.ddl.ColumnFamilyDefinition; +import me.prettyprint.hector.api.exceptions.HectorException; + /** * @author John Sanda */ public class ColumnFamilyComponent extends MBeanResourceComponent { + + private Log log = LogFactory.getLog(ColumnFamilyComponent.class); + + @Override + public Configuration loadResourceConfiguration() { + if (log.isDebugEnabled()) { + ResourceContext context = getResourceContext(); + log.debug("Loading resource context for column family " + context.getResourceKey()); + } + + ColumnFamilyDefinition cfDef = getColumnFamilyDefinition(); + Configuration config = new Configuration(); + + config.put(new PropertySimple("gc_grace_seconds", cfDef.getGcGraceSeconds())); + + return config; + } + + @Override + public void updateResourceConfiguration(ConfigurationUpdateReport report) { + ResourceContext context = getResourceContext(); + + if (log.isDebugEnabled()) { + log.debug("Updating resource configuration for column family " + context.getResourceKey()); + } + + Cluster cluster = getCluster(); + ColumnFamilyDefinition cfDef = getColumnFamilyDefinition(); + Configuration updatedConfig = report.getConfiguration(); + + String gcGraceSeconds = updatedConfig.getSimpleValue("gc_grace_seconds", "864000"); + cfDef.setGcGraceSeconds(Integer.parseInt(gcGraceSeconds)); + + try { + cluster.updateColumnFamily(cfDef, true); + report.setStatus(SUCCESS); + } catch (HectorException e) { + String msg = "Failed to update resource configuration for column family " + context.getResourceKey(); + if (log.isDebugEnabled()) { + log.debug(msg, e); + } else if (log.isWarnEnabled()) { + log.warn(msg); + } + report.setErrorMessageFromThrowable(e); + report.setStatus(FAILURE); + } + } + + private ColumnFamilyDefinition getColumnFamilyDefinition() { + ResourceContext context = getResourceContext(); + Configuration pluginConfig = context.getPluginConfiguration(); + String cfName = pluginConfig.getSimpleValue("name"); + KeyspaceComponent keyspaceComponent = (KeyspaceComponent) context.getParentResourceComponent(); + + for (ColumnFamilyDefinition cfDef : keyspaceComponent.getKeyspaceDefinition().getCfDefs()) { + if (cfName.equals(cfDef.getName())) { + return cfDef; + } + } + + return null; + } } diff --git a/modules/plugins/cassandra/src/main/java/org/rhq/plugins/cassandra/ColumnFamilyDiscoveryComponent.java b/modules/plugins/cassandra/src/main/java/org/rhq/plugins/cassandra/ColumnFamilyDiscoveryComponent.java index d320f75..b63d2dc 100644 --- a/modules/plugins/cassandra/src/main/java/org/rhq/plugins/cassandra/ColumnFamilyDiscoveryComponent.java +++ b/modules/plugins/cassandra/src/main/java/org/rhq/plugins/cassandra/ColumnFamilyDiscoveryComponent.java @@ -57,6 +57,7 @@ public class ColumnFamilyDiscoveryComponent implements ResourceDiscoveryComponen pluginConfig.put(new PropertySimple("objectName", "org.apache.cassandra.db:type=ColumnFamilies,keyspace=" + keyspaceDef.getName() + ",columnfamily=" + columnFamilyDef.getName())); + pluginConfig.put(new PropertySimple("name", columnFamilyDef.getName())); details.add(new DiscoveredResourceDetails(context.getResourceType(), resourceKey, columnFamilyDef.getName(), null, null, pluginConfig, null)); } diff --git a/modules/plugins/cassandra/src/main/java/org/rhq/plugins/cassandra/KeyspaceComponent.java b/modules/plugins/cassandra/src/main/java/org/rhq/plugins/cassandra/KeyspaceComponent.java index d736669..17b7fd9 100644 --- a/modules/plugins/cassandra/src/main/java/org/rhq/plugins/cassandra/KeyspaceComponent.java +++ b/modules/plugins/cassandra/src/main/java/org/rhq/plugins/cassandra/KeyspaceComponent.java @@ -25,8 +25,6 @@
package org.rhq.plugins.cassandra;
-import static org.rhq.plugins.cassandra.CassandraUtil.getKeyspaceDefinition; - import java.util.Map;
import org.mc4j.ems.connection.EmsConnection; @@ -73,7 +71,7 @@ public class KeyspaceComponent implements ResourceComponent, ConfigurationFacet,
@Override public Configuration loadResourceConfiguration() throws Exception { - KeyspaceDefinition keyspaceDef = getKeyspaceDefinition(context.getResourceKey()); + KeyspaceDefinition keyspaceDef = getKeyspaceDefinition();
Configuration config = new Configuration(); config.put(new PropertySimple("name", keyspaceDef.getName())); @@ -94,6 +92,10 @@ public class KeyspaceComponent implements ResourceComponent, ConfigurationFacet, return config; }
+ public KeyspaceDefinition getKeyspaceDefinition() { + return CassandraUtil.getKeyspaceDefinition(context.getResourceKey()); + } + @Override public void updateResourceConfiguration(ConfigurationUpdateReport report) { } diff --git a/modules/plugins/cassandra/src/main/resources/META-INF/rhq-plugin.xml b/modules/plugins/cassandra/src/main/resources/META-INF/rhq-plugin.xml index 1ba9bfb..8463a82 100644 --- a/modules/plugins/cassandra/src/main/resources/META-INF/rhq-plugin.xml +++ b/modules/plugins/cassandra/src/main/resources/META-INF/rhq-plugin.xml @@ -5,7 +5,6 @@ code base of Cassandra which comes from the cassandra-1.1 branch of the Cassandra git repo. The plugin will not yet work with 1.2.x Cassandra builds which come out of its trunk (i.e., master) branch." package="org.rhq.plugins.cassandra" - version="5.0.2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="urn:xmlns:rhq-plugin" xmlns:c="urn:xmlns:rhq-configuration"> @@ -248,6 +247,7 @@ class="org.rhq.plugins.cassandra.ColumnFamilyComponent"> <plugin-configuration> <c:simple-property name="objectName" readOnly="true" type="string"/> + <c:simple-property name="name" type="string" description="The column family name"/> </plugin-configuration>
<metric property="TotalReadLatencyMicros" @@ -283,6 +283,18 @@ <metric property="TotalDiskSpaceUsed" measurementType="dynamic" displayType="summary"/> + + <resource-configuration> + <c:simple-property name="gc_grace_seconds" + displayName="gc_grace_seconds" + required="false" + default="864000" + type="integer" + description="Specifies the time to wait before garbage collecting tombstones (deletion + markers). The value, specified in seconds, defaults to 10 days and allows for a large + amount of time for consistency to be achived prior to deletion. In a single node cluster + this can be reduced to zero."/> + </resource-configuration> </service> </service> </server>
commit 0b688c9b5693d9710f4e237596d8a6f6de9d715c Author: John Sanda jsanda@redhat.com Date: Wed Sep 19 14:05:02 2012 -0400
Adding CommitLog resource type
Adding CommitLog type along with a few metrics for it. Also providing a more detailed description for the SchemaVersion trait which is managed by the StorageService type.
diff --git a/modules/plugins/cassandra/src/main/resources/META-INF/rhq-plugin.xml b/modules/plugins/cassandra/src/main/resources/META-INF/rhq-plugin.xml index 902bc49..1ba9bfb 100644 --- a/modules/plugins/cassandra/src/main/resources/META-INF/rhq-plugin.xml +++ b/modules/plugins/cassandra/src/main/resources/META-INF/rhq-plugin.xml @@ -5,6 +5,7 @@ code base of Cassandra which comes from the cassandra-1.1 branch of the Cassandra git repo. The plugin will not yet work with 1.2.x Cassandra builds which come out of its trunk (i.e., master) branch." package="org.rhq.plugins.cassandra" + version="5.0.2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="urn:xmlns:rhq-plugin" xmlns:c="urn:xmlns:rhq-configuration"> @@ -63,7 +64,8 @@
<metric property="cluster" dataType="trait" - description="The name of the cluster. This is used to prevent machines in one logical cluster from joining another."/> + description="The name of the cluster. This is used to prevent machines in one logical cluster from joining another." + displayType="summary"/>
<server name="Cassandra Server JVM" description="The JVM of the Cassandra node" @@ -163,12 +165,21 @@ </parameters> </operation>
+ <metric property="Token" + dataType="trait" + description="A string representation of this node's token" + defaultOn="true"/> + <metric property="ReleaseVersion" dataType="trait" description="The Cassandra version"/> <metric property="SchemaVersion" dataType="trait" - description="The current schema version"/> + description="The current schema version for this node. The value is calculated as a checksum of all rows + in the system.schema_* column families. This value is used in an algorithm to compare schema versions + between nodes and apply updates as necessary. This value should be the same for all fully initialized + nodes in the cluster." + displayType="summary"/> <metric property="ReleaseVersion" dataType="trait" description="The Cassandra version"/> @@ -192,6 +203,30 @@ </resource-configuration> </service>
+ <service name="CommitLog" + discovery="org.rhq.plugins.jmx.MBeanResourceDiscoveryComponent" + class="org.rhq.plugins.jmx.MBeanResourceComponent"> + <plugin-configuration> + <c:simple-property name="objectName" + readOnly="true" + type="string" + default="org.apache.cassandra.db:type=Commitlog"/> + </plugin-configuration> + + <metric property="TotalCommitLogSize" + measurementType="trendsup" + displayType="summary" + description="The size of all commit log segments"/> + <metric property="PendingTasks" + measurementType="dynamic" + displayType="detail" + description="The number of tasks waiting to be executed"/> + <metric property="CompletedTasks" + measurementType="trendsup" + displayType="detail" + description="The number of completed tasks"/> + </service> + <service name="Keyspace" discovery="org.rhq.plugins.cassandra.KeyspaceDiscoveryComponent" class="org.rhq.plugins.cassandra.KeyspaceComponent">