You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ambari.apache.org by sr...@apache.org on 2015/09/10 01:41:54 UTC

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

Repository: ambari
Updated Branches:
  refs/heads/branch-2.1 59371e6cf -> 34180fb27


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/34180fb2
Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/34180fb2
Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/34180fb2

Branch: refs/heads/branch-2.1
Commit: 34180fb27851df7d84e682877ef2291ae452b57d
Parents: 59371e6
Author: Srimanth Gunturi <sg...@hortonworks.com>
Authored: Tue Sep 8 11:21:56 2015 -0700
Committer: Srimanth Gunturi <sg...@hortonworks.com>
Committed: Wed Sep 9 16:41:37 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/34180fb2/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/34180fb2/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/34180fb2/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/34180fb2/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());