lastIDSuccessCallback: function(data, jqXHR, textStatus) { if(!data.entities[0]){ return; } var lastReceivedID = data.entities[0].entity; if(this.get('lastJobID') == '') { this.set('lastJobID', lastReceivedID); if (this.get('loaded') && App.HiveJob.find().get('length') < 1) { this.set('hasNewJobs', true); } } else if (this.get('lastJobID') !== lastReceivedID) { this.set('lastJobID', lastReceivedID); if(!App.HiveJob.find().findProperty('id', lastReceivedID)) { this.set('hasNewJobs', true); } } },
map : function(json) { var model = this.get('model'); if (!model) { return; } var hiveJob = {}; if (json && json.entity) { var hiveJob = {}; hiveJob.id = json.entity; hiveJob.name = hiveJob.id; hiveJob.startTime = json.starttime; if (typeof(json.endtime) == "undefined") { var i = 0; while (typeof(hiveJob.endTime) == "undefined" && json.events && json.events[i]) { if (json.events[i].eventtype == 'QUERY_COMPLETED') { hiveJob.endTime = json.events[i].timestamp; }; i++; }; } else { hiveJob.endTime = json.endtime; }; json.otherinfo.query = $.parseJSON(json.otherinfo.query); if (json.otherinfo.query && json.otherinfo.query.queryText) { hiveJob.query_text = json.otherinfo.query.queryText; } hiveJob.stages = []; var stagePlans = json.otherinfo.query.queryPlan["STAGE PLANS"]; for ( var stage in stagePlans) { var stageValue = stagePlans[stage]; var stageItem = {}; stageItem.id = stage; stageItem.description = '. '; for (var item in stageValue) { stageItem.description += item; }; hiveJob.stages.push(stageItem); if (stageValue.Tez != null && hiveJob.tezDag == null) { var dagName = stageValue.Tez['DagName:']; // Vertices var vertices = []; var vertexIds = []; var vertexIdMap = {}; for ( var vertexName in stageValue.Tez["Vertices:"]) { var vertex = stageValue.Tez["Vertices:"][vertexName]; var vertexObj = { id : dagName + "/" + vertexName, name : vertexName, incoming_edges : [], outgoing_edges : [] }; vertexIds.push(vertexObj.id); var operatorExtractor = function(obj) { var ops = []; if ($.isArray(obj)) { obj.forEach(function(o) { ops = ops.concat(operatorExtractor(o)); }); } else { for ( var key in obj) { ops.push(key); if (obj[key].children != null) { ops = ops.concat(operatorExtractor(obj[key].children)); } } } return ops; } if (vertex["Map Operator Tree:"] != null) { vertexObj.type = App.TezDagVertexType.MAP; vertexObj.operations = operatorExtractor(vertex["Map Operator Tree:"]); vertexObj.operation_plan = JSON.stringify(vertex["Map Operator Tree:"], undefined, " "); } else if (vertex["Reduce Operator Tree:"] != null) { vertexObj.type = App.TezDagVertexType.REDUCE; vertexObj.operations = operatorExtractor(vertex["Reduce Operator Tree:"]); vertexObj.operation_plan = JSON.stringify(vertex["Reduce Operator Tree:"], undefined, " "); } else if (vertex["Vertex:"] != null && vertexName==vertex['Vertex:']) { vertexObj.type = App.TezDagVertexType.UNION; } vertexIdMap[vertexObj.id] = vertexObj; vertices.push(vertexObj); } // Edges var edges = []; var edgeIds = []; for ( var childVertex in stageValue.Tez["Edges:"]) { var childVertices = stageValue.Tez["Edges:"][childVertex]; if (!$.isArray(childVertices)) { // Single edge given as object instead of array childVertices = [ childVertices ]; } childVertices.forEach(function(e) { var parentVertex = e.parent; if (e.type == 'CONTAINS') { var parentVertexNode = vertexIdMap[dagName + "/" + parentVertex]; if (parentVertexNode != null && parentVertexNode.type == App.TezDagVertexType.UNION) { // We flip the edges for Union vertices var tmp = childVertex; childVertex = parentVertex; parentVertex = tmp; } } var edgeObj = { id : dagName + "/" + parentVertex + "-" + childVertex, from_vertex_id : dagName + "/" + parentVertex, to_vertex_id : dagName + "/" + childVertex }; vertexIdMap[edgeObj.from_vertex_id].outgoing_edges.push(edgeObj.id); vertexIdMap[edgeObj.to_vertex_id].incoming_edges.push(edgeObj.id); edgeIds.push(edgeObj.id); switch (e.type) { case "BROADCAST_EDGE": edgeObj.edge_type = App.TezDagEdgeType.BROADCAST; break; case "SIMPLE_EDGE": edgeObj.edge_type = App.TezDagEdgeType.SCATTER_GATHER; break; case "CONTAINS": edgeObj.edge_type = App.TezDagEdgeType.CONTAINS; break; default: break; } edges.push(edgeObj); }); } // Create records var tezDag = { id : dagName, name : dagName, stage : stage, vertices : vertexIds, edges : edgeIds } // Once the DAG is loaded, we do not need to // reload as the structure does not change. Reloading // here causes missing data (got from other calls) // to propagate into UI - causing flashing. var newVertices = []; var newEdges = []; vertices.forEach(function(v) { var vertexRecord = App.TezDagVertex.find(v.id); if (!vertexRecord.get('isLoaded')) { newVertices.push(v); } }); edges.forEach(function(e) { var edgeRecord = App.TezDagEdge.find(e.id); if (!edgeRecord.get('isLoaded')) { newEdges.push(e); } }); App.store.loadMany(App.TezDagVertex, newVertices); App.store.loadMany(App.TezDagEdge, newEdges); var dagRecord = App.TezDag.find(tezDag.id); if (!dagRecord.get('isLoaded')) { App.store.load(App.TezDag, tezDag); } hiveJob.tezDag = tezDag.id; } } if(App.HiveJob.find().get('content').length == 0){ App.store.load(model, hiveJob); } var hiveJobRecord = App.HiveJob.find(hiveJob.id); if (hiveJobRecord != null) { hiveJobRecord.set('stages', hiveJob.stages.sortProperty('id')); hiveJobRecord.set('startTime', hiveJob.startTime); hiveJobRecord.set('endTime', hiveJob.endTime); if (hiveJob.tezDag != null) { // Some hive queries dont use Tez hiveJobRecord.set('tezDag', App.TezDag.find(hiveJob.tezDag)); } } } },
contentAndSortObserver : function() { Ember.run.once(this, 'contentAndSortUpdater'); if(App.HiveJob.find().findProperty('id', this.get('lastJobID'))) { this.set('hasNewJobs', false); } }.observes('content.length', '*****@*****.**', '*****@*****.**', '*****@*****.**', 'sortProperties', 'sortAscending'),
* 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', /** * Unsorted ArrayProxy */ content: App.HiveJob.find(), /** * Sorted ArrayProxy */ sortedContent: [], contentAndSortObserver : function() { Ember.run.once(this, 'contentAndSortUpdater'); if(App.HiveJob.find().findProperty('id', this.get('lastJobID'))) { this.set('hasNewJobs', false); } }.observes('content.length', '*****@*****.**', '*****@*****.**', '*****@*****.**', 'sortProperties', 'sortAscending'), contentAndSortUpdater: function() { this.set('sortingDone', false);