Repository: ambari
Updated Branches:
  refs/heads/trunk 26b093a1a -> b47318902


AMBARI-13035. BE / Hosts Page Performance: alerts_summary takes too long to 
load (srimanth)


Project: http://git-wip-us.apache.org/repos/asf/ambari/repo
Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/b4731890
Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/b4731890
Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/b4731890

Branch: refs/heads/trunk
Commit: b4731890272e216ab327656101ec26e051d6b9f8
Parents: 26b093a
Author: Srimanth Gunturi <sgunt...@hortonworks.com>
Authored: Tue Sep 8 11:21:56 2015 -0700
Committer: Srimanth Gunturi <sgunt...@hortonworks.com>
Committed: Wed Sep 9 16:42:33 2015 -0700

----------------------------------------------------------------------
 .../internal/AlertSummaryPropertyProvider.java  | 57 ++++++++++++--
 .../apache/ambari/server/orm/dao/AlertsDAO.java | 41 ++++++++++
 .../server/orm/dao/HostAlertSummaryDTO.java     | 63 +++++++++++++++
 .../ambari/server/orm/dao/AlertsDAOTest.java    | 81 ++++++++++++++++++++
 4 files changed, 237 insertions(+), 5 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/b4731890/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AlertSummaryPropertyProvider.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AlertSummaryPropertyProvider.java
 
b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AlertSummaryPropertyProvider.java
index 2e8cf83..5c6bc85 100644
--- 
a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AlertSummaryPropertyProvider.java
+++ 
b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AlertSummaryPropertyProvider.java
@@ -89,22 +89,60 @@ public class AlertSummaryPropertyProvider extends 
BaseProvider implements Proper
   @Override
   public Set<Resource> populateResources(Set<Resource> resources,
       Request request, Predicate predicate) throws SystemException {
-
     Set<String> propertyIds = getRequestPropertyIds(request, predicate);
 
     try {
+      // Optimization:
+      // Some information can be determined more efficiently when requested in 
bulk 
+      // for an entire cluster at once. 
+      // For Example:
+      //   (1) Cluster level alert-status counts
+      //   (2) Per host alert-status counts
+      // These can be determined in 1 SQL call per cluster, and results used 
multiple times.
+      Map<Long, Map<String, AlertSummaryDTO>> perHostSummaryMap = new 
HashMap<Long, Map<String, AlertSummaryDTO>>();
+      Map<Long, AlertHostSummaryDTO> hostsSummaryMap = new HashMap<Long, 
AlertHostSummaryDTO>();
+      Map<String, Cluster> resourcesClusterMap = new HashMap<String, 
Cluster>();
+      for (Resource res : resources) {
+        String clusterName = (String) 
res.getPropertyValue(m_clusterPropertyId);
+        if (clusterName == null || 
resourcesClusterMap.containsKey(clusterName)) {
+          continue;
+        }
+        Cluster cluster = s_clusters.get().getCluster(clusterName);
+        resourcesClusterMap.put(clusterName, cluster);
+      }
+      for (Cluster cluster : resourcesClusterMap.values()) {
+        long clusterId = cluster.getClusterId();
+        switch (m_resourceType.getInternalType()) {
+          case Cluster:
+            // only make the calculation if asked
+            if (BaseProvider.isPropertyRequested(ALERTS_SUMMARY_HOSTS, 
propertyIds)) {
+              hostsSummaryMap.put(clusterId, 
s_dao.findCurrentHostCounts(clusterId));
+            }
+            break;
+          case Host:
+            if (resources.size() > 1) {
+              // More efficient to get information for all hosts in 1 call
+              Map<String, AlertSummaryDTO> perHostCounts = 
s_dao.findCurrentPerHostCounts(clusterId);
+              perHostSummaryMap.put(clusterId, perHostCounts);
+            }
+            break;
+          default:
+            break;
+        }
+      }
+
       for (Resource res : resources) {
-        populateResource(res, propertyIds);
+        populateResource(res, propertyIds, perHostSummaryMap, hostsSummaryMap);
       }
     } catch (AmbariException e) {
       LOG.error("Could not load built-in alerts - Executor exception ({})",
           e.getMessage());
     }
-
     return resources;
   }
 
-  private void populateResource(Resource resource, Set<String> requestedIds) 
throws AmbariException {
+  private void populateResource(Resource resource, Set<String> requestedIds, 
Map<Long, Map<String, 
+      AlertSummaryDTO>> perHostSummaryMap, Map<Long, AlertHostSummaryDTO> 
hostsSummaryMap) throws AmbariException {
 
     AlertSummaryDTO summary = null;
     AlertHostSummaryDTO hostSummary = null;
@@ -130,7 +168,11 @@ public class AlertSummaryPropertyProvider extends 
BaseProvider implements Proper
         // only make the calculation if asked
         if (BaseProvider.isPropertyRequested(ALERTS_SUMMARY_HOSTS,
             requestedIds)) {
-          hostSummary = s_dao.findCurrentHostCounts(clusterId);
+          if (hostsSummaryMap.containsKey(cluster.getClusterId())) {
+            hostSummary = hostsSummaryMap.get(cluster.getClusterId());
+          } else {
+            hostSummary = s_dao.findCurrentHostCounts(clusterId);
+          }
         }
 
         break;
@@ -138,7 +180,12 @@ public class AlertSummaryPropertyProvider extends 
BaseProvider implements Proper
         summary = s_dao.findCurrentCounts(cluster.getClusterId(), typeId, 
null);
         break;
       case Host:
+      if (perHostSummaryMap.containsKey(cluster.getClusterId()) && 
+          perHostSummaryMap.get(cluster.getClusterId()).containsKey(typeId)) {
+        summary = perHostSummaryMap.get(cluster.getClusterId()).get(typeId);
+      } else {
         summary = s_dao.findCurrentCounts(cluster.getClusterId(), null, 
typeId);
+      }
         break;
       default:
         break;

http://git-wip-us.apache.org/repos/asf/ambari/blob/b4731890/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/AlertsDAO.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/AlertsDAO.java 
b/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/AlertsDAO.java
index adcc710..73ca637 100644
--- 
a/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/AlertsDAO.java
+++ 
b/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/AlertsDAO.java
@@ -20,6 +20,7 @@ package org.apache.ambari.server.orm.dao;
 import java.util.Collections;
 import java.util.Date;
 import java.util.EnumSet;
+import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 
@@ -86,6 +87,15 @@ public class AlertsDAO {
       + "SUM(CASE WHEN alert.maintenanceState != :maintenanceStateOff THEN 1 
ELSE 0 END)) "
       + "FROM AlertCurrentEntity alert JOIN alert.alertHistory history WHERE 
history.clusterId = :clusterId";
 
+  private static final String ALERT_COUNT_PER_HOST_SQL_TEMPLATE = "SELECT NEW 
%s("
+      + "history.hostName, "
+      + "SUM(CASE WHEN history.alertState = :okState AND 
alert.maintenanceState = :maintenanceStateOff THEN 1 ELSE 0 END), "
+      + "SUM(CASE WHEN history.alertState = :warningState AND 
alert.maintenanceState = :maintenanceStateOff THEN 1 ELSE 0 END), "
+      + "SUM(CASE WHEN history.alertState = :criticalState AND 
alert.maintenanceState = :maintenanceStateOff THEN 1 ELSE 0 END), "
+      + "SUM(CASE WHEN history.alertState = :unknownState AND 
alert.maintenanceState = :maintenanceStateOff THEN 1 ELSE 0 END), "
+      + "SUM(CASE WHEN alert.maintenanceState != :maintenanceStateOff THEN 1 
ELSE 0 END)) "
+      + "FROM AlertCurrentEntity alert JOIN alert.alertHistory history WHERE 
history.clusterId = :clusterId GROUP BY history.hostName";
+
   /**
    * JPA entity manager
    */
@@ -445,6 +455,37 @@ public class AlertsDAO {
   }
 
   /**
+   * Retrieves the summary information for all the hosts in the provided 
cluster. 
+   * The result is mapping from hostname to summary DTO.
+   *
+   * @param clusterId
+   *          the cluster id
+   * @return map from hostnames to summary DTO
+   */
+  @RequiresSession
+  public Map<String, AlertSummaryDTO> findCurrentPerHostCounts(long clusterId) 
{
+    String sql = String.format(ALERT_COUNT_PER_HOST_SQL_TEMPLATE, 
HostAlertSummaryDTO.class.getName());
+
+    StringBuilder sb = new StringBuilder(sql);
+
+    TypedQuery<HostAlertSummaryDTO> query = 
m_entityManagerProvider.get().createQuery(sb.toString(), 
HostAlertSummaryDTO.class);
+
+    query.setParameter("clusterId", Long.valueOf(clusterId));
+    query.setParameter("okState", AlertState.OK);
+    query.setParameter("warningState", AlertState.WARNING);
+    query.setParameter("criticalState", AlertState.CRITICAL);
+    query.setParameter("unknownState", AlertState.UNKNOWN);
+    query.setParameter("maintenanceStateOff", MaintenanceState.OFF);
+
+    Map<String, AlertSummaryDTO> map = new HashMap<String, AlertSummaryDTO>();
+    List<HostAlertSummaryDTO> resultList = m_daoUtils.selectList(query);
+    for (HostAlertSummaryDTO result : resultList) {
+      map.put(result.getHostName(), result);
+    }
+    return map;
+  }
+
+  /**
    * Retrieve the summary alert information for all hosts. This is different
    * from {@link #findCurrentCounts(long, String, String)} since this will
    * return only alerts related to hosts and those values will be the total

http://git-wip-us.apache.org/repos/asf/ambari/blob/b4731890/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/HostAlertSummaryDTO.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/HostAlertSummaryDTO.java
 
b/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/HostAlertSummaryDTO.java
new file mode 100644
index 0000000..4f9fe66
--- /dev/null
+++ 
b/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/HostAlertSummaryDTO.java
@@ -0,0 +1,63 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ambari.server.orm.dao;
+
+/**
+ * Used when getting per host alert summary in bulk where a single database 
call will 
+ * return alert summaries for multiple hosts. In addition to the information
+ * returned by {@link AlertSummaryDTO}, a host name is provided.
+ */
+public class HostAlertSummaryDTO extends AlertSummaryDTO {
+
+  private String hostName;
+
+  /**
+   * Constructor, used by JPA. JPA invokes this constructor, even if there are 
no 
+   * records in the resultset. In that case, all arguments are {@code null}.
+   * 
+   * @param hostName
+   * @param ok
+   * @param warning
+   * @param critical
+   * @param unknown
+   * @param maintenance
+   */
+  public HostAlertSummaryDTO(String hostName, Number ok, Number warning, 
Number critical, Number unknown, Number maintenance) {
+    super(ok, warning, critical, unknown, maintenance);
+    this.setHostName(hostName);
+  }
+
+  /**
+   * Provide host name for this alerts summary
+   * 
+   * @return
+   */
+  public String getHostName() {
+    return hostName;
+  }
+
+  /**
+   * Set host name for this alerts summary
+   * 
+   * @param hostName
+   */
+  public void setHostName(String hostName) {
+    this.hostName = hostName;
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b4731890/ambari-server/src/test/java/org/apache/ambari/server/orm/dao/AlertsDAOTest.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/test/java/org/apache/ambari/server/orm/dao/AlertsDAOTest.java
 
b/ambari-server/src/test/java/org/apache/ambari/server/orm/dao/AlertsDAOTest.java
index f267544..0bbe998 100644
--- 
a/ambari-server/src/test/java/org/apache/ambari/server/orm/dao/AlertsDAOTest.java
+++ 
b/ambari-server/src/test/java/org/apache/ambari/server/orm/dao/AlertsDAOTest.java
@@ -29,6 +29,7 @@ import java.util.Calendar;
 import java.util.Collections;
 import java.util.Date;
 import java.util.List;
+import java.util.Map;
 import java.util.TimeZone;
 import java.util.UUID;
 
@@ -653,6 +654,86 @@ public class AlertsDAOTest {
    *
    */
   @Test
+  public void testFindCurrentPerHostSummary() throws Exception {
+    // Add extra host and alerts
+    m_helper.addHost(m_clusters, m_cluster, "h2");
+    List<AlertDefinitionEntity> definitions = m_definitionDao.findAll();
+    AlertDefinitionEntity definition = definitions.get(0);
+    AlertHistoryEntity h2CriticalHistory = new AlertHistoryEntity();
+    h2CriticalHistory.setServiceName(definition.getServiceName());
+    h2CriticalHistory.setClusterId(m_cluster.getClusterId());
+    h2CriticalHistory.setAlertDefinition(definition);
+    h2CriticalHistory.setAlertLabel(definition.getDefinitionName() + " h2");
+    h2CriticalHistory.setAlertText(definition.getDefinitionName() + " h2");
+    h2CriticalHistory.setAlertTimestamp(calendar.getTimeInMillis());
+    h2CriticalHistory.setComponentName(definition.getComponentName());
+    h2CriticalHistory.setHostName("h2");
+    h2CriticalHistory.setAlertState(AlertState.CRITICAL);
+    m_dao.create(h2CriticalHistory);
+    AlertCurrentEntity h2CriticalCurrent = new AlertCurrentEntity();
+    h2CriticalCurrent.setAlertHistory(h2CriticalHistory);
+    h2CriticalCurrent.setLatestTimestamp(new Date().getTime());
+    h2CriticalCurrent.setOriginalTimestamp(new Date().getTime() - 10800000);
+    h2CriticalCurrent.setMaintenanceState(MaintenanceState.OFF);
+    m_dao.create(h2CriticalCurrent);
+
+    try {
+      long clusterId = m_cluster.getClusterId();
+      AlertSummaryDTO summary = m_dao.findCurrentCounts(clusterId, null, null);
+      assertEquals(5, summary.getOkCount());
+
+      AlertHistoryEntity h1 = 
m_dao.findCurrentByCluster(clusterId).get(2).getAlertHistory();
+      AlertHistoryEntity h2 = 
m_dao.findCurrentByCluster(clusterId).get(3).getAlertHistory();
+      AlertHistoryEntity h3 = 
m_dao.findCurrentByCluster(clusterId).get(4).getAlertHistory();
+
+      h1.setAlertState(AlertState.WARNING);
+      m_dao.merge(h1);
+      h2.setAlertState(AlertState.CRITICAL);
+      m_dao.merge(h2);
+      h3.setAlertState(AlertState.UNKNOWN);
+      m_dao.merge(h3);
+
+      Map<String, AlertSummaryDTO> perHostSummary = 
m_dao.findCurrentPerHostCounts(clusterId);
+
+      AlertSummaryDTO h1summary = m_dao.findCurrentCounts(clusterId, null, 
"h1");
+      assertEquals(2, h1summary.getOkCount());
+      assertEquals(1, h1summary.getWarningCount());
+      assertEquals(1, h1summary.getCriticalCount());
+      assertEquals(1, h1summary.getUnknownCount());
+      assertEquals(0, h1summary.getMaintenanceCount());
+
+      AlertSummaryDTO h2summary = m_dao.findCurrentCounts(clusterId, null, 
"h2");
+      assertEquals(0, h2summary.getOkCount());
+      assertEquals(0, h2summary.getWarningCount());
+      assertEquals(1, h2summary.getCriticalCount());
+      assertEquals(0, h2summary.getUnknownCount());
+      assertEquals(0, h2summary.getMaintenanceCount());
+
+      AlertSummaryDTO h1PerHostSummary = perHostSummary.get("h1");
+      assertEquals(h1PerHostSummary.getOkCount(), h1summary.getOkCount());
+      assertEquals(h1PerHostSummary.getWarningCount(), 
h1summary.getWarningCount());
+      assertEquals(h1PerHostSummary.getCriticalCount(), 
h1summary.getCriticalCount());
+      assertEquals(h1PerHostSummary.getUnknownCount(), 
h1summary.getUnknownCount());
+      assertEquals(h1PerHostSummary.getMaintenanceCount(), 
h1summary.getMaintenanceCount());
+
+      AlertSummaryDTO h2PerHostSummary = perHostSummary.get("h2");
+      assertEquals(h2PerHostSummary.getOkCount(), h2summary.getOkCount());
+      assertEquals(h2PerHostSummary.getWarningCount(), 
h2summary.getWarningCount());
+      assertEquals(h2PerHostSummary.getCriticalCount(), 
h2summary.getCriticalCount());
+      assertEquals(h2PerHostSummary.getUnknownCount(), 
h2summary.getUnknownCount());
+      assertEquals(h2PerHostSummary.getMaintenanceCount(), 
h2summary.getMaintenanceCount());
+    } finally {
+      // Cleanup extra host and alerts to not effect other tests
+      m_dao.remove(h2CriticalCurrent);
+      m_dao.remove(h2CriticalHistory);
+      m_clusters.unmapHostFromCluster("h2", m_cluster.getClusterName());
+    }
+  }
+
+  /**
+   *
+   */
+  @Test
   public void testFindCurrentHostSummary() throws Exception {
     // start out with 1 since all alerts are for a single host and are OK
     AlertHostSummaryDTO summary = 
m_dao.findCurrentHostCounts(m_cluster.getClusterId());

Reply via email to