You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tez.apache.org by sr...@apache.org on 2015/11/05 03:15:48 UTC
tez git commit: TEZ-2893. Tez UI: Retain vertex info displayed in DAG
details page even after completion (sree)
Repository: tez
Updated Branches:
refs/heads/master baa506557 -> d7ba1098e
TEZ-2893. Tez UI: Retain vertex info displayed in DAG details page even after completion (sree)
Project: http://git-wip-us.apache.org/repos/asf/tez/repo
Commit: http://git-wip-us.apache.org/repos/asf/tez/commit/d7ba1098
Tree: http://git-wip-us.apache.org/repos/asf/tez/tree/d7ba1098
Diff: http://git-wip-us.apache.org/repos/asf/tez/diff/d7ba1098
Branch: refs/heads/master
Commit: d7ba1098e8d2c0050d6acf490906a4c86346f256
Parents: baa5065
Author: Sreenath Somarajapuram <sr...@apache.org>
Authored: Thu Nov 5 07:45:10 2015 +0530
Committer: Sreenath Somarajapuram <sr...@apache.org>
Committed: Thu Nov 5 07:45:10 2015 +0530
----------------------------------------------------------------------
CHANGES.txt | 1 +
tez-ui/src/main/webapp/app/scripts/app.js | 15 +-
.../bs-progress-animated-component.js | 4 +-
.../app/scripts/controllers/dag_controller.js | 151 +++--------
.../scripts/controllers/dag_index_controller.js | 263 ++++++++++++-------
.../app/scripts/controllers/dag_vertices.js | 6 +-
.../scripts/controllers/polling-controller.js | 1 +
.../controllers/table-page-controller.js | 8 +
.../main/webapp/app/scripts/helpers/em-data.js | 59 +++++
.../scripts/helpers/entity-array-pollster.js | 51 +---
.../app/scripts/models/TimelineRestAdapter.js | 38 ++-
.../src/main/webapp/app/scripts/models/dag.js | 16 +-
tez-ui/src/main/webapp/app/scripts/router.js | 10 +-
.../src/main/webapp/app/templates/dag/index.hbs | 20 +-
14 files changed, 375 insertions(+), 268 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/tez/blob/d7ba1098/CHANGES.txt
----------------------------------------------------------------------
diff --git a/CHANGES.txt b/CHANGES.txt
index 4d63906..355a85c 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -7,6 +7,7 @@ INCOMPATIBLE CHANGES
TEZ-2679. Admin forms of launch env settings
ALL CHANGES:
+ TEZ-2893. Tez UI: Retain vertex info displayed in DAG details page even after completion
TEZ-2878. Tez UI: AM error handling - Make the UI handle cases in which AM returns unexpected/no data
TEZ-2922. Tez Live UI gives access denied for admins
TEZ-2849. Implement Specific Workaround for JDK-8026049 & JDK-8073093.
http://git-wip-us.apache.org/repos/asf/tez/blob/d7ba1098/tez-ui/src/main/webapp/app/scripts/app.js
----------------------------------------------------------------------
diff --git a/tez-ui/src/main/webapp/app/scripts/app.js b/tez-ui/src/main/webapp/app/scripts/app.js
index 5d7e28d..c1c2c45 100644
--- a/tez-ui/src/main/webapp/app/scripts/app.js
+++ b/tez-ui/src/main/webapp/app/scripts/app.js
@@ -194,16 +194,23 @@ App.ready = function () {
// v2 version of am web services
App.DagInfoAdapter = App.AMInfoAdapter.extend({
namespace: App.Configs.restNamespace.aminfoV2,
+ findQuery: function(store, type, query) {
+ var record = query.metadata;
+ delete query.metadata;
+ return this.ajax(
+ this.buildURL(Ember.String.pluralize(type.typeKey),
+ record.dagID, Em.Object.create(record)), 'GET', { data: query});
+ },
buildURL: function(type, id, record) {
- var url = this._super(type, null, record);
- return url.replace('__app_id__', record.get('appId'))
- .fmt(record.get('dagIdx'));
+ var url = this._super(type, undefined, record);
+ return url.replace('__app_id__', record.get('appID')).fmt(id);
},
- pathForType: function() {
+ pathForType: function(typeName) {
return 'dagInfo?dagID=%@';
}
});
+
App.VertexInfoAdapter = App.AMInfoAdapter.extend({
namespace: App.Configs.restNamespace.aminfoV2,
findQuery: function(store, type, query) {
http://git-wip-us.apache.org/repos/asf/tez/blob/d7ba1098/tez-ui/src/main/webapp/app/scripts/components/bs-progress-animated-component.js
----------------------------------------------------------------------
diff --git a/tez-ui/src/main/webapp/app/scripts/components/bs-progress-animated-component.js b/tez-ui/src/main/webapp/app/scripts/components/bs-progress-animated-component.js
index 22f380d..6a260ea 100644
--- a/tez-ui/src/main/webapp/app/scripts/components/bs-progress-animated-component.js
+++ b/tez-ui/src/main/webapp/app/scripts/components/bs-progress-animated-component.js
@@ -25,7 +25,9 @@ Bootstrap.BsProgressAnimatedComponent = Bootstrap.BsProgressComponent.extend({
},
progressDecimalObserver: function () {
- this.set('progress', parseInt(this.get('progressDecimal') * 100).toString());
+ var progress = parseFloat(this.get('progressDecimal'));
+ progress = (typeof progress == 'number' && !isNaN(progress)) ? progress : 0;
+ this.set('progress', parseInt(progress * 100).toString());
}.observes('progressDecimal'),
progressObserver: function () {
http://git-wip-us.apache.org/repos/asf/tez/blob/d7ba1098/tez-ui/src/main/webapp/app/scripts/controllers/dag_controller.js
----------------------------------------------------------------------
diff --git a/tez-ui/src/main/webapp/app/scripts/controllers/dag_controller.js b/tez-ui/src/main/webapp/app/scripts/controllers/dag_controller.js
index 9643f64..95c6a8f 100644
--- a/tez-ui/src/main/webapp/app/scripts/controllers/dag_controller.js
+++ b/tez-ui/src/main/webapp/app/scripts/controllers/dag_controller.js
@@ -16,10 +16,47 @@
* limitations under the License.
*/
-App.DagController = Em.ObjectController.extend(App.Helpers.DisplayHelper, {
+App.DagController = App.PollingController.extend(App.Helpers.DisplayHelper, {
controllerName: 'DagController',
pageTitle: 'Dag',
+
loading: true,
+ isActive: false,
+
+ pollingType: 'dagInfo',
+
+ setup: function () {
+ this.set('isActive', true);
+ },
+ reset: function () {
+ this.set('isActive', false);
+ },
+
+ pollsterControl: function () {
+ if(this.get('status') == 'RUNNING' &&
+ this.get('amWebServiceVersion') != '1' &&
+ this.get('isActive')) {
+ this.get('pollster').start();
+ }
+ else {
+ this.get('pollster').stop();
+ }
+ }.observes('status', 'amWebServiceVersion', 'isActive'),
+
+ pollsterOptionsObserver: function () {
+ var model = this.get('model');
+
+ this.get('pollster').setProperties( (model && model.get('status') != 'SUCCEEDED') ? {
+ targetRecords: [model],
+ options: {
+ appID: this.get('applicationId'),
+ dagID: App.Helpers.misc.getIndexFromId(this.get('id')),
+ }
+ } : {
+ targetRecords: [],
+ options: null
+ });
+ }.observes('applicationId', 'model', 'model.status', 'id'),
loadAdditional: function(dag) {
var that = this;
@@ -68,19 +105,10 @@ App.DagController = Em.ObjectController.extend(App.Helpers.DisplayHelper, {
var allLoaders = Em.RSVP.all(loaders);
allLoaders.then(function(){
- ['dagProgress', 'dagInfo', 'vertexInfo'].forEach(function(itemType){
- that.store.unloadAll(itemType);
- });
if (dag.get('status') === 'RUNNING') {
// update the progress info if available. this need not block the UI
if (dag.get('amWebServiceVersion') == '1') {
that.updateInfoFromAM(dag);
- } else {
- // if AM version is v2 we keep updating the status, progress etc live.
- ["loading", "id", "model.status"].forEach(function(item) {
- Em.addObserver(that, item, that.startAMInfoUpdateService);
- });
- that.startAMInfoUpdateService();
}
}
});
@@ -91,116 +119,17 @@ App.DagController = Em.ObjectController.extend(App.Helpers.DisplayHelper, {
// called only for v1 version of am api.
updateInfoFromAM: function(dag) {
var that = this;
+ App.Helpers.misc.removeRecord(this.get('store'), 'dagProgress', dag.get('id'));
var aminfoLoader = this.store.find('dagProgress', dag.get('id'), {
appId: dag.get('applicationId'),
dagIdx: dag.get('idx')
}).then(function(dagProgressInfo) {
- that.set('amDagInfo', dagProgressInfo);
+ that.set('dag.progress', dagProgressInfo.get('progress'));
}).catch(function (error) {
Em.Logger.error("Failed to fetch dagProgress" + e);
});
},
- updateAMDagInfo: function() {
- var dagId = this.get('id')
- that = this,
- dagInfoLoader = null;
-
- if (!dagId) return;
-
- if (this.store.recordIsLoaded("dagInfo", dagId)) {
- var dagInfoRecord = this.store.recordForId("dagInfo", dagId);
- if (dagInfoRecord.get('isLoading')) return;
- dagInfoLoader = dagInfoRecord.reload();
- } else {
- dagInfoLoader = this.store.find("dagInfo", dagId, {
- appId: that.get('applicationId'),
- dagIdx: that.get('idx')
- })
- }
-
- dagInfoLoader.then(function(dagInfo){
- that.set('amDagInfo', dagInfo);
- //TODO: find another way to trigger notification
- that.set('amDagInfo._amInfoLastUpdatedTime', moment());
- that.set('amProgressInfoSucceededOnce', true);
- }).catch(function(e){
- if (that.get('amProgressInfoSucceededOnce') === true) {
- that.set('amProgressInfoSucceededOnce', false);
- App.Helpers.ErrorBar.getInstance().show(
- "Failed to get in-progress status. Manually refresh to get the updated status",
- "Application Manager either exited or is not running.");
- }
- });
- },
-
- updateAMVerticesInfo: function() {
- var dagId = this.get('id')
- that = this,
- verticesInfoLoader = null;
-
- if (!dagId) return;
-
- verticesInfoLoader = this.store.findQuery('vertexInfo', {
- metadata: {
- appID: that.get('applicationId'),
- dagID: that.get('idx'),
- counters: App.get('vertexCounters')
- }
- });
-
- verticesInfoLoader.then(function(verticesInfo) {
- that.set('amVertexInfo', verticesInfo);
- }).catch(function(e){
- // do nothing
- });
-
- },
-
- startAMInfoUpdateService: function() {
- if (this.get('loading') || !this.get('model.id') || this.get('model.status') != 'RUNNING') {
- return;
- }
-
- var amInfoUpdateService = this.get('amInfoUpdateService')
- that = this;
-
- if (Em.isNone(amInfoUpdateService)) {
- amInfoUpdateService = App.Helpers.Pollster.create({
- onPoll: function() {
- that.updateAMDagInfo();
- that.updateAMVerticesInfo();
- }
- });
- that.set('amInfoUpdateService', amInfoUpdateService);
- amInfoUpdateService.start(true);
-
- ["loading", "id", "model.status"].forEach(function(item) {
- Em.addObserver(that, item, that.stopAMInfoUpdateService);
- });
- }
- else {
- that.updateAMDagInfo();
- that.updateAMVerticesInfo();
- }
- },
-
- dostopAMInfoUpdateService: function() {
- var amInfoUpdateService = this.get('amInfoUpdateService');
- if (!Em.isNone(amInfoUpdateService)) {
- amInfoUpdateService.stop();
- this.set('amInfoUpdateService', undefined);
- }
- },
-
- // stop the update service if the status changes. see startAMInfoUpdateService
- stopAMInfoUpdateService: function() {
- that.set('amProgressInfoSucceededOnce', false);
- if (this.get('loading') || this.get('model.status') != 'RUNNING') {
- this.dostopAMInfoUpdateService();
- }
- },
-
enableAppIdLink: function() {
return !!this.get('tezApp');
}.property('applicationId', 'tezApp'),
http://git-wip-us.apache.org/repos/asf/tez/blob/d7ba1098/tez-ui/src/main/webapp/app/scripts/controllers/dag_index_controller.js
----------------------------------------------------------------------
diff --git a/tez-ui/src/main/webapp/app/scripts/controllers/dag_index_controller.js b/tez-ui/src/main/webapp/app/scripts/controllers/dag_index_controller.js
index a85c707..ad3c454 100644
--- a/tez-ui/src/main/webapp/app/scripts/controllers/dag_index_controller.js
+++ b/tez-ui/src/main/webapp/app/scripts/controllers/dag_index_controller.js
@@ -16,21 +16,59 @@
* limitations under the License.
*/
- //TODO: watch individual counters.
-App.DagIndexController = Em.ObjectController.extend(App.ModelRefreshMixin, {
+App.DagIndexController = App.TablePageController.extend({
controllerName: 'DagIndexController',
+ needs: "dag",
- needs: 'dag',
+ entityType: 'dagVertex',
+ filterEntityType: 'dag',
+ filterEntityId: Ember.computed.alias('controllers.dag.id'),
- liveData: null,
+ cacheDomain: Ember.computed.alias('controllers.dag.id'),
- succeededTasks: null,
- totalTasks: null,
- completedVertices: null,
+ pollingType: 'vertexInfo',
- liveDataObserver: function () {
- var vertexInfoContent = this.get('amVertexInfo.content'),
- liveData = null,
+ init: function () {
+ this._super();
+ this.set('pollster.mergeProperties', ['progress', 'status', 'runningTasks', 'pendingTasks',
+ 'sucessfulTasks', 'failedTaskAttempts', 'killedTaskAttempts']);
+ },
+
+ reset: function () {
+ this._super();
+ this.set('data', null);
+ },
+
+ pollsterControl: function () {
+ if(this.get('status') == 'RUNNING' &&
+ this.get('amWebServiceVersion') != '1' &&
+ !this.get('loading') &&
+ this.get('isActive') &&
+ this.get('rowsDisplayed.length') > 0) {
+ this.get('pollster').start();
+ }
+ else {
+ this.get('pollster').stop();
+ }
+ }.observes('status', 'amWebServiceVersion', 'loading', 'isActive'),
+
+ applicationComplete: function () {
+ this._super();
+ this.set('controllers.dag.progress', 1);
+ },
+
+ pollsterOptionsObserver: function () {
+ this.set('pollster.options', {
+ appID: this.get('applicationId'),
+ dagID: this.get('idx')
+ });
+ }.observes('applicationId', 'idx').on('init'),
+
+ progressDetails: null,
+
+ progressObserver: function () {
+ var vertexInfoContent = this.get('pollster.polledRecords.content'),
+ progressDetails = null,
succeededTasks = null,
totalTasks = null,
completedVertices = null;
@@ -42,65 +80,86 @@ App.DagIndexController = Em.ObjectController.extend(App.ModelRefreshMixin, {
completedVertices = 0;
liveData.forEach(function (vertex) {
- succeededTasks += parseInt(vertex.get('succeededTasks'));
- totalTasks += parseInt(vertex.get('totalTasks'));
+ succeededTasks += parseInt(vertex.get('sucessfulTasks'));
+ totalTasks += parseInt(vertex.get('numTasks'));
if(vertex.get('progress') >= 1) {
completedVertices++;
}
});
+
+ progressDetails = {
+ succeededTasks: succeededTasks,
+ completedVertices: completedVertices,
+ totalTasks: totalTasks
+ };
}
- this.setProperties({
- liveData: liveData,
- succeededTasks: succeededTasks,
- totalTasks: totalTasks,
- completedVertices: completedVertices
+ this.set('progressDetails', progressDetails);
+ }.observes('pollster.polledRecords'),
+
+ dataObserver: function () {
+ var data = this.get('data.content');
+ this.set('rowsDisplayed', data ? data.slice(0) : null);
+ }.observes('data'),
+
+ beforeLoad: function () {
+ var dagController = this.get('controllers.dag'),
+ model = dagController.get('model');
+ return model.reload().then(function () {
+ return dagController.loadAdditional(model);
});
- }.observes('amVertexInfo'),
+ },
- dagRunning: function () {
- var progress = this.get('dagProgress');
- return progress != null && progress < 1;
- }.property('dagProgress'),
+ afterLoad: function () {
+ var data = this.get('data'),
+ runningVerticesIdx,
+ isUnsuccessfulDag = App.Helpers.misc.isStatusInUnsuccessful(
+ this.get('controllers.dag.status')
+ );
- actions: {
- downloadDagJson: function() {
- var dagID = this.get('id');
- var downloader = App.Helpers.misc.downloadDAG(this.get('id'), {
- batchSize: 500,
- onSuccess: function() {
- Bootstrap.ModalManager.close('downloadModal');
- },
- onFailure: function() {
- $('#modalMessage').html('<i class="fa fa-lg fa-exclamation-circle margin-small-horizontal" ' +
- 'style="color:red"></i> Error downloading data');
- }
+ if(isUnsuccessfulDag) {
+ data.filterBy('status', 'RUNNING').forEach(function (vertex) {
+ vertex.set('status', 'KILLED');
});
- this.set('tmpDownloader', downloader);
- var modalDialogView = Ember.View.extend({
- template: Em.Handlebars.compile(
- '<p id="modalMessage"><i class="fa fa-lg fa-spinner fa-spin margin-small-horizontal" ' +
- 'style="color:green"></i>Downloading data for dag %@</p>'.fmt(dagID)
- )
- });
- var buttons = [
- Ember.Object.create({title: 'Cancel', dismiss: 'modal', clicked: 'cancelDownload'})
- ];
- Bootstrap.ModalManager.open('downloadModal', 'Download data',
- modalDialogView, buttons, this);
- },
+ }
- cancelDownload: function() {
- var currentDownloader = this.get('tmpDownloader');
- if (!!currentDownloader) {
- currentDownloader.cancel();
- }
- this.set('tmpDownloader', undefined);
+ if (this.get('controllers.dag.amWebServiceVersion') == '1') {
+ this._loadProgress(data);
}
+ return this._super();
+ },
+
+ // Load progress in parallel for v1 version of the api
+ _loadProgress: function (vertices) {
+ var that = this,
+ runningVerticesIdx = vertices
+ .filterBy('status', 'RUNNING')
+ .map(function(item) {
+ return item.get('id').split('_').splice(-1).pop();
+ });
+
+ if (runningVerticesIdx.length > 0) {
+ this.store.unloadAll('vertexProgress');
+ this.store.findQuery('vertexProgress', {
+ metadata: {
+ appId: that.get('applicationId'),
+ dagIdx: that.get('idx'),
+ vertexIds: runningVerticesIdx.join(',')
+ }
+ }).then(function(vertexProgressInfo) {
+ App.Helpers.emData.mergeRecords(
+ that.get('rowsDisplayed'),
+ vertexProgressInfo,
+ ['progress']
+ );
+ }).catch(function(error) {
+ Em.Logger.debug("failed to fetch vertex progress")
+ });
+ }
},
- liveColumns: function () {
+ defaultColumnConfigs: function() {
var vertexIdToNameMap = this.get('vertexIdToNameMap');
return App.Helpers.misc.createColumnDescription([
@@ -118,16 +177,11 @@ App.DagIndexController = Em.ObjectController.extend(App.ModelRefreshMixin, {
}
},
{
- id: 'progress',
- headerCellName: 'Progress',
- contentPath: 'progress',
- templateName: 'components/basic-table/progress-cell'
- },
- {
id: 'status',
headerCellName: 'Status',
templateName: 'components/basic-table/status-cell',
contentPath: 'status',
+ observePath: true,
getCellContent: function(row) {
var status = row.get('status');
return {
@@ -138,53 +192,92 @@ App.DagIndexController = Em.ObjectController.extend(App.ModelRefreshMixin, {
}
},
{
+ id: 'progress',
+ headerCellName: 'Progress',
+ contentPath: 'progress',
+ observePath: true,
+ templateName: 'components/basic-table/progress-cell'
+ },
+ {
id: 'totalTasks',
headerCellName: 'Total Tasks',
- contentPath: 'totalTasks',
+ contentPath: 'numTasks',
+ observePath: true,
},
{
id: 'succeededTasks',
headerCellName: 'Succeeded Tasks',
- contentPath: 'succeededTasks',
+ contentPath: 'sucessfulTasks',
+ observePath: true,
},
{
id: 'runningTasks',
headerCellName: 'Running Tasks',
contentPath: 'runningTasks',
+ observePath: true,
},
{
id: 'pendingTasks',
headerCellName: 'Pending Tasks',
contentPath: 'pendingTasks',
+ observePath: true,
},
{
id: 'failedTasks',
headerCellName: 'Failed Task Attempts',
contentPath: 'failedTaskAttempts',
+ observePath: true,
},
{
id: 'killedTasks',
headerCellName: 'Killed Task Attempts',
contentPath: 'killedTaskAttempts',
+ observePath: true,
}
]);
- }.property('id'),
+ }.property('vertexIdToNameMap'),
- load: function () {
- var dag = this.get('controllers.dag.model'),
- controller = this.get('controllers.dag'),
- t = this;
- t.set('loading', true);
- dag.reload().then(function () {
- return controller.loadAdditional(dag);
- }).catch(function(error){
- Em.Logger.error(error);
- var err = App.Helpers.misc.formatError(error, defaultErrMsg);
- var msg = 'error code: %@, message: %@'.fmt(err.errCode, err.msg);
- App.Helpers.ErrorBar.getInstance().show(msg, err.details);
- });
+ actions: {
+ downloadDagJson: function() {
+ var dagID = this.get('id');
+ var downloader = App.Helpers.misc.downloadDAG(this.get('id'), {
+ batchSize: 500,
+ onSuccess: function() {
+ Bootstrap.ModalManager.close('downloadModal');
+ },
+ onFailure: function() {
+ $('#modalMessage').html('<i class="fa fa-lg fa-exclamation-circle margin-small-horizontal" ' +
+ 'style="color:red"></i> Error downloading data');
+ }
+ });
+ this.set('tmpDownloader', downloader);
+ var modalDialogView = Ember.View.extend({
+ template: Em.Handlebars.compile(
+ '<p id="modalMessage"><i class="fa fa-lg fa-spinner fa-spin margin-small-horizontal" ' +
+ 'style="color:green"></i>Downloading data for dag %@</p>'.fmt(dagID)
+ )
+ });
+ var buttons = [
+ Ember.Object.create({title: 'Cancel', dismiss: 'modal', clicked: 'cancelDownload'})
+ ];
+ Bootstrap.ModalManager.open('downloadModal', 'Download data',
+ modalDialogView, buttons, this);
+ },
+
+ cancelDownload: function() {
+ var currentDownloader = this.get('tmpDownloader');
+ if (!!currentDownloader) {
+ currentDownloader.cancel();
+ }
+ this.set('tmpDownloader', undefined);
+ }
},
+ dagRunning: function () {
+ var progress = this.get('dagProgress');
+ return progress != null && progress < 1;
+ }.property('dagProgress'),
+
taskIconStatus: function() {
return App.Helpers.misc.getStatusClassForEntity(this.get('model.status'),
this.get('hasFailedTaskAttempts'));
@@ -246,22 +339,4 @@ App.DagIndexController = Em.ObjectController.extend(App.ModelRefreshMixin, {
}
}.property('appContextInfo.appType'),
- updateAMInfo: function() {
- var status = this.get('amDagInfo.status');
- progress = this.get('amDagInfo.progress'),
- infoUpdated = false;
- if (!Em.isNone(status)) {
- this.set('status', status);
- infoUpdated = true;
- }
-
- if (!Em.isNone(progress)) {
- this.set('progress', progress);
- infoUpdated = true;
- }
-
- if (infoUpdated) {
- Em.tryInvoke(this.get('model'), 'didLoad');
- }
- }.observes('amDagInfo', 'amDagInfo._amInfoLastUpdatedTime')
});
http://git-wip-us.apache.org/repos/asf/tez/blob/d7ba1098/tez-ui/src/main/webapp/app/scripts/controllers/dag_vertices.js
----------------------------------------------------------------------
diff --git a/tez-ui/src/main/webapp/app/scripts/controllers/dag_vertices.js b/tez-ui/src/main/webapp/app/scripts/controllers/dag_vertices.js
index f25c59e..44d29da 100644
--- a/tez-ui/src/main/webapp/app/scripts/controllers/dag_vertices.js
+++ b/tez-ui/src/main/webapp/app/scripts/controllers/dag_vertices.js
@@ -103,7 +103,11 @@ App.DagVerticesController = App.TablePageController.extend({
vertexIds: runningVerticesIdx.join(',')
}
}).then(function(vertexProgressInfo) {
- that.set('controllers.dag.amVertexInfo', vertexProgressInfo);
+ App.Helpers.emData.mergeRecords(
+ that.get('displayedRecords'),
+ vertexProgressInfo,
+ ['progress']
+ );
}).catch(function(error) {
Em.Logger.debug("failed to fetch vertex progress")
});
http://git-wip-us.apache.org/repos/asf/tez/blob/d7ba1098/tez-ui/src/main/webapp/app/scripts/controllers/polling-controller.js
----------------------------------------------------------------------
diff --git a/tez-ui/src/main/webapp/app/scripts/controllers/polling-controller.js b/tez-ui/src/main/webapp/app/scripts/controllers/polling-controller.js
index c15db57..507ee49 100644
--- a/tez-ui/src/main/webapp/app/scripts/controllers/polling-controller.js
+++ b/tez-ui/src/main/webapp/app/scripts/controllers/polling-controller.js
@@ -61,6 +61,7 @@ App.PollingController = Em.ObjectController.extend({
},
applicationComplete: function () {
+ this.set('pollster.polledRecords', null);
if(this.load) {
this.load();
}
http://git-wip-us.apache.org/repos/asf/tez/blob/d7ba1098/tez-ui/src/main/webapp/app/scripts/controllers/table-page-controller.js
----------------------------------------------------------------------
diff --git a/tez-ui/src/main/webapp/app/scripts/controllers/table-page-controller.js b/tez-ui/src/main/webapp/app/scripts/controllers/table-page-controller.js
index a91dafc..285cc69 100644
--- a/tez-ui/src/main/webapp/app/scripts/controllers/table-page-controller.js
+++ b/tez-ui/src/main/webapp/app/scripts/controllers/table-page-controller.js
@@ -46,6 +46,14 @@ App.TablePageController = App.PollingController.extend(
this.set('pollster.targetRecords', this.get('rowsDisplayed'));
}.observes('rowsDisplayed', 'pollster'),
+ parentStatusObserver: function () {
+ var parentStatus = this.get('status');
+ if(parentStatus && parentStatus != 'RUNNING') {
+ this.get('pollster').stop();
+ this.loadData(true);
+ }
+ }.observes('status'),
+
applicationComplete: function () {
this.loadData(true);
},
http://git-wip-us.apache.org/repos/asf/tez/blob/d7ba1098/tez-ui/src/main/webapp/app/scripts/helpers/em-data.js
----------------------------------------------------------------------
diff --git a/tez-ui/src/main/webapp/app/scripts/helpers/em-data.js b/tez-ui/src/main/webapp/app/scripts/helpers/em-data.js
new file mode 100644
index 0000000..5c4dadc
--- /dev/null
+++ b/tez-ui/src/main/webapp/app/scripts/helpers/em-data.js
@@ -0,0 +1,59 @@
+/**
+ * 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.
+ */
+
+App.Helpers.emData = {
+ /**
+ * Merge data from an array of records to another
+ * @param target {Array} Target record array
+ * @param source {Array} Source record array
+ * @param mergeProps {Array} Array of strings of property names to be merged
+ * @return true if merge was success, else false
+ */
+ mergeRecords: function (target, source, mergeProps) {
+
+ if(source && target && mergeProps) {
+ target.forEach(function (row) {
+ var info = source.findBy('id', row.get('id')),
+ merge = !!info;
+
+ if(merge && row.get('progress') && info.get('progress')) {
+ if(row.get('progress') >= info.get('progress')) {
+ merge = false;
+ }
+ }
+
+ if(merge) {
+ row.setProperties(info.getProperties.apply(info, mergeProps));
+
+ if(info.get('counters')) {
+ row.set('counterGroups',
+ App.Helpers.misc.mergeCounterInfo(
+ row.get('counterGroups'),
+ info.get('counters')
+ ).slice(0)
+ );
+ }
+
+ row.didLoad();// To update the record time stamp
+ }
+ });
+ return true;
+ }
+ return false;
+ }
+};
http://git-wip-us.apache.org/repos/asf/tez/blob/d7ba1098/tez-ui/src/main/webapp/app/scripts/helpers/entity-array-pollster.js
----------------------------------------------------------------------
diff --git a/tez-ui/src/main/webapp/app/scripts/helpers/entity-array-pollster.js b/tez-ui/src/main/webapp/app/scripts/helpers/entity-array-pollster.js
index 31181be..4cf97cf 100644
--- a/tez-ui/src/main/webapp/app/scripts/helpers/entity-array-pollster.js
+++ b/tez-ui/src/main/webapp/app/scripts/helpers/entity-array-pollster.js
@@ -37,20 +37,14 @@ App.Helpers.EntityArrayPollster = App.Helpers.Pollster.extend({
start: function(interval) {
if(!this.get('isRunning')) {
- if (!!interval && interval > 1000) {
- this.set('_interval', interval)
- }
-
+ this._super(true, interval);
this.set('isRunning', true);
-
- this.onPoll();
- this.set('timer', this.schedule(this.onPoll, true));
}
},
stop: function() {
if(this.get('isRunning')) {
- Ember.run.cancel(this.get('timer'));
+ this._super();
this.set('isRunning', false);
}
},
@@ -68,7 +62,9 @@ App.Helpers.EntityArrayPollster = App.Helpers.Pollster.extend({
},
_optionObserver: function () {
- Em.run.later(this, this.onPoll, 10);
+ if(this.get('options')) {
+ Em.run.later(this, this.onPoll, 10);
+ }
}.observes('options'),
_callIfRunning: function (that, funName) {
@@ -94,37 +90,10 @@ App.Helpers.EntityArrayPollster = App.Helpers.Pollster.extend({
},
mergeToTarget: function () {
- var polledRecords = this.get('polledRecords'),
- targetRecords = this.get('targetRecords'),
- mergeProperties = this.get('mergeProperties') || [];
-
- if(polledRecords && targetRecords) {
- targetRecords.forEach(function (row) {
- var info = polledRecords.findBy('id', row.get('id')),
- merge = !!info;
-
- row.didLoad();
-
- if(merge && row.get('progress') && info.get('progress')) {
- if(row.get('progress') >= info.get('progress')) {
- merge = false;
- }
- }
-
- if(merge) {
- row.setProperties(info.getProperties.apply(info, mergeProperties));
-
- if(info.get('counters')) {
- row.set('counterGroups',
- App.Helpers.misc.mergeCounterInfo(
- row.get('counterGroups'),
- info.get('counters')
- ).slice(0)
- );
- }
-
- }
- });
- }
+ App.Helpers.emData.mergeRecords(
+ this.get('targetRecords'),
+ this.get('polledRecords'),
+ this.get('mergeProperties') || []
+ );
}.observes('targetRecords').on('init')
});
http://git-wip-us.apache.org/repos/asf/tez/blob/d7ba1098/tez-ui/src/main/webapp/app/scripts/models/TimelineRestAdapter.js
----------------------------------------------------------------------
diff --git a/tez-ui/src/main/webapp/app/scripts/models/TimelineRestAdapter.js b/tez-ui/src/main/webapp/app/scripts/models/TimelineRestAdapter.js
index e7fe876..d54c8b9 100644
--- a/tez-ui/src/main/webapp/app/scripts/models/TimelineRestAdapter.js
+++ b/tez-ui/src/main/webapp/app/scripts/models/TimelineRestAdapter.js
@@ -94,6 +94,13 @@ var timelineJsonToDagMap = {
name: 'primaryfilters.dagName.0',
user: 'primaryfilters.user.0',
status: 'otherinfo.status',
+
+ progress: {
+ custom: function(source) {
+ return Em.get(source, 'otherinfo.status') == 'SUCCEEDED' ? 1 : null;
+ }
+ },
+
containerLogs: {
custom: function(source) {
@@ -254,6 +261,16 @@ var timelineJsonToVertexMap = {
return Em.get(source, 'otherinfo.status') == 'SUCCEEDED' ? 1 : null;
}
},
+ runningTasks: {
+ custom: function(source) {
+ return Em.get(source, 'otherinfo.status') == 'SUCCEEDED' ? 0 : null;
+ }
+ },
+ pendingTasks: {
+ custom: function(source) {
+ return Em.get(source, 'otherinfo.status') == 'SUCCEEDED' ? 0 : null;
+ }
+ },
status: 'otherinfo.status',
hasFailedTaskAttempts: {
@@ -266,6 +283,9 @@ var timelineJsonToVertexMap = {
},
diagnostics: 'otherinfo.diagnostics',
+ failedTaskAttempts: 'otherinfo.numFailedTaskAttempts',
+ killedTaskAttempts: 'otherinfo.numKilledTaskAttempts',
+
failedTasks: 'otherinfo.numFailedTasks',
sucessfulTasks: 'otherinfo.numSucceededTasks',
numTasks: 'otherinfo.numTasks',
@@ -570,16 +590,30 @@ App.VertexProgressSerializer = App.DagProgressSerializer = DS.RESTSerializer.ext
App.DagInfoSerializer = DS.RESTSerializer.extend({
normalizePayload: function(rawPayload) {
return {
- dagInfo : rawPayload.dag
+ dagInfo : [rawPayload.dag]
}
}
});
App.VertexInfoSerializer = DS.RESTSerializer.extend({
+ map: {
+ id: 'id',
+ progress: 'progress',
+ status: 'status',
+ numTasks: 'totalTasks',
+ runningTasks: 'runningTasks',
+ sucessfulTasks: 'succeededTasks',
+ failedTaskAttempts: 'failedTaskAttempts',
+ killedTaskAttempts: 'killedTaskAttempts',
+ counters: 'counters'
+ },
normalizePayload: function(rawPayload) {
return {
vertexInfo : rawPayload.vertices
}
+ },
+ normalize: function(type, hash, prop) {
+ return Em.JsonMapper.map(hash, this.get('map'));
}
});
@@ -620,4 +654,4 @@ App.ClusterAppSerializer = App.TimelineSerializer.extend({
normalize: function(type, hash, prop) {
return Em.JsonMapper.map(hash, this.get('map'));
}
-});
+});
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/tez/blob/d7ba1098/tez-ui/src/main/webapp/app/scripts/models/dag.js
----------------------------------------------------------------------
diff --git a/tez-ui/src/main/webapp/app/scripts/models/dag.js b/tez-ui/src/main/webapp/app/scripts/models/dag.js
index a21b983..0457157 100644
--- a/tez-ui/src/main/webapp/app/scripts/models/dag.js
+++ b/tez-ui/src/main/webapp/app/scripts/models/dag.js
@@ -50,6 +50,8 @@ App.Dag = App.AbstractEntity.extend({
tezApp: DS.belongsTo('tezApp'),
appDetail: DS.belongsTo('appDetail'),
+ progress: DS.attr('number'),
+
// status
status: DS.attr('string'),
hasFailedTaskAttempts: DS.attr('boolean'),
@@ -215,9 +217,14 @@ App.Vertex = App.AbstractEntity.extend({
failedTasks: DS.attr('number'),
sucessfulTasks: DS.attr('number'),
+ runningTasks: DS.attr('number'),
+ pendingTasks: DS.attr('number'),
numTasks: DS.attr('number'),
killedTasks: DS.attr('number'),
+ failedTaskAttempts: DS.attr('number'),
+ killedTaskAttempts: DS.attr('number'),
+
diagnostics: DS.attr('string'),
counterGroups: DS.attr('array'),
@@ -434,14 +441,15 @@ App.VertexInfo = DS.Model.extend({
progress: DS.attr('number'),
status: DS.attr('string'),
- totalTasks: DS.attr('number'),
+ numTasks: DS.attr('number'),
runningTasks: DS.attr('number'),
- succeededTasks: DS.attr('number'),
+ sucessfulTasks: DS.attr('number'),
failedTaskAttempts: DS.attr('number'),
killedTaskAttempts: DS.attr('number'),
+
pendingTasks: function() {
- return this.get('totalTasks') - this.get('runningTasks') - this.get('succeededTasks');
- }.property('totalTasks', 'runningTasks', 'succeededTasks'),
+ return this.get('numTasks') - this.get('runningTasks') - this.get('sucessfulTasks');
+ }.property('numTasks', 'runningTasks', 'sucessfulTasks'),
counters: DS.attr('object')
});
http://git-wip-us.apache.org/repos/asf/tez/blob/d7ba1098/tez-ui/src/main/webapp/app/scripts/router.js
----------------------------------------------------------------------
diff --git a/tez-ui/src/main/webapp/app/scripts/router.js b/tez-ui/src/main/webapp/app/scripts/router.js
index 1f7f646..ab551a1 100644
--- a/tez-ui/src/main/webapp/app/scripts/router.js
+++ b/tez-ui/src/main/webapp/app/scripts/router.js
@@ -155,7 +155,6 @@ App.DagRoute = Em.Route.extend({
},
setupController: setupControllerFactory('Dag: %@ (%@)', 'name', 'id'),
resetController: function() {
- this.controller.dostopAMInfoUpdateService();
if(this.controller.reset) {
this.controller.reset();
}
@@ -314,6 +313,15 @@ App.TezAppConfigsRoute = Em.Route.extend({
});
/* --- Shared routes --- */
+App.DagIndexRoute = Em.Route.extend({
+ resetController: function () {
+ if(this.controller.reset) {
+ this.controller.reset();
+ }
+ },
+ setupController: setupControllerFactory()
+});
+
App.DagTasksRoute =
App.DagVerticesRoute =
App.DagTaskAttemptsRoute =
http://git-wip-us.apache.org/repos/asf/tez/blob/d7ba1098/tez-ui/src/main/webapp/app/templates/dag/index.hbs
----------------------------------------------------------------------
diff --git a/tez-ui/src/main/webapp/app/templates/dag/index.hbs b/tez-ui/src/main/webapp/app/templates/dag/index.hbs
index f7ec99f..c287584 100644
--- a/tez-ui/src/main/webapp/app/templates/dag/index.hbs
+++ b/tez-ui/src/main/webapp/app/templates/dag/index.hbs
@@ -95,22 +95,24 @@
</div>
</div>
-{{#if liveData}}
+{{#if data.content}}
<br/>
<h4>DAG Progress
- ( Vertices {{completedVertices}}/{{liveData.length}} )
- {{#if totalTasks}}
- ( Tasks {{succeededTasks}}/{{totalTasks}} )
+ {{#if progressDetails}}
+ ( Vertices {{progressDetails.completedVertices}}/{{data.length}} )
+ {{#if progressDetails.totalTasks}}
+ ( Tasks {{progressDetails.succeededTasks}}/{{progressDetails.totalTasks}} )
+ {{/if}}
+ :
+ {{progressStr}}
{{/if}}
- :
- {{progressStr}}
</h4>
{{bs-progress-animated progressDecimal=progress}}
{{basic-table-component
- columns=liveColumns
- rows=liveData
- rowCount=liveData.length
+ columns=defaultColumnConfigs
+ rows=data.content
+ rowCount=data.content.length
enableStatus=false
enableSort=true