Skip to content
This repository has been archived by the owner on Jul 11, 2022. It is now read-only.

Commit

Permalink
Bug 1107858 - [AS7] Exception during discovery of Query Cache resourc…
Browse files Browse the repository at this point in the history
…es of RHQ Server resource

Instead of importing tons of Query Cache resources, AS7 plugin will mimic Hibernate Plugin's behavior and expose a "viewQueries" operation to gather the Query Cache nodes statistics.

Added HibernatePersistenceUnitComponent to implement "viewQueries" operation. The operation processes Query Cache nodes in batches to avoid sending too many queries to the management interface
Deleted the never used QueryCacheDiscovery class (updated API check file accordingly)
Removed the commented-out Query Cache service in AS7 plugin descriptor and added the "viewQueries" operation on the Hibernate Persistence Unit service
Added itest for the "viewQueries" operation

(cherry picked from commit a348010)

Conflicts:
	modules/plugins/jboss-as-7/intentional-api-changes-since-4.11.0.xml
	modules/plugins/jboss-as-7/src/main/resources/META-INF/rhq-plugin.xml
	modules/plugins/jboss-as-7/src/test/java/org/rhq/modules/plugins/jbossas7/itest/standalone/DeploymentRuntimeResourcesTest.java
  • Loading branch information
tsegismont committed Jun 16, 2014
1 parent db321cb commit 4929d13
Show file tree
Hide file tree
Showing 3 changed files with 249 additions and 25 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
/*
* RHQ Management Platform
* Copyright (C) 2005-2014 Red Hat, Inc.
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation version 2 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/

package org.rhq.modules.plugins.jbossas7;

import java.util.List;
import java.util.Map;

import org.rhq.core.domain.configuration.Configuration;
import org.rhq.core.domain.configuration.PropertyList;
import org.rhq.core.domain.configuration.PropertyMap;
import org.rhq.core.domain.configuration.PropertySimple;
import org.rhq.core.pluginapi.operation.OperationResult;
import org.rhq.modules.plugins.jbossas7.json.Address;
import org.rhq.modules.plugins.jbossas7.json.CompositeOperation;
import org.rhq.modules.plugins.jbossas7.json.ReadChildrenNames;
import org.rhq.modules.plugins.jbossas7.json.ReadResource;
import org.rhq.modules.plugins.jbossas7.json.Result;

/**
* @author Thomas Segismont
*/
public class HibernatePersistenceUnitComponent extends BaseComponent {
private static final String[] QUERY_CACHE_ATTRIBUTE_NAMES = new String[] { //
"query-name", //
"query-execution-count", //
"query-execution-row-count", //
"query-execution-min-time", //
"query-execution-max-time", //
"query-execution-average-time", //
"query-cache-hit-count", //
"query-cache-miss-count", //
"query-cache-put-count" //
};
private static final int BATCH_SIZE = 10;
private static final int MANAGEMENT_QUERY_TIMEOUT = 60;

@Override
public OperationResult invokeOperation(String name, Configuration parameters) throws Exception {
if ("viewQueries".equals(name)) {
return invokeViewQueriesOperation(parameters);
}
return super.invokeOperation(name, parameters);
}

private OperationResult invokeViewQueriesOperation(Configuration parameters) throws InterruptedException {
OperationResult operationResult = new OperationResult();

int batchSize;
PropertySimple batchSizeProp = parameters.getSimple("batchSize");
if (batchSizeProp == null || batchSizeProp.getStringValue() == null) {
batchSize = BATCH_SIZE;
} else {
try {
batchSize = Integer.parseInt(batchSizeProp.getStringValue());
if (batchSize < 1) {
operationResult.setErrorMessage("batchSize property is less than 1");
return operationResult;
}
} catch (NumberFormatException e) {
operationResult.setErrorMessage("batchSize property is not an integer");
return operationResult;
}
}

int timeoutSec;
PropertySimple managementQueryTimeoutProp = parameters.getSimple("managementQueryTimeout");
if (managementQueryTimeoutProp == null || managementQueryTimeoutProp.getStringValue() == null) {
timeoutSec = MANAGEMENT_QUERY_TIMEOUT;
} else {
try {
timeoutSec = Integer.parseInt(managementQueryTimeoutProp.getStringValue());
if (timeoutSec < 1) {
operationResult.setErrorMessage("managementQueryTimeout property is less than 1");
return operationResult;
}
} catch (NumberFormatException e) {
operationResult.setErrorMessage("managementQueryTimeout property is not an integer");
return operationResult;
}
}

PropertyList queriesPropertyList = new PropertyList("queries");
operationResult.getComplexResults().put(queriesPropertyList);

ReadChildrenNames readQueryCacheChildrenNames = new ReadChildrenNames(getAddress(), "query-cache");
Result readQueryCacheChildrenNamesResult = getASConnection().execute(readQueryCacheChildrenNames, timeoutSec);
if (!readQueryCacheChildrenNamesResult.isSuccess()) {
operationResult.setErrorMessage("Could not read query-cache children names: "
+ readQueryCacheChildrenNamesResult.getFailureDescription());
return operationResult;
}
@SuppressWarnings("unchecked")
List<String> childrenNames = (List<String>) readQueryCacheChildrenNamesResult.getResult();

// Process children in batches to avoid sending too many queries if the PU has many query-cache nodes
while (!childrenNames.isEmpty()) {
if (context.getComponentInvocationContext().isInterrupted()) {
// Operation canceled or timed out
throw new InterruptedException();
}

List<String> childrenNamesSubList = childrenNames.subList(0, Math.min(batchSize, childrenNames.size()));

// Create batch operation to read N query-cache nodes
CompositeOperation batchOperation = new CompositeOperation();
for (String childrenName : childrenNamesSubList) {
Address address = new Address(getAddress());
address.add("query-cache", childrenName);
ReadResource readQueryCacheResource = new ReadResource(address);
readQueryCacheResource.includeRuntime(true);
batchOperation.addStep(readQueryCacheResource);
}

// Execute batch
Result batchResult = getASConnection().execute(batchOperation, timeoutSec);
if (!batchResult.isSuccess()) {
operationResult.setErrorMessage("Could not read query-cache attributes: "
+ batchResult.getFailureDescription());
return operationResult;
}

// Iterate over batch results
@SuppressWarnings("unchecked")
Map<String, Map> mapResult = (Map<String, Map>) batchResult.getResult();
for (Map stepResult : mapResult.values()) {
PropertyMap queryPropertyMap = new PropertyMap("query");
@SuppressWarnings("unchecked")
Map<String, String> queryCacheAttributes = (Map<String, String>) stepResult.get("result");
for (String queryCacheAttributeName : QUERY_CACHE_ATTRIBUTE_NAMES) {
addAttributeToPropertyMap(queryCacheAttributeName, queryPropertyMap, queryCacheAttributes);
}
queriesPropertyList.add(queryPropertyMap);
}

childrenNamesSubList.clear();
}

return operationResult;
}

private void addAttributeToPropertyMap(String attributeName, PropertyMap propertyMap,
Map<String, String> queryCacheAttributes) {
propertyMap.put(new PropertySimple(attributeName, queryCacheAttributes.get(attributeName)));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10058,7 +10058,7 @@
</plugin-configuration>

<service name="Hibernate Persistence Unit"
class="BaseComponent"
class="HibernatePersistenceUnitComponent"
discovery="SubsystemDiscovery"
description="Runtime information about JPA use in the deployment."
singleton="true">
Expand All @@ -10085,6 +10085,46 @@
</results>
</operation>

<operation name="viewQueries" description="View statistical information about queries executed by Hibernate">
<parameters>
<c:simple-property name="batchSize" required="true" type="integer" default="10"
description="Sets the Query Cache resources read batch size. Defaults to 10.">
<c:constraint>
<c:integer-constraint minimum="1"/>
</c:constraint>
</c:simple-property>
<c:simple-property name="managementQueryTimeout" required="true" type="integer" default="60" units="seconds"
description="In seconds. Sets the connection read timeout for queries sent to the server management interface. Defaults to 60 seconds.">
<c:constraint>
<c:integer-constraint minimum="1"/>
</c:constraint>
</c:simple-property>
</parameters>
<results>
<c:list-property name="queries">
<c:map-property name="query">
<c:simple-property name="query-name" description="Query name."/>
<c:simple-property name="query-execution-count" type="long"
description="Get number of times query has been executed."/>
<c:simple-property name="query-execution-row-count" type="long"
description="Get number of rows returned from executions of query."/>
<c:simple-property name="query-execution-min-time" type="long"
description="Get the minimum time in milliseconds of the query."/>
<c:simple-property name="query-execution-max-time" type="long"
description="Get the time in milliseconds of the query."/>
<c:simple-property name="query-execution-average-time" type="long"
description="Get the average time in milliseconds of the query."/>
<c:simple-property name="query-cache-hit-count" type="long"
description="Get the number of times query was retrieved from cache."/>
<c:simple-property name="query-cache-miss-count" type="long"
description="Get the number of times query was not found in cache."/>
<c:simple-property name="query-cache-put-count" type="long"
description="Get the number of times query was put in cache."/>
</c:map-property>
</c:list-property>
</results>
</operation>

<metric property="close-statement-count" displayType="summary" measurementType="trendsup" description="Number of released prepared statements."/>
<metric property="collection-fetch-count" displayType="summary" measurementType="trendsup" description="Number of collections fetched."/>
<metric property="collection-load-count" displayType="summary" measurementType="trendsup" description="Number of collections loaded."/>
Expand Down Expand Up @@ -10134,26 +10174,6 @@
<metric property="put-count" description="Number of cacheable entities/collections put in the cache."/>
</service>

<!--<service name="Query Cache"-->
<!--class="BaseComponent"-->
<!--discovery="QueryCacheDiscovery"-->
<!--description="Statistics for individual queries."-->
<!--singleton="true">-->
<!--<plugin-configuration>-->
<!--<c:simple-property name="path" readOnly="true"/>-->
<!--</plugin-configuration>-->

<!--<metric property="query-cache-hit-count" displayType="summary" measurementType="trendsup" description="Get the number of times query was retrieved from cache."/>-->
<!--<metric property="query-cache-miss-count" displayType="summary" measurementType="trendsup" description="Get the number of times query was not found in cache."/>-->
<!--<metric property="query-cache-put-count" displayType="summary" measurementType="trendsup" description="Get the number of times query was put in cache."/>-->
<!--<metric property="query-execution-average-time" description="Get the average time in milliseconds of the query."/>-->
<!--<metric property="query-execution-count" displayType="summary" measurementType="trendsup" description="Get number of times query has been executed."/>-->
<!--<metric property="query-execution-max-time" description="Get the time in milliseconds of the query."/>-->
<!--<metric property="query-execution-min-time" description="Get the minimum time in milliseconds of the query."/>-->
<!--<metric property="query-execution-row-count" displayType="summary" measurementType="trendsup" description="Get number of rows returned from executions of query."/>-->
<!--<metric property="query-name" dataType="trait" description="Query name."/>-->
<!--</service>-->

<service name="Entity"
class="BaseComponent"
discovery="SubsystemDiscovery"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*
* RHQ Management Platform
* Copyright (C) 2005-2013 Red Hat, Inc.
* Copyright (C) 2005-2014 Red Hat, Inc.
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
Expand Down Expand Up @@ -28,15 +28,16 @@
import static org.rhq.modules.plugins.jbossas7.itest.standalone.DeploymentTest.getTestDeploymentPackageDetails;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertFalse;
import static org.testng.Assert.assertNotNull;
import static org.testng.Assert.assertNull;
import static org.testng.Assert.assertTrue;

import java.io.InputStream;
import java.io.OutputStream;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.mockito.Mockito;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
Expand All @@ -47,6 +48,9 @@
import org.rhq.core.clientapi.agent.inventory.CreateResourceResponse;
import org.rhq.core.clientapi.agent.inventory.DeleteResourceRequest;
import org.rhq.core.domain.configuration.Configuration;
import org.rhq.core.domain.configuration.Property;
import org.rhq.core.domain.configuration.PropertyList;
import org.rhq.core.domain.configuration.PropertyMap;
import org.rhq.core.domain.configuration.PropertySimple;
import org.rhq.core.domain.content.PackageDetailsKey;
import org.rhq.core.domain.content.transfer.ResourcePackageDetails;
Expand All @@ -57,6 +61,8 @@
import org.rhq.core.pc.inventory.ResourceContainer;
import org.rhq.core.pc.util.FacetLockType;
import org.rhq.core.pluginapi.measurement.MeasurementFacet;
import org.rhq.core.pluginapi.operation.OperationFacet;
import org.rhq.core.pluginapi.operation.OperationResult;
import org.rhq.modules.plugins.jbossas7.itest.AbstractJBossAS7PluginTest;
import org.rhq.test.arquillian.DiscoveredResources;
import org.rhq.test.arquillian.RunDiscovery;
Expand All @@ -69,7 +75,6 @@
*/
@Test(groups = { "integration", "pc", "standalone" }, singleThreaded = true)
public class DeploymentRuntimeResourcesTest extends AbstractJBossAS7PluginTest {
private static final Log LOG = LogFactory.getLog(DeploymentRuntimeResourcesTest.class);

private enum RuntimeServiceType {
DATASOURCES_RUNTIME("Datasources Runtime"), //
Expand Down Expand Up @@ -246,6 +251,33 @@ private Set<Resource> getChildResourcesOfType(final Resource parentResource, fin
return foundResources;
}

@Test(priority = 13)
public void testHibernatePersistenceUnitViewQueriesOperation() throws Exception {
Set<Resource> resources = getChildResourcesOfType(getDeploymentResource(),
RuntimeServiceType.HIBERNATE_PERSISTENCE_UNIT.getServiceTypeName());
for (Resource resource : resources) {
OperationFacet operationFacet = getOperationFacet(resource);
Configuration parameters = new Configuration();
parameters.setSimpleValue("batchSize", "50");
parameters.setSimpleValue("managementQueryTimeout", "180");
OperationResult operationResult = operationFacet.invokeOperation("viewQueries", parameters);
String errorMessage = operationResult.getErrorMessage();
assertNull(errorMessage, errorMessage);
Configuration complexResults = operationResult.getComplexResults();
assertNotNull(complexResults, "ComplexResults is null");
PropertyList queriesPropList = complexResults.getList("queries");
assertNotNull(queriesPropList, "queriesPropList is null");
List<Property> queriesList = queriesPropList.getList();
assertFalse(queriesList.isEmpty(), "queriesPropList is empty");
for (Property queryProperty : queriesList) {
assertTrue(queryProperty instanceof PropertyMap, "Not a PropertyMap: " + queryProperty);
PropertyMap queryPropertyMap = (PropertyMap) queryProperty;
assertTrue(queryPropertyMap.getMap().containsKey("query-name"),
"Map does not contain query-name attribute: " + queryPropertyMap.getMap());
}
}
}

@Test(priority = 99)
public void testUndeploy() throws Exception {
Resource deploymentResource = getDeploymentResource();
Expand All @@ -261,4 +293,14 @@ private Resource getDeploymentResource() {
.getResourceContainer(deploymentResources.iterator().next().getId()).getResource();
}

private OperationFacet getOperationFacet(Resource resource) {
ResourceContainer resourceContainer = pluginContainer.getInventoryManager().getResourceContainer(resource);
try {
return resourceContainer.createResourceComponentProxy(OperationFacet.class, FacetLockType.WRITE,
SECONDS.toMillis(5), false, false, false);
} catch (PluginContainerException e) {
return null;
}
}

}

0 comments on commit 4929d13

Please sign in to comment.