Browse Source

AMBARI-6260 Heatmaps is not usable on 2K-node cluster. (atkach)

atkach 11 năm trước cách đây
mục cha
commit
f2d759e05b

+ 7 - 2
ambari-web/app/controllers/main/charts/heatmap.js

@@ -131,8 +131,13 @@ App.MainChartsHeatmapController = Em.Controller.extend({
 
   loadMetrics: function () {
     var selectedMetric = this.get('selectedMetric');
-    if (selectedMetric) {
-      selectedMetric.refreshHostSlots();
+    var hostNames = [];
+
+    if (selectedMetric && this.get('racks').everyProperty('isLoaded', true)) {
+      this.get('racks').forEach(function (rack) {
+        hostNames = hostNames.concat(rack.hosts.mapProperty('hostName'));
+      });
+      selectedMetric.refreshHostSlots(hostNames);
     }
     this.set('inputMaximum', this.get('selectedMetric.maximumValue'));
   }.observes('selectedMetric'),

+ 3 - 2
ambari-web/app/controllers/main/charts/heatmap_metrics/heatmap_metric.js

@@ -239,7 +239,7 @@ App.MainChartHeatmapMetric = Em.Object.extend(heatmap.mappers, {
   hostToSlotMap: function(){
     var hostToValueMap = this.get('hostToValueMap');
     var slotDefs = this.get('slotDefinitions');
-    var hostNames = App.Host.find().mapProperty('hostName');
+    var hostNames = this.get('hostNames');
     var hostToSlotMap = {};
     if (hostToValueMap && hostNames) {
       hostNames.forEach(function(hostName){
@@ -276,8 +276,9 @@ App.MainChartHeatmapMetric = Em.Object.extend(heatmap.mappers, {
    * the callback's #map(hostnameToSlotObject) method. The
    * 'hostnameToSlotObject' has key as hostname, and the slot index as value.
    */
-  refreshHostSlots: function () {
+  refreshHostSlots: function (hostNames) {
     this.set('loading', true);
+    this.set('hostNames', hostNames);
     var fixedMetricName = this.get('defaultMetric');
     fixedMetricName = fixedMetricName.replace(/\./g, "/");
     var ajaxData = {

+ 2 - 4
ambari-web/app/models/rack.js

@@ -24,10 +24,8 @@ App.Rack = DS.Model.extend({
   status: DS.attr('string'),
   criticalHostsCount: DS.attr('number'),
   deadHostsCount: DS.attr('number'),
-  hosts: App.Host.find(),
-  liveHostsCount: function () {
-    return this.get('hosts').filterProperty('healthStatus', 'HEALTHY').length;
-  }.property('hosts.@each.healthStatus')
+  liveHostsCount: DS.attr('number'),
+  hosts: []
 });
 
 App.Rack.FIXTURES = [

+ 1 - 1
ambari-web/app/templates/main/charts/heatmap/heatmap_host.hbs

@@ -17,5 +17,5 @@
 }}
 
 <div {{bindAttr class="view.hostClass"}} {{bindAttr style="view.hostTemperatureStyle"}}>
-  <a href="#" class="heatmap-host" {{action "showDetails" view.content}}></a>
+  <a href="#" class="heatmap-host" {{action "showDetails" view.hostModelLink}}></a>
 </div>

+ 8 - 5
ambari-web/app/templates/main/charts/heatmap/heatmap_rack.hbs

@@ -40,9 +40,12 @@
   <!--{{!/if}}-->
 <!--</div>-->
 <div class="isActive hosts clearfix">
-  {{#each view.hosts}}
-    <div {{bindAttr style="view.hostCssStyle"}}>
-      {{view App.MainChartsHeatmapHostView contentBinding="this"}}
-    </div>
-  {{/each}}
+  <div {{bindAttr  class="view.rack.isLoaded::hidden"}}>
+    {{#each view.hosts}}
+        <div {{bindAttr style="view.hostCssStyle"}}>
+          {{view App.MainChartsHeatmapHostView contentBinding="this"}}
+        </div>
+    {{/each}}
+  </div>
+  <div {{bindAttr  class="view.rack.isLoaded:hidden :spinner"}}></div>
 </div>

+ 1 - 1
ambari-web/app/utils/ajax/ajax.js

@@ -2091,7 +2091,7 @@ var urls = {
     'mock': ''
   },
   'hosts.heatmaps': {
-    'real': '/clusters/{clusterName}/hosts?fields=Hosts/host_name,Hosts/maintenance_state,Hosts/public_host_name,Hosts/cpu_count,Hosts/ph_cpu_count,Hosts/total_mem,Hosts/host_status,Hosts/last_heartbeat_time,Hosts/os_arch,Hosts/os_type,Hosts/ip,host_components/HostRoles/service_name,host_components/HostRoles/state,host_components/HostRoles/maintenance_state,Hosts/disk_info,metrics/disk,metrics/load/load_one,metrics/cpu/cpu_system,metrics/cpu/cpu_user,metrics/memory/mem_total,metrics/memory/mem_free,alerts/summary&minimal_response=true',
+    'real': '/clusters/{clusterName}/hosts?fields=Hosts/host_name,Hosts/public_host_name,Hosts/os_type,Hosts/ip,host_components,metrics/disk,metrics/cpu/cpu_system,metrics/cpu/cpu_user,metrics/memory/mem_total,metrics/memory/mem_free&minimal_response=true',
     'mock': ''
   },
 

+ 5 - 3
ambari-web/app/views/main/charts/heatmap.js

@@ -24,11 +24,13 @@ App.MainChartsHeatmapView = Em.View.extend({
     this._super();
     // set default metric
     this.set('controller.selectedMetric', this.get('controller.allMetrics')[0].get('items')[0]);
-    this.get('controller.racks').setEach('isLoaded', false);
     $("#heatmapDetailsBlock").hide();
   },
+  /**
+   * show spinner while loading selected metric
+   */
   showLoading: function () {
-    if (this.get('controller.selectedMetric.loading') || !this.get('controller.racks').everyProperty('isLoaded')) {
+    if (this.get('controller.selectedMetric.loading')) {
       var e = document.getElementById("heatmap-metric-loading");
       if (e) {
         $(e).children('div.spinner').remove();
@@ -49,5 +51,5 @@ App.MainChartsHeatmapView = Em.View.extend({
       }
       this.set('spinner', null);
     }
-  }.observes('controller.selectedMetric.loading', 'controller.racks.@each.isLoaded')
+  }.observes('controller.selectedMetric.loading')
 });

+ 81 - 37
ambari-web/app/views/main/charts/heatmap/heatmap_host.js

@@ -5,9 +5,9 @@
  * 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
@@ -24,51 +24,83 @@ App.MainChartsHeatmapHostView = Em.View.extend({
   /** @private */
   hostClass: 'hostBlock',
 
+  /**
+   * link to host record in App.Host model
+   */
+  hostModelLink: function () {
+    return App.Host.find(this.get('content.hostName'));
+  }.property('content.hostName'),
+
   /**
    * show Host details block and move it near the cursor
-   * 
-   * @param {Object} e
+   *
+   * @param {Object} event
    * @this App.MainChartsHeatmapHostView
    */
-  mouseEnter: function (e) {
+  mouseEnter: function (event) {
     var host = this.get('content');
     var view = App.MainChartsHeatmapHostDetailView.create();
-    $.each(view.get('details'), function(i){
-      var val = host.get(i);
-      if (i == 'diskUsage') {
-        if (val == undefined || isNaN(val) || val == Infinity || val == -Infinity) {
-          val = null;
-        } else {
-          val = val.toFixed(1);
-        }
-      } else if (i == 'cpuUsage') {
-        if (val == undefined || isNaN(val)) {
-          val = null;
-        } else {
-          val = val.toFixed(1);
-        }
-      } else if (i == 'memoryUsage') {
-        if (val == undefined || isNaN(val) || val == Infinity || val == -Infinity) {
-          val = null;
-        } else {
+    var self = this;
+    var nonClientComponents = App.get('components.slaves').concat(App.get('components.masters'));
+
+    $.each(view.get('details'), function (i) {
+      var val = host[i];
+
+      switch (i) {
+        case 'diskUsage':
+          val = self.getUsage(host, 'diskTotal', 'diskFree');
+          break;
+        case 'cpuUsage':
+          val = 0;
+          if (Number.isFinite(host.cpuSystem) && Number.isFinite(host.cpuUser)) {
+            val = host.cpuSystem + host.cpuUser;
+          }
           val = val.toFixed(1);
-        }
-      } else if (i == 'hostComponents') {
-        if (val == undefined) {
-          val = null;
-        } else {
-          val = val.filterProperty('isMaster').concat(val.filterProperty('isSlave')).mapProperty('displayName').join(', ');
-        }
+          break;
+        case 'memoryUsage':
+          val = self.getUsage(host, 'memTotal', 'memFree');
+          break;
+        case 'hostComponents':
+          val = [];
+          host[i].forEach(function (componentName) {
+            if (nonClientComponents.contains(componentName)) {
+              val.push(App.format.role(componentName));
+            }
+          }, this);
+          val = val.join(', ')
       }
+
       view.set('details.' + i, val);
     });
+    this.setMetric(view, host);
+    this.openDetailsBlock(event);
+  },
+
+  /**
+   * show tooltip with host's details
+   */
+  openDetailsBlock: function (event) {
+    var detailsBlock = $("#heatmapDetailsBlock");
+
+    detailsBlock.css('top', event.pageY + 10);
+    detailsBlock.css('left', event.pageX + 10);
+    detailsBlock.show();
+  },
+
+  /**
+   * set name and value of selected metric
+   * @param view
+   * @param host
+   */
+  setMetric: function (view, host) {
     var selectedMetric = this.get('controller.selectedMetric');
+
     if (selectedMetric) {
       var metricName = selectedMetric.get('name');
       var h2vMap = selectedMetric.get('hostToValueMap');
       if (h2vMap && metricName) {
-        var value = h2vMap[host.get('hostName')];
-        if (value == undefined || value == null) {
+        var value = h2vMap[host.hostName];
+        if (Em.isNone(value)) {
           value = this.t('charts.heatmap.unknown');
         } else {
           if (metricName == 'Garbage Collection Time') {
@@ -85,15 +117,27 @@ App.MainChartsHeatmapHostView = Em.View.extend({
         view.set('details.metricValue', value);
       }
     }
-    var detailsBlock = $("#heatmapDetailsBlock");
-    detailsBlock.css('top', e.pageY + 10);
-    detailsBlock.css('left', e.pageX + 10);
-    detailsBlock.show();
+  },
+  /**
+   * get relative usage of metric in percents
+   * @param item
+   * @param totalProperty
+   * @param freeProperty
+   * @return {String}
+   */
+  getUsage: function (item, totalProperty, freeProperty) {
+    var result = 0;
+    var total = item[totalProperty];
+
+    if (Number.isFinite(total) && Number.isFinite(item[freeProperty]) && total > 0) {
+      result = ((total - item[freeProperty]) / total) * 100;
+    }
+    return result.toFixed(1);
   },
 
   /**
    * hide Host details block
-   * 
+   *
    * @param {Object} e
    * @this App.MainChartsHeatmapHostView
    */

+ 115 - 15
ambari-web/app/views/main/charts/heatmap/heatmap_rack.js

@@ -25,14 +25,12 @@ App.MainChartsHeatmapRackView = Em.View.extend({
   classNameBindings: ['visualSchema'],
 
   /** rack status block class */
-  statusIndicator:'statusIndicator',
+  statusIndicator: 'statusIndicator',
   /** loaded hosts of rack */
-  hosts: function() {
-    return this.get('rack.hosts').toArray();
-  }.property('rack.hosts', 'rack.hosts.length'),
+  hosts: [],
 
-  willInsertElement: function () {
-    this.set('rack.isLoaded', false);
+  willDestroyElement: function () {
+    this.get('hosts').clear();
   },
 
   /**
@@ -49,15 +47,119 @@ App.MainChartsHeatmapRackView = Em.View.extend({
   },
 
   getHostsSuccessCallback: function (data, opt, params) {
-    App.hostsMapper.map(data, true);
-    this.set('rack.isLoaded', true);
+    this.pushHostsToRack(data);
+    this.displayHosts();
+  },
+
+  /**
+   * display hosts of rack
+   */
+  displayHosts: function () {
+    var rackHosts = this.get('rack.hosts');
+
+    if (this.get('hosts.length') === 0) {
+      if (rackHosts.length > 100) {
+        lazyloading.run({
+          initSize: 100,
+          chunkSize: 200,
+          delay: 100,
+          destination: this.get('hosts'),
+          source: rackHosts,
+          context: this.get('rack')
+        });
+      } else {
+        this.set('hosts', rackHosts);
+        this.set('rack.isLoaded', true);
+      }
+    }
   },
 
-  getHostsErrorCallback: function(request, ajaxOptions, error, opt, params){
+  getHostsErrorCallback: function (request, ajaxOptions, error, opt, params) {
     this.set('rack.isLoaded', true);
   },
+  /**
+   * push hosts to rack
+   * @param data
+   */
+  pushHostsToRack: function (data) {
+    var newHostsData = [];
+    var rackHosts = this.get('rack.hosts');
+
+    data.items.forEach(function (item) {
+      newHostsData.push({
+        hostName: item.Hosts.host_name,
+        publicHostName: item.Hosts.public_host_name,
+        osType: item.Hosts.os_type,
+        ip: item.Hosts.ip,
+        diskTotal: item.metrics.disk.disk_total,
+        diskFree: item.metrics.disk.disk_free,
+        cpuSystem: item.metrics.cpu.cpu_system,
+        cpuUser: item.metrics.cpu.cpu_user,
+        memTotal: item.metrics.memory.mem_total,
+        memFree: item.metrics.memory.mem_free,
+        hostComponents: item.host_components.mapProperty('HostRoles.component_name')
+      })
+    });
+
+    if (rackHosts.length > 0) {
+      this.updateLoadedHosts(rackHosts, newHostsData);
+    } else {
+      this.set('rack.hosts', newHostsData);
+    }
+  },
+
+  updateLoadedHosts: function (rackHosts, newHostsData) {
+    var rackHostsMap = {};
+    var isNewHosts = false;
+
+    //create map
+    rackHosts.forEach(function (host) {
+      rackHostsMap[host.hostName] = host;
+    });
+
+    newHostsData.forEach(function (item) {
+      var currentHostInfo = rackHostsMap[item.hostName];
+
+      if (currentHostInfo) {
+        ['diskTotal', 'diskFree', 'cpuSystem', 'cpuUser', 'memTotal', 'memFree', 'hostComponents'].forEach(function (property) {
+          currentHostInfo[property] = item[property];
+        });
+        delete rackHostsMap[item.hostName];
+      } else {
+        isNewHosts = true;
+      }
+    }, this);
+
+    //if hosts were deleted or added then reload hosts view
+    if (!App.isEmptyObject(rackHostsMap) || isNewHosts) {
+      this.redrawHostsView(newHostsData)
+    }
+  },
+
+  /**
+   * reload hosts rack
+   * @param newHostsData
+   */
+  redrawHostsView: function (newHostsData) {
+    this.set('rack.isLoaded', false);
+    this.get('hosts').clear();
+    this.set('rack.hosts', newHostsData);
+  },
+
+  /**
+   * call metrics update after hosts of rack are loaded
+   */
+  updateMetrics: function(){
+    if (this.get('rack.isLoaded')) {
+      this.get('controller').loadMetrics();
+    }
+  }.observes('rack.isLoaded'),
 
   didInsertElement: function () {
+    this.set('rack.isLoaded', false);
+    if (this.get('rack.hosts.length') > 0) {
+      this.displayHosts();
+    }
     this.getHosts();
   },
   /**
@@ -68,12 +170,10 @@ App.MainChartsHeatmapRackView = Em.View.extend({
     var rack = this.get('rack');
     var widthPercent = 100;
     var hostCount = rack.get('hosts.length');
-    if (rack.get('isLoaded')) {
-      if (hostCount && hostCount < 11) {
-        widthPercent = (100 / hostCount) - 0.5;
-      } else {
-        widthPercent = 10; // max out at 10%
-      }
+    if (hostCount && hostCount < 11) {
+      widthPercent = (100 / hostCount) - 0.5;
+    } else {
+      widthPercent = 10; // max out at 10%
     }
     return "width:" + widthPercent + "%;float:left;";
   }.property('rack.isLoaded')