Repository: ambari
Updated Branches:
  refs/heads/trunk b51bfea4e -> 6625ae5dd


AMBARI-5203. Jobs page becomes extremely slow and unresponsive around 500 
queries (alexantonenko)


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

Branch: refs/heads/trunk
Commit: 4f226737f99d2caadbd53b27945c14d7a745d43d
Parents: b51bfea
Author: Alex Antonenko <hiv...@gmail.com>
Authored: Tue Mar 25 17:21:40 2014 +0200
Committer: Alex Antonenko <hiv...@gmail.com>
Committed: Tue Mar 25 17:21:40 2014 +0200

----------------------------------------------------------------------
 .../app/controllers/main/jobs_controller.js     | 84 +++++++++++++++++---
 ambari-web/app/mappers/jobs/hive_jobs_mapper.js |  5 +-
 ambari-web/app/messages.js                      |  1 +
 ambari-web/app/templates/main/jobs.hbs          | 12 ++-
 ambari-web/app/views/main/jobs_view.js          |  4 +-
 5 files changed, 87 insertions(+), 19 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/4f226737/ambari-web/app/controllers/main/jobs_controller.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/controllers/main/jobs_controller.js 
b/ambari-web/app/controllers/main/jobs_controller.js
index d77a9ed..454210b 100644
--- a/ambari-web/app/controllers/main/jobs_controller.js
+++ b/ambari-web/app/controllers/main/jobs_controller.js
@@ -18,11 +18,72 @@
 
 var App = require('app');
 
-App.MainJobsController = Em.ArrayController.extend({
-
+App.MainJobsController = Em.Controller.extend({
+/*
+ * https://github.com/emberjs/ember.js/issues/1221 prevents this controller
+ * from being an Ember.ArrayController. Doing so will keep the UI flashing
+ * whenever any of the 'sortProperties' or 'sortAscending' properties are set.
+ * 
+ *  To bypass this issue this controller will be a regular controller. Also,
+ *  for memory-leak issues and sorting purposes, we are decoupling the backend
+ *  model and the UI model. There will be simple Ember POJOs for the UI which
+ *  will be periodically updated from backend Jobs model. 
+ */
+  
   name:'mainJobsController',
 
-  content: [],
+  /**
+   * Unsorted ArrayProxy
+   */
+  content: App.HiveJob.find(),
+  
+  /**
+   * Sorted ArrayProxy
+   */
+  sortedContent: [],
+
+  contentAndSortObserver : function() {
+    Ember.run.once(this, 'contentAndSortUpdater');
+  }.observes('content.length', 'conte...@each.id', 'content.@each.startTime', 
'content.@each.endTime', 'sortProperties', 'sortAscending'),
+  
+  contentAndSortUpdater: function() {
+    var content = this.get('content');
+    var sortedContent = content.toArray();
+    var sortProperty = this.get('sortProperty');
+    var sortAscending = this.get('sortAscending');
+    sortedContent.sort(function(r1, r2) {
+      var r1id = r1.get(sortProperty);
+      var r2id = r2.get(sortProperty);
+      if (r1id < r2id)
+        return sortAscending ? -1 : 1;
+      if (r1id > r2id)
+        return sortAscending ? 1 : -1;
+      return 0;
+    });
+    var sortedArray = this.get('sortedContent');
+    var count = 0;
+    sortedContent.forEach(function(sortedJob){
+      if(sortedArray.length <= count) {
+        sortedArray.pushObject(Ember.Object.create());
+      }
+      sortedArray[count].set('failed', sortedJob.get('failed'));
+      sortedArray[count].set('hasTezDag', sortedJob.get('hasTezDag'));
+      sortedArray[count].set('queryText', sortedJob.get('queryText'));
+      sortedArray[count].set('name', sortedJob.get('name'));
+      sortedArray[count].set('user', sortedJob.get('user'));
+      sortedArray[count].set('id', sortedJob.get('id'));
+      sortedArray[count].set('startTimeDisplay', 
sortedJob.get('startTimeDisplay'));
+      sortedArray[count].set('endTimeDisplay', 
sortedJob.get('endTimeDisplay'));
+      sortedArray[count].set('durationDisplay', 
sortedJob.get('durationDisplay'));
+      count ++;
+    });
+    if(sortedArray.length > count) {
+      for(var c = sortedArray.length-1; c >= count; c--){
+        sortedArray.removeObject(sortedArray[c]);
+      }
+    }
+    sortedContent.length = 0;
+  },
 
   loaded : false,
   loading : false,
@@ -31,6 +92,15 @@ App.MainJobsController = Em.ArrayController.extend({
   jobsUpdateInterval: 6000,
   jobsUpdate: null,
   sortingColumn: null,
+  sortProperty: 'id',
+  sortAscending: true,
+
+  sortingColumnObserver: function () {
+    if(this.get('sortingColumn')){
+      this.set('sortProperty', this.get('sortingColumn').get('name'));
+      this.set('sortAscending', this.get('sortingColumn').get('status') == 
"sorting_desc" ? false : true );
+    }
+  }.observes('sortingColumn.name','sortingColumn.status'),
 
   updateJobs: function (controllerName, funcName) {
     clearInterval(this.get('jobsUpdate'));
@@ -255,14 +325,6 @@ App.MainJobsController = Em.ArrayController.extend({
           + ":" + yarnService.get('ahsWebPort') + 
"/ws/v1/timeline/HIVE_QUERY_ID" + filtersLink;
       App.HttpClient.get(hiveQueriesUrl, App.hiveJobsMapper, {
         complete : function(jqXHR, textStatus) {
-          var sortColumn = self.get('sortingColumn');
-          if(sortColumn && sortColumn.get('status')){
-            var sortColumnStatus = sortColumn.get('status');
-            sortColumn.get('parentView').set('content', self.get('content'));
-            sortColumn.get('parentView').sort(sortColumn, sortColumnStatus === 
"sorting_desc");
-            sortColumn.set('status', sortColumnStatus);
-            self.set('content',sortColumn.get('parentView').get('content'));
-          }
           self.set('loading', false);
           self.set('loaded', true);
         }

http://git-wip-us.apache.org/repos/asf/ambari/blob/4f226737/ambari-web/app/mappers/jobs/hive_jobs_mapper.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/mappers/jobs/hive_jobs_mapper.js 
b/ambari-web/app/mappers/jobs/hive_jobs_mapper.js
index 7ebf8a7..f810bbb 100644
--- a/ambari-web/app/mappers/jobs/hive_jobs_mapper.js
+++ b/ambari-web/app/mappers/jobs/hive_jobs_mapper.js
@@ -72,6 +72,8 @@ App.hiveJobsMapper = App.QuickDataMapper.create({
           hiveJob.end_time = entity.endtime;
         }
         hiveJobs.push(hiveJob);
+        hiveJob = null;
+        entity = null;
       });
       // Delete IDs not seen from server
       var hiveJobsModel = model.find().toArray();
@@ -82,7 +84,8 @@ App.hiveJobsMapper = App.QuickDataMapper.create({
       }, this);
     }
     App.store.loadMany(model, hiveJobs);
-    App.router.get('mainJobsController').set('content', 
App.HiveJob.find().toArray());
+    json = null;
+    hiveJobs = null;
   },
   config : {}
 });

http://git-wip-us.apache.org/repos/asf/ambari/blob/4f226737/ambari-web/app/messages.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/messages.js b/ambari-web/app/messages.js
index cc15d9f..9c3ae98 100644
--- a/ambari-web/app/messages.js
+++ b/ambari-web/app/messages.js
@@ -1964,6 +1964,7 @@ Em.I18n.translations = {
   'menu.item.admin':'Admin',
 
   'jobs.nothingToShow': 'No jobs to display',
+  'jobs.loadingTasks': 'Loading...',
   'jobs.table.custom.date.am':'AM',
   'jobs.table.custom.date.pm':'PM',
   'jobs.table.custom.date.header':'Select Custom Dates',

http://git-wip-us.apache.org/repos/asf/ambari/blob/4f226737/ambari-web/app/templates/main/jobs.hbs
----------------------------------------------------------------------
diff --git a/ambari-web/app/templates/main/jobs.hbs 
b/ambari-web/app/templates/main/jobs.hbs
index a03cc96..81391b6 100644
--- a/ambari-web/app/templates/main/jobs.hbs
+++ b/ambari-web/app/templates/main/jobs.hbs
@@ -26,7 +26,7 @@
       </div>
       <table id="jobs-table" class="table table-bordered table-striped">
           <thead>
-          {{#view view.sortView classNames="label-row" 
contentBinding="controller.content"}}
+          {{#view view.sortView classNames="label-row" 
contentBinding="view.content"}}
               <th></th>
               {{view view.parentView.idSort}}
               {{view view.parentView.userSort}}
@@ -47,10 +47,14 @@
           <tbody>
           {{#if view.noDataToShow}}
               <tr>
+                {{#if controller.loaded}}
                 <td class="no-data" {{bindAttr 
colspan="controller.columnsName.content.length"}}>{{t jobs.nothingToShow}}</td>
+              {{else}}
+                    <td class="no-data" {{bindAttr 
colspan="controller.columnsName.content.length"}}>{{t jobs.loadingTasks}}</td>
+                {{/if}}
               </tr>
           {{else}}
-            {{#each job in controller.content}}
+            {{#each job in controller.sortedContent}}
               <tr>
                 <td>
                   {{#if job.failed}}
@@ -60,9 +64,9 @@
                 <td>
                   <div class="id">
                     {{#if job.hasTezDag}}
-                        <a rel="tooltip" class="job-link" title="{{unbound 
job.queryText}}" href="#" {{action "showJobDetails" job}}>{{unbound 
job.name}}</a>
+                      <a rel="tooltip" class="job-link" {{bindAttr 
title="job.queryText"}} href="#" {{action "showJobDetails" 
job}}>{{job.name}}</a>
                     {{else}}
-                        <span rel="tooltip" class="job-link" title="{{unbound 
job.queryText}}">{{unbound job.name}}</span>
+                      <span rel="tooltip" class="job-link" {{bindAttr 
title="job.queryText"}}>{{job.name}}</span>
                     {{/if}}
                   </div>
                 </td>

http://git-wip-us.apache.org/repos/asf/ambari/blob/4f226737/ambari-web/app/views/main/jobs_view.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/views/main/jobs_view.js 
b/ambari-web/app/views/main/jobs_view.js
index 4ee2d84..25fbe6b 100644
--- a/ambari-web/app/views/main/jobs_view.js
+++ b/ambari-web/app/views/main/jobs_view.js
@@ -23,9 +23,7 @@ var sort = require('views/common/sort_view');
 App.MainJobsView = App.TableView.extend({
   templateName: require('templates/main/jobs'),
 
-  content: function () {
-    return this.get('controller.content');
-  }.property('controller.content.length'),
+  content: [],
 
 
   /**

Reply via email to