Bug 926907 - Handle push updates in batches; r=edmorley
authorArpad Borsos <arpad.borsos@googlemail.com>
Tue, 15 Oct 2013 16:04:34 +0200
changeset 1323 16e6a0cc29c01694070fc415f65718a2b66fa258
parent 1322 5374d60b4091d289fa80fe09726bfcefb40b2cce
child 1324 5c46873a2db6985cebf3b8097e77d52c53979aa5
push id716
push userarpad.borsos@googlemail.com
push dateTue, 15 Oct 2013 14:08:57 +0000
reviewersedmorley
bugs926907
Bug 926907 - Handle push updates in batches; r=edmorley
js/Controller.js
js/Data.js
js/UserInterface.js
--- a/js/Controller.js
+++ b/js/Controller.js
@@ -195,17 +195,17 @@ var Controller = {
     } else {
       // Extend into the past, i.e. decrease startID.
       requestedRange = {
         startID: currentRange.startID - Math.abs(num),
         endID: currentRange.endID,
       };
     }
     var loadTracker = new LoadTracker(this._uiCallbacks.status);
-    this._data.loadPushRange(requestedRange, false, loadTracker, this._uiCallbacks.handleUpdatedPush, this._uiCallbacks.handleInfraStatsUpdate, this._uiCallbacks.handleInitialPushlogLoad);
+    this._data.loadPushRange(requestedRange, false, loadTracker, this._uiCallbacks.handleUpdatedPushes, this._uiCallbacks.handleInfraStatsUpdate, this._uiCallbacks.handleInitialPushlogLoad);
     this._requestedRange = requestedRange;
   },
 
   _getURLForParams: function Controller__getURLForParams(params) {
     var items = [];
     for (var key in params) {
       if (params[key] && params[key] != this._paramDefaults[key])
         items.push(escape(key) + "=" + escape(params[key]));
@@ -289,16 +289,16 @@ var Controller = {
     return {
       range: { maxhours: 24 }, // Don't include pushes that are older than the latest push minus 24 hours.
       trackTip: true,
     };
   },
 
   _initialDataLoad: function Controller__initialDataLoad(initialPushRange) {
     var loadTracker = new LoadTracker(this._uiCallbacks.status);
-    this._data.loadPushRange(initialPushRange, true, loadTracker, this._uiCallbacks.handleUpdatedPush, this._uiCallbacks.handleInfraStatsUpdate, this._uiCallbacks.handleInitialPushlogLoad);
+    this._data.loadPushRange(initialPushRange, true, loadTracker, this._uiCallbacks.handleUpdatedPushes, this._uiCallbacks.handleInfraStatsUpdate, this._uiCallbacks.handleInitialPushlogLoad);
   },
 
   refreshData: function Controller_refreshData() {
     var loadTracker = new LoadTracker(this._uiCallbacks.status);
-    this._data.refresh(loadTracker, this._trackingTip, this._uiCallbacks.handleUpdatedPush, this._uiCallbacks.handleInfraStatsUpdate);
+    this._data.refresh(loadTracker, this._trackingTip, this._uiCallbacks.handleUpdatedPushes, this._uiCallbacks.handleInfraStatsUpdate);
   },
 };
--- a/js/Data.js
+++ b/js/Data.js
@@ -43,33 +43,33 @@ Data.prototype = {
     if (!this._mostRecentPush)
       return null;
     return {
       startID: this._mostRecentPush.id - Object.values(this._pushes).length,
       endID: this._mostRecentPush.id,
     };
   },
 
-  loadPushRange: function Data_loadPushRange(pushRange, loadPendingRunning, loadTracker, updatedPushCallback, infraStatsCallback, initialPushlogLoadCallback) {
+  loadPushRange: function Data_loadPushRange(pushRange, loadPendingRunning, loadTracker, updatedPushesCallback, infraStatsCallback, initialPushlogLoadCallback) {
     var self = this;
     var pushlogRequestParams = this._getPushlogParamsForRange(pushRange);
     pushlogRequestParams.forEach(function (params) {
-      self._loadPushlogData(params, loadTracker, updatedPushCallback, initialPushlogLoadCallback);
+      self._loadPushlogData(params, loadTracker, updatedPushesCallback, initialPushlogLoadCallback);
     });
     if (loadPendingRunning)
-      this._loadPendingAndRunningBuilds(loadTracker, updatedPushCallback, infraStatsCallback);
+      this._loadPendingAndRunningBuilds(loadTracker, updatedPushesCallback, infraStatsCallback);
   },
 
-  refresh: function Data_refresh(loadTracker, trackTip, updatedPushCallback, infraStatsCallback) {
+  refresh: function Data_refresh(loadTracker, trackTip, updatedPushesCallback, infraStatsCallback) {
     if (trackTip) {
       // Passing only startID means "Load all pushes with push.id > startID".
-      this._loadPushlogData({ startID: this._mostRecentPush.id }, loadTracker, updatedPushCallback);
+      this._loadPushlogData({ startID: this._mostRecentPush.id }, loadTracker, updatedPushesCallback);
     }
-    this._loadTinderboxDataForPushes(this._pushes, loadTracker, updatedPushCallback);
-    this._loadPendingAndRunningBuilds(loadTracker, updatedPushCallback, infraStatsCallback);
+    this._loadTinderboxDataForPushes(this._pushes, loadTracker, updatedPushesCallback);
+    this._loadPendingAndRunningBuilds(loadTracker, updatedPushesCallback, infraStatsCallback);
   },
 
   _getPushlogParamsForRange: function Data__getPushlogParamsForRange(pushRange) {
     // This function determines what to load from pushlog so that our total
     // loaded range matches the requested pushRange.
     // pushRange is guaranteed to be a superset of this.getLoadedPushRange().
     // We never make our window smaller.
 
@@ -136,66 +136,66 @@ Data.prototype = {
     // Second pass: Drop all pushes older than mostRecentPushDate - maxHours hours.
     for (var toprev in pushes) {
       var push = pushes[toprev];
       if (push.date < mostRecentPushDate - maxHours * 60 * 60 * 1000)
         delete pushes[toprev];
     }
   },
 
-  _loadPushlogData: function Data__loadPushlogData(params, loadTracker, updatedPushCallback, initialPushlogLoadCallback) {
+  _loadPushlogData: function Data__loadPushlogData(params, loadTracker, updatedPushesCallback, initialPushlogLoadCallback) {
     var self = this;
     var tinderboxLoadEstimation = loadTracker.addMorePotentialLoads(30);
     Config.pushlogDataLoader.load(
       Config.treeInfo[this._treeName].primaryRepo,
       params,
       loadTracker,
       function pushlogLoadCallback(loadedPushes) {
         self._restrictPushesToRequestedRange(loadedPushes, params);
         var updatedPushes = {};
         self._addPushes(loadedPushes, updatedPushes);
         self._addPendingOrRunningResultsToPushes("pending", updatedPushes);
         self._addPendingOrRunningResultsToPushes("running", updatedPushes);
         self._addFinishedResultsToPushes(self._finishedResultsWithoutPush, updatedPushes, updatedPushes);
-        self._notifyUpdatedPushes(updatedPushes, updatedPushCallback);
+        self._notifyUpdatedPushes(updatedPushes, updatedPushesCallback);
         if (initialPushlogLoadCallback)
           initialPushlogLoadCallback();
-        self._loadTinderboxDataForPushes(updatedPushes, loadTracker, updatedPushCallback);
+        self._loadTinderboxDataForPushes(updatedPushes, loadTracker, updatedPushesCallback);
         tinderboxLoadEstimation.cancel();
       }
     );
   },
 
-  _loadTinderboxDataForPushes: function Data__loadTinderboxDataForPushes(unfilteredPushes, loadTracker, updatedPushCallback) {
+  _loadTinderboxDataForPushes: function Data__loadTinderboxDataForPushes(unfilteredPushes, loadTracker, updatedPushesCallback) {
     var self = this;
     Config.tinderboxDataLoader.load(
       this._treeName,
       this._getSortedPushesArray(unfilteredPushes),
       this._showAll,
       loadTracker,
       function tinderboxDataLoadCallback(machineResults) {
         var updatedPushes = [];
         self._addFinishedResultsToPushes(machineResults, self._pushes, updatedPushes);
-        self._notifyUpdatedPushes(updatedPushes, updatedPushCallback);
+        self._notifyUpdatedPushes(updatedPushes, updatedPushesCallback);
       },
       this
     );
   },
 
-  _loadPendingAndRunningBuilds: function Data__loadPendingAndRunningBuilds(loadTracker, updatedPushCallback, infraStatsCallback) {
+  _loadPendingAndRunningBuilds: function Data__loadPendingAndRunningBuilds(loadTracker, updatedPushesCallback, infraStatsCallback) {
     var self = this;
     this._reloadHiddenBuilders(loadTracker);
     ["pending", "running"].forEach(function (pendingOrRunning) {
       self._getPendingOrRunningBuilds(pendingOrRunning, loadTracker, function (data) {
         var updatedPushes = {};
         self._clearOldPendingOrRunningResultsFromTheirPushes(pendingOrRunning, updatedPushes);
         self["_" + pendingOrRunning + "Jobs"] = (typeof data == "object") ? data : {};
         self._discardPendingRunsThatAreAlreadyRunning(updatedPushes);
         self._addPendingOrRunningResultsToPushes(pendingOrRunning, self._pushes, updatedPushes);
-        self._notifyUpdatedPushes(updatedPushes, updatedPushCallback);
+        self._notifyUpdatedPushes(updatedPushes, updatedPushesCallback);
         self._reportInfrastructureStatistics(infraStatsCallback);
       });
     });
   },
 
   _addPushes: function Data__addPushes(loadedPushes, updatedPushes) {
     for (var toprev in loadedPushes) {
       var push = loadedPushes[toprev];
@@ -226,17 +226,17 @@ Data.prototype = {
 
   _getSortedPushesArray: function Data__getSortedPushesArray(unsortedPushesObject) {
     var pushes = Object.values(unsortedPushesObject);
     pushes.sort(function(a,b) { return a.date - b.date; });
     return pushes;
   },
 
   _notifyUpdatedPushes: function Data__notifyUpdatedPushes(updatedPushes, callback) {
-    this._getSortedPushesArray(updatedPushes).forEach(callback);
+    callback(this._getSortedPushesArray(updatedPushes));
   },
 
   _reportInfrastructureStatistics: function Data__reportInfrastructureStatistics(infraStatsCallback) {
     if (!this._pendingJobs || !this._runningJobs)
       return;
 
     var self = this;
     var infraStats = {};
--- a/js/UserInterface.js
+++ b/js/UserInterface.js
@@ -139,18 +139,17 @@ var UserInterface = {
       self.updateStatus();
       if (changedResult) {
         // Starredness is reflected in several places:
         //  - a star after the letter in the results column next to the push
         //  - the list of failed jobs in the top right corner
         //  - the number of unstarred failures in the title
         //  - the panel showing the star if the starred result is selected
         // We need to refresh all these places.
-        self.handleUpdatedPush(changedResult.push);
-        self._updateFailingBuildsDisplay();
+        self.handleUpdatedPushes([changedResult.push]);
         self._setActiveResult(self._activeResult, false);
       }
     });
     AddCommentUI.registerNumSendingBugChangedCallback(function bugSendUpdater() {
       self.updateStatus();
     });
     HiddenBuildsAdminUI.init();
 
@@ -162,18 +161,18 @@ var UserInterface = {
           self._controller.extendPushRange(-Config.goBackPushes);
           return false;
         }).parent());
 
     return {
       status: function (status) {
         self.updateStatus(status);
       },
-      handleUpdatedPush: function (push) {
-        self.handleUpdatedPush(push);
+      handleUpdatedPushes: function (push) {
+        self.handleUpdatedPushes(push);
       },
       handleInfraStatsUpdate: function (infraStats) {
         self.handleInfraStatsUpdate(infraStats);
       },
       handleInitialPushlogLoad: function () {
         $("#pushes").removeClass("initialload");
       },
       updateTreeStatus: function (data) {
@@ -212,30 +211,33 @@ var UserInterface = {
 
   _getPrettyTreeName: function UserInterface_getPrettyTreeName(treeName) {
     if (!(treeName in Config.treeInfo))
       return "Unknown Tree";
     return ("prettierName" in Config.treeInfo[treeName])
              ? Config.treeInfo[treeName].prettierName : treeName;
   },
 
-  handleUpdatedPush: function UserInterface_handleUpdatedPush(push) {
+  handleUpdatedPushes: function UserInterface_handleUpdatedPushes(pushes) {
+    var self = this;
     $("#nopushes").remove();
-    var existingPushNode = $("#push-" + push.id);
-    if (existingPushNode.length) {
-      this._refreshPushResultsInPushNode(push, existingPushNode);
-    } else {
-      var pushNode = this._generatePushNode(push);
-      pushNode.insertBefore(this._getInsertBeforeAnchor(push));
+    pushes.forEach(function (push) {
+      var existingPushNode = $("#push-" + push.id);
+      if (existingPushNode.length) {
+        self._refreshPushResultsInPushNode(push, existingPushNode);
+      } else {
+        var pushNode = self._generatePushNode(push);
+        pushNode.insertBefore(self._getInsertBeforeAnchor(push));
 
-      // It's a new push node which might need to be filtered.
-      if (this._pusher && this._pusher != push.pusher) {
-        pushNode.hide();
+        // It's a new push node which might need to be filtered.
+        if (self._pusher && self._pusher != push.pusher) {
+          pushNode.hide();
+        }
       }
-    }
+    });
     this._updateFailingBuildsDisplay();
   },
 
   _getInsertBeforeAnchor: function UserInterface__getInsertBeforeAnchor(push) {
     var allPushNodes = $("#pushes").children(".push");
     // allPushNodes are sorted in decreasing pushID order.
     // The first pushNode with pushID < push.id will be our
     // insertBefore anchor. If all existing pushes have
@@ -413,25 +415,24 @@ var UserInterface = {
       $("#wrongtree").html(
         "The tree “" + this._treeName.escapeContent() +
         "” does not exist in Tinderboxpushlog. " +
         "Please choose a tree from the list on the upper left.");
     }
   },
 
   _updateUnstarredFilter: function UserInterface__updateOnlyStarredFilter(state) {
+    if (state == this._onlyUnstarred)
+      return;
+
     document.getElementById('onlyUnstarred').checked = state;
     this._onlyUnstarred = state;
 
     var pushes = Object.values(this._data.getPushes());
-    for (var i = 0; i < pushes.length; ++i) {
-      this.handleUpdatedPush(pushes[i]);
-    }
-
-    this._updateFailingBuildsDisplay();
+    this.handleUpdatedPushes(pushes);
   },
 
   _updatePusherFilter: function UserInterface__updatePusherFilter(pusher) {
     document.getElementById('pusher').value = pusher;
     this._pusher = pusher;
 
     var self = this;
     // This loop needs to be executed even if the pusher hasn't changed
@@ -459,23 +460,18 @@ var UserInterface = {
 
   _updateMachineFilter: function UserInterface__updateMachineFilter(machine) {
     if (machine == this._machine)
       return;
 
     document.getElementById('machine').value = machine;
     this._machine = machine;
 
-    var self = this;
     var pushes = Object.values(this._data.getPushes());
-    for (var i = 0; i < pushes.length; ++i) {
-      this.handleUpdatedPush(pushes[i]);
-    }
-
-    this._updateFailingBuildsDisplay();
+    this.handleUpdatedPushes(pushes);
   },
 
   _initFilters: function UserInterface__initFilters() {
     var onlyUnstarredCheckbox = document.getElementById('onlyUnstarred');
     var pusherField = document.getElementById('pusher');
     var machineField = document.getElementById('machine');
 
     // Use the values passed in parameter as the default values.