AMBARI-3811 - API performance issue on large cluster
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/query/QueryImpl.java b/ambari-server/src/main/java/org/apache/ambari/server/api/query/QueryImpl.java
index 89513fa..e838375 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/api/query/QueryImpl.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/query/QueryImpl.java
@@ -23,7 +23,6 @@
import org.apache.ambari.server.api.resources.ResourceInstanceFactoryImpl;
import org.apache.ambari.server.api.resources.SubResourceDefinition;
import org.apache.ambari.server.api.services.ResultImpl;
-import org.apache.ambari.server.controller.predicate.OrPredicate;
import org.apache.ambari.server.controller.utilities.PropertyHelper;
import org.apache.ambari.server.controller.predicate.AndPredicate;
import org.apache.ambari.server.controller.predicate.EqualsPredicate;
@@ -67,9 +66,9 @@
private final Map<Resource.Type, String> keyValueMap = new HashMap<Resource.Type, String>();
/**
- * Set of maps of primary and foreign key values.
+ * Set of query results.
*/
- Set<Map<Resource.Type, String>> keyValueMaps = new HashSet<Map<Resource.Type, String>>();
+ Set<QueryResult> queryResults = new LinkedHashSet<QueryResult>();
/**
* Sub-resources of the resource which is being operated on.
@@ -98,11 +97,6 @@
private PageRequest pageRequest;
/**
- * Query resources.
- */
- private Set<Resource> providerResourceSet;
-
- /**
* The logger.
*/
private final static Logger LOG =
@@ -303,14 +297,21 @@
NoSuchResourceException,
NoSuchParentResourceException {
- providerResourceSet = new LinkedHashSet<Resource>();
+ Set<Resource> providerResourceSet = new LinkedHashSet<Resource>();
- // save the top level resources
- for (Resource resource : doQuery(getPredicate())) {
- providerResourceSet.add(resource);
+ Resource.Type resourceType = getResourceDefinition().getType();
+ Request request = createRequest();
+ Predicate predicate = getPredicate();
+
+ Set<Resource> resourceSet = new LinkedHashSet<Resource>();
+
+ for (Resource queryResource : doQuery(resourceType, request, predicate)) {
+ providerResourceSet.add(queryResource);
+ resourceSet.add(queryResource);
}
- keyValueMaps.add(getKeyValueMap());
+ queryResults.add(new QueryResult(request, predicate, getKeyValueMap(), resourceSet));
+ clusterController.populateResources(resourceType, providerResourceSet, request, predicate);
queryForSubResources();
}
@@ -325,17 +326,31 @@
NoSuchResourceException,
NoSuchParentResourceException {
- // get predicates for all of the sub resource types
- Map<String, Predicate> predicateMap = getSubResourcePredicates(providerResourceSet);
-
for (Map.Entry<String, QueryImpl> entry : querySubResourceSet.entrySet()) {
- QueryImpl subResource = entry.getValue();
- subResource.providerResourceSet = new LinkedHashSet<Resource>();
+ QueryImpl subResource = entry.getValue();
+ Resource.Type resourceType = subResource.getResourceDefinition().getType();
+ Request request = subResource.createRequest();
- for (Resource resource : subResource.doQuery(predicateMap.get(entry.getKey()))) {
- subResource.providerResourceSet.add(resource);
+ Set<Resource> providerResourceSet = new LinkedHashSet<Resource>();
+
+ for (QueryResult queryResult : queryResults) {
+ for (Resource resource : queryResult.getProviderResourceSet()) {
+
+ Map<Resource.Type, String> map = getKeyValueMap(resource, queryResult.getKeyValueMap());
+
+ Predicate predicate = subResource.createPredicate(map);
+
+ Set<Resource> resourceSet = new LinkedHashSet<Resource>();
+
+ for (Resource queryResource : subResource.doQuery(resourceType, request, predicate)) {
+ providerResourceSet.add(queryResource);
+ resourceSet.add(queryResource);
+ }
+ subResource.queryResults.add(new QueryResult(request, predicate, map, resourceSet));
+ }
}
+ clusterController.populateResources(resourceType, providerResourceSet, request, null);
subResource.queryForSubResources();
}
}
@@ -343,59 +358,24 @@
/**
* Query the cluster controller for the resources.
*/
- private Set<Resource> doQuery(Predicate predicate)
+ private Set<Resource> doQuery(Resource.Type type, Request request, Predicate predicate)
throws UnsupportedPropertyException,
SystemException,
NoSuchResourceException,
NoSuchParentResourceException {
- Resource.Type resourceType1 = getResourceDefinition().getType();
-
- if (getKeyValueMap().get(resourceType1) == null) {
- addCollectionProperties(resourceType1);
+ if (getKeyValueMap().get(type) == null) {
+ addCollectionProperties(type);
}
if (queryPropertySet.isEmpty() && querySubResourceSet.isEmpty()) {
//Add sub resource properties for default case where no fields are specified.
querySubResourceSet.putAll(ensureSubResources());
}
- Resource.Type resourceType = getResourceDefinition().getType();
- Request request = createRequest();
-
if (LOG.isDebugEnabled()) {
LOG.debug("Executing resource query: " + request + " where " + predicate);
}
- return clusterController.getResources(resourceType, request, predicate);
- }
-
- /**
- * Get a map of predicates for the given resource's sub-resources keyed
- * by resource type. Each predicate is a combined predicate of all
- * the sub resource predicates for a given type OR'd together. This
- * allows for all of the sub-resources of a given type to be
- * acquired in a single query.
- */
- private Map<String, Predicate> getSubResourcePredicates(Set<Resource> resources) {
- Map<String, Predicate> predicateMap = new HashMap<String, Predicate>();
-
- for (Resource resource : resources) {
- for (Map.Entry<String, QueryImpl> entry : querySubResourceSet.entrySet()) {
- QueryImpl subResourceInstance = entry.getValue();
- String subResCategory = entry.getKey();
-
- Set<Map<Resource.Type, String>> resourceKeyValueMaps = getKeyValueMaps(resource, keyValueMaps);
-
- for( Map<Resource.Type, String> map : resourceKeyValueMaps) {
- Predicate predicate = predicateMap.get(subResCategory);
-
- predicateMap.put(subResCategory, predicate == null ?
- subResourceInstance.createPredicate(map) :
- new OrPredicate(predicate, subResourceInstance.createPredicate(map)));
- }
- subResourceInstance.keyValueMaps.addAll(resourceKeyValueMaps);
- }
- }
- return predicateMap;
+ return clusterController.getResources(type, request, predicate);
}
/**
@@ -406,40 +386,44 @@
Result result = new ResultImpl(true);
Resource.Type resourceType = getResourceDefinition().getType();
- if (getKeyValueMap().get(resourceType) == null) {
- result.getResultTree().setProperty("isCollection", "true");
- }
-
- Predicate predicate = createPredicate();
- Request request = createRequest();
-
- Iterable<Resource> iterResource;
-
- if (pageRequest == null) {
- iterResource = clusterController.getIterable(
- resourceType, providerResourceSet, request, predicate);
- } else {
- PageResponse pageResponse = clusterController.getPage(
- resourceType, providerResourceSet, request, predicate, pageRequest);
- iterResource = pageResponse.getIterable();
- }
-
TreeNode<Resource> tree = result.getResultTree();
- int count = 1;
- for (Resource resource : iterResource) {
- // add a child node for the resource and provide a unique name. The name is never used.
- TreeNode<Resource> node = tree.addChild(resource, resource.getType() + ":" + count++);
- for (Map.Entry<String, QueryImpl> entry : querySubResourceSet.entrySet()) {
- String subResCategory = entry.getKey();
- QueryImpl subResource = entry.getValue();
+ if (isCollectionResource()) {
+ tree.setProperty("isCollection", "true");
+ }
- subResource.setKeyValueMap(getKeyValueMap(resource, getKeyValueMap()));
+ for (QueryResult queryResult : queryResults) {
+ Predicate predicate = queryResult.getPredicate();
+ Request request = queryResult.getRequest();
- TreeNode<Resource> childResult = subResource.getResult().getResultTree();
- childResult.setName(subResCategory);
- childResult.setProperty("isCollection", "false");
- node.addChild(childResult);
+ Iterable<Resource> iterResource;
+
+ Set<Resource> providerResourceSet = queryResult.getProviderResourceSet();
+
+ if (pageRequest == null) {
+ iterResource = clusterController.getIterable(
+ resourceType, providerResourceSet, request, predicate);
+ } else {
+ PageResponse pageResponse = clusterController.getPage(
+ resourceType, providerResourceSet, request, predicate, pageRequest);
+ iterResource = pageResponse.getIterable();
+ }
+
+ int count = 1;
+ for (Resource resource : iterResource) {
+ // add a child node for the resource and provide a unique name. The name is never used.
+ TreeNode<Resource> node = tree.addChild(resource, resource.getType() + ":" + count++);
+ for (Map.Entry<String, QueryImpl> entry : querySubResourceSet.entrySet()) {
+ String subResCategory = entry.getKey();
+ QueryImpl subResource = entry.getValue();
+
+ subResource.setKeyValueMap(getKeyValueMap(resource, getKeyValueMap()));
+
+ TreeNode<Resource> childResult = subResource.getResult().getResultTree();
+ childResult.setName(subResCategory);
+ childResult.setProperty("isCollection", "false");
+ node.addChild(childResult);
+ }
}
}
return result;
@@ -567,18 +551,6 @@
Collections.<String>emptySet() : setProperties, mapTemporalInfo);
}
- // Get a set of key value maps based on the given resource and an existing set of key value maps
- private Set<Map<Resource.Type, String>> getKeyValueMaps(Resource resource,
- Set<Map<Resource.Type, String>> keyValueMaps) {
- Set<Map<Resource.Type, String>> resourceKeyValueMaps = new HashSet<Map<Resource.Type, String>>();
-
- for(Map<Resource.Type, String> keyValueMap : keyValueMaps) {
- Map<Resource.Type, String> resourceKeyValueMap = getKeyValueMap(resource, keyValueMap);
- resourceKeyValueMaps.add(resourceKeyValueMap);
- }
- return resourceKeyValueMaps;
- }
-
// Get a key value map based on the given resource and an existing key value map
private Map<Resource.Type, String> getKeyValueMap(Resource resource,
Map<Resource.Type, String> keyValueMap) {
@@ -601,4 +573,45 @@
resourceKeyValueMap.put(resource.getType(), resource.getPropertyValue(resourceKeyProp).toString());
return resourceKeyValueMap;
}
+
+ // ----- inner class : QueryResult -----------------------------------------
+
+ /**
+ * Maintain information about an individual query and its result.
+ */
+ private static class QueryResult {
+ private final Request request;
+ private final Predicate predicate;
+ private final Map<Resource.Type, String> keyValueMap;
+ private final Set<Resource> providerResourceSet;
+
+ // ----- Constructor -----------------------------------------------------
+
+ private QueryResult(Request request, Predicate predicate,
+ Map<Resource.Type, String> keyValueMap,
+ Set<Resource> providerResourceSet) {
+ this.request = request;
+ this.predicate = predicate;
+ this.keyValueMap = keyValueMap;
+ this.providerResourceSet = providerResourceSet;
+ }
+
+ // ----- accessors -------------------------------------------------------
+
+ public Request getRequest() {
+ return request;
+ }
+
+ public Predicate getPredicate() {
+ return predicate;
+ }
+
+ public Map<Resource.Type, String> getKeyValueMap() {
+ return keyValueMap;
+ }
+
+ public Set<Resource> getProviderResourceSet() {
+ return providerResourceSet;
+ }
+ }
}
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ClusterControllerImpl.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ClusterControllerImpl.java
index 1a9079f..4f1751d 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ClusterControllerImpl.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ClusterControllerImpl.java
@@ -113,21 +113,26 @@
// get the resources
resources = provider.getResources(request, predicate);
-
- // populate the resources with metrics and properties.
- populateResources(type, resources, request, predicate);
-
- // filter the fully populated resources with the given predicate
- Iterable<Resource> iterable = getIterable(type, resources, request, predicate);
- resources = new LinkedHashSet<Resource>();
- for (Resource resource : iterable){
- resources.add(resource);
- }
}
return resources;
}
@Override
+ public Set<Resource> populateResources(Resource.Type type,
+ Set<Resource> resources,
+ Request request,
+ Predicate predicate) throws SystemException {
+ Set<Resource> keepers = resources;
+
+ for (PropertyProvider propertyProvider : propertyProviders.get(type)) {
+ if (providesRequestProperties(propertyProvider, request, predicate)) {
+ keepers = propertyProvider.populateResources(keepers, request, predicate);
+ }
+ }
+ return keepers;
+ }
+
+ @Override
public Iterable<Resource> getIterable(Resource.Type type, Set<Resource> providerResources,
Request request, Predicate predicate)
throws NoSuchParentResourceException, UnsupportedPropertyException, NoSuchResourceException, SystemException {
@@ -279,7 +284,8 @@
SystemException,
NoSuchParentResourceException,
NoSuchResourceException {
- return getResources(type, request, predicate, null).getIterable();
+ PageResponse resources = getResources(type, request, predicate, null);
+ return resources.getIterable();
}
/**
@@ -415,34 +421,6 @@
}
/**
- * Populate the given resources from the associated property providers. This
- * method may filter the resources based on the predicate and return a subset
- * of the given resources.
- *
- * @param type the resource type
- * @param resources the resources to be populated
- * @param request the request
- * @param predicate the predicate
- *
- * @return the set of resources that were successfully populated
- *
- * @throws SystemException if unable to populate the resources
- */
- protected Set<Resource> populateResources(Resource.Type type,
- Set<Resource> resources,
- Request request,
- Predicate predicate) throws SystemException {
- Set<Resource> keepers = resources;
-
- for (PropertyProvider propertyProvider : propertyProviders.get(type)) {
- if (providesRequestProperties(propertyProvider, request, predicate)) {
- keepers = propertyProvider.populateResources(keepers, request, predicate);
- }
- }
- return keepers;
- }
-
- /**
* Indicates whether or not the given property provider can service the given request.
*
* @param provider the property provider
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/spi/ClusterController.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/spi/ClusterController.java
index 0ab15db..c50ff7e 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/spi/ClusterController.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/spi/ClusterController.java
@@ -52,6 +52,25 @@
SystemException;
/**
+ * Populate the given resources from the associated property providers. This
+ * method may filter the resources based on the predicate and return a subset
+ * of the given resources.
+ *
+ * @param type the resource type
+ * @param resources the resources to be populated
+ * @param request the request
+ * @param predicate the predicate
+ *
+ * @return the set of resources that were successfully populated
+ *
+ * @throws SystemException if unable to populate the resources
+ */
+ public Set<Resource> populateResources(Resource.Type type,
+ Set<Resource> resources,
+ Request request,
+ Predicate predicate) throws SystemException;
+
+ /**
* Get an iterable set of resources from the given set of resources filtered by the
* given request and predicate objects.
*