Prechádzať zdrojové kódy

AMBARI-4829. Tez DAG diagram should have zoom in/out and pan actions. (srimanth)

Srimanth Gunturi 11 rokov pred
rodič
commit
b269ba5f49

Rozdielové dáta súboru neboli zobrazené, pretože súbor je príliš veľký
+ 3 - 3
ambari-web/app/assets/data/jobs/hive-queries.json


Rozdielové dáta súboru neboli zobrazené, pretože súbor je príliš veľký
+ 1 - 1
ambari-web/app/assets/data/jobs/hive-query-2.json


+ 98 - 106
ambari-web/app/assets/data/jobs/tezDag-name-to-id.json

@@ -1,41 +1,41 @@
 {
   "entities": [
     {
-      "starttime": 1392936257904,
+      "starttime": 1393031617162,
       "events": [
         {
-          "timestamp": 1392936280537,
+          "timestamp": 1393031624957,
           "eventtype": "DAG_FINISHED",
           "eventinfo": {}
         },
         {
-          "timestamp": 1392936258013,
+          "timestamp": 1393031617405,
           "eventtype": "DAG_STARTED",
           "eventinfo": {}
         },
         {
-          "timestamp": 1392936257968,
+          "timestamp": 1393031617401,
           "eventtype": "DAG_INITIALIZED",
           "eventinfo": {}
         },
         {
-          "timestamp": 1392936257904,
+          "timestamp": 1393031617162,
           "eventtype": "DAG_SUBMITTED",
           "eventinfo": {}
         }
       ],
       "otherinfo": {
-        "startTime": 1392936258013,
+        "startTime": 1393031617405,
         "status": "SUCCEEDED",
-        "initTime": 1392936257968,
-        "timeTaken": 22524,
+        "initTime": 1393031617401,
+        "timeTaken": 7552,
         "dagPlan": {
-          "dagName": "hive_20140220172727_9cb1b1a3-25bd-457b-81dc-60544c941cfa:11",
+          "dagName": "root_20140221171313_8bdaf452-0a61-4cff-bd24-63662e2c3dcc:3",
           "edges": [
             {
-              "edgeId": "167296427",
-              "inputVertexName": "Reducer 3",
-              "outputVertexName": "Reducer 4",
+              "edgeId": "167637864",
+              "inputVertexName": "Map 2",
+              "outputVertexName": "Reducer 3",
               "dataMovementType": "SCATTER_GATHER",
               "dataSourceType": "PERSISTED",
               "schedulingType": "SEQUENTIAL",
@@ -43,9 +43,9 @@
               "edgeDestinationClass": "org.apache.tez.runtime.library.input.ShuffledMergedInputLegacy"
             },
             {
-              "edgeId": "473758957",
-              "inputVertexName": "Map 1",
-              "outputVertexName": "Map 6",
+              "edgeId": "702054850",
+              "inputVertexName": "Map 4",
+              "outputVertexName": "Map 2",
               "dataMovementType": "BROADCAST",
               "dataSourceType": "PERSISTED",
               "schedulingType": "SEQUENTIAL",
@@ -53,19 +53,9 @@
               "edgeDestinationClass": "org.apache.tez.runtime.library.input.ShuffledUnorderedKVInput"
             },
             {
-              "edgeId": "2076565304",
-              "inputVertexName": "Reducer 4",
-              "outputVertexName": "Reducer 5",
-              "dataMovementType": "SCATTER_GATHER",
-              "dataSourceType": "PERSISTED",
-              "schedulingType": "SEQUENTIAL",
-              "edgeSourceClass": "org.apache.tez.runtime.library.output.OnFileSortedOutput",
-              "edgeDestinationClass": "org.apache.tez.runtime.library.input.ShuffledMergedInputLegacy"
-            },
-            {
-              "edgeId": "974132657",
-              "inputVertexName": "Reducer 5",
-              "outputVertexName": "Map 1",
+              "edgeId": "1016858596",
+              "inputVertexName": "Map 1",
+              "outputVertexName": "Map 2",
               "dataMovementType": "BROADCAST",
               "dataSourceType": "PERSISTED",
               "schedulingType": "SEQUENTIAL",
@@ -73,113 +63,111 @@
               "edgeDestinationClass": "org.apache.tez.runtime.library.input.ShuffledUnorderedKVInput"
             },
             {
-              "edgeId": "1784432228",
-              "inputVertexName": "Map 2",
-              "outputVertexName": "Reducer 3",
-              "dataMovementType": "SCATTER_GATHER",
+              "edgeId": "1012906348",
+              "inputVertexName": "Map 6",
+              "outputVertexName": "Map 2",
+              "dataMovementType": "BROADCAST",
               "dataSourceType": "PERSISTED",
               "schedulingType": "SEQUENTIAL",
-              "edgeSourceClass": "org.apache.tez.runtime.library.output.OnFileSortedOutput",
-              "edgeDestinationClass": "org.apache.tez.runtime.library.input.ShuffledMergedInputLegacy"
+              "edgeSourceClass": "org.apache.tez.runtime.library.output.OnFileUnorderedKVOutput",
+              "edgeDestinationClass": "org.apache.tez.runtime.library.input.ShuffledUnorderedKVInput"
             },
             {
-              "edgeId": "54634294",
-              "inputVertexName": "Map 6",
-              "outputVertexName": "Reducer 7",
-              "dataMovementType": "SCATTER_GATHER",
+              "edgeId": "591684997",
+              "inputVertexName": "Map 5",
+              "outputVertexName": "Map 2",
+              "dataMovementType": "BROADCAST",
               "dataSourceType": "PERSISTED",
               "schedulingType": "SEQUENTIAL",
-              "edgeSourceClass": "org.apache.tez.runtime.library.output.OnFileSortedOutput",
-              "edgeDestinationClass": "org.apache.tez.runtime.library.input.ShuffledMergedInputLegacy"
+              "edgeSourceClass": "org.apache.tez.runtime.library.output.OnFileUnorderedKVOutput",
+              "edgeDestinationClass": "org.apache.tez.runtime.library.input.ShuffledUnorderedKVInput"
             }
           ],
           "vertices": [
             {
-              "vertexName": "Reducer 7",
+              "vertexName": "Reducer 3",
               "processorClass": "org.apache.hadoop.hive.ql.exec.tez.ReduceTezProcessor",
               "inEdgeIds": [
-                "54634294"
+                "167637864"
               ],
               "additionalOutputs": [
                 {
-                  "name": "out_Reducer 7",
+                  "name": "out_Reducer 3",
                   "class": "org.apache.tez.mapreduce.output.MROutput"
                 }
               ]
             },
             {
-              "vertexName": "Map 6",
+              "vertexName": "Map 2",
               "processorClass": "org.apache.hadoop.hive.ql.exec.tez.MapTezProcessor",
               "inEdgeIds": [
-                "473758957"
+                "1012906348",
+                "591684997",
+                "702054850",
+                "1016858596"
               ],
               "outEdgeIds": [
-                "54634294"
+                "167637864"
               ],
               "additionalInputs": [
                 {
-                  "name": "players",
+                  "name": "store_sales",
                   "class": "org.apache.tez.mapreduce.input.MRInputLegacy",
                   "initializer": "org.apache.tez.mapreduce.common.MRInputAMSplitGenerator"
                 }
               ]
             },
             {
-              "vertexName": "Map 1",
+              "vertexName": "Map 6",
               "processorClass": "org.apache.hadoop.hive.ql.exec.tez.MapTezProcessor",
-              "inEdgeIds": [
-                "974132657"
-              ],
               "outEdgeIds": [
-                "473758957"
+                "1012906348"
               ],
               "additionalInputs": [
                 {
-                  "name": "school",
+                  "name": "date_dim",
                   "class": "org.apache.tez.mapreduce.input.MRInputLegacy",
                   "initializer": "org.apache.tez.mapreduce.common.MRInputAMSplitGenerator"
                 }
               ]
             },
             {
-              "vertexName": "Reducer 5",
-              "processorClass": "org.apache.hadoop.hive.ql.exec.tez.ReduceTezProcessor",
-              "inEdgeIds": [
-                "2076565304"
-              ],
+              "vertexName": "Map 5",
+              "processorClass": "org.apache.hadoop.hive.ql.exec.tez.MapTezProcessor",
               "outEdgeIds": [
-                "974132657"
-              ]
-            },
-            {
-              "vertexName": "Reducer 4",
-              "processorClass": "org.apache.hadoop.hive.ql.exec.tez.ReduceTezProcessor",
-              "inEdgeIds": [
-                "167296427"
+                "591684997"
               ],
-              "outEdgeIds": [
-                "2076565304"
+              "additionalInputs": [
+                {
+                  "name": "customer_demographics",
+                  "class": "org.apache.tez.mapreduce.input.MRInputLegacy",
+                  "initializer": "org.apache.tez.mapreduce.common.MRInputAMSplitGenerator"
+                }
               ]
             },
             {
-              "vertexName": "Reducer 3",
-              "processorClass": "org.apache.hadoop.hive.ql.exec.tez.ReduceTezProcessor",
-              "inEdgeIds": [
-                "1784432228"
-              ],
+              "vertexName": "Map 4",
+              "processorClass": "org.apache.hadoop.hive.ql.exec.tez.MapTezProcessor",
               "outEdgeIds": [
-                "167296427"
+                "702054850"
+              ],
+              "additionalInputs": [
+                {
+                  "name": "item",
+                  "class": "org.apache.tez.mapreduce.input.MRInputLegacy",
+                  "initializer": "org.apache.tez.mapreduce.common.MRInputAMSplitGenerator"
+                }
               ]
             },
             {
-              "vertexName": "Map 2",
+              "vertexName": "Map 1",
               "processorClass": "org.apache.hadoop.hive.ql.exec.tez.MapTezProcessor",
               "outEdgeIds": [
-                "1784432228"
+                "1016858596"
               ],
               "additionalInputs": [
                 {
-                  "name": "school",
+                  "name": "store",
                   "class": "org.apache.tez.mapreduce.input.MRInputLegacy",
                   "initializer": "org.apache.tez.mapreduce.common.MRInputAMSplitGenerator"
                 }
@@ -188,7 +176,7 @@
           ],
           "version": 1
         },
-        "endTime": 1392936280537,
+        "endTime": 1393031624957,
         "diagnostics": "",
         "counters": {
           "counterGroups": [
@@ -199,17 +187,17 @@
                 {
                   "counterName": "TOTAL_LAUNCHED_TASKS",
                   "counterDisplayName": "TOTAL_LAUNCHED_TASKS",
-                  "counterValue": 7
+                  "counterValue": 180
                 },
                 {
                   "counterName": "DATA_LOCAL_TASKS",
                   "counterDisplayName": "DATA_LOCAL_TASKS",
-                  "counterValue": 2
+                  "counterValue": 162
                 },
                 {
                   "counterName": "RACK_LOCAL_TASKS",
                   "counterDisplayName": "RACK_LOCAL_TASKS",
-                  "counterValue": 1
+                  "counterValue": 17
                 }
               ]
             },
@@ -220,12 +208,12 @@
                 {
                   "counterName": "FILE_BYTES_READ",
                   "counterDisplayName": "FILE: BYTES_READ",
-                  "counterValue": 4839
+                  "counterValue": 0
                 },
                 {
                   "counterName": "FILE_BYTES_WRITTEN",
                   "counterDisplayName": "FILE: BYTES_WRITTEN",
-                  "counterValue": 11213
+                  "counterValue": 6380254
                 },
                 {
                   "counterName": "FILE_READ_OPS",
@@ -245,17 +233,17 @@
                 {
                   "counterName": "HDFS_BYTES_READ",
                   "counterDisplayName": "HDFS: BYTES_READ",
-                  "counterValue": 306084
+                  "counterValue": 1291686552
                 },
                 {
                   "counterName": "HDFS_BYTES_WRITTEN",
                   "counterDisplayName": "HDFS: BYTES_WRITTEN",
-                  "counterValue": 622
+                  "counterValue": 8917
                 },
                 {
                   "counterName": "HDFS_READ_OPS",
                   "counterDisplayName": "HDFS: READ_OPS",
-                  "counterValue": 5
+                  "counterValue": 14144
                 },
                 {
                   "counterName": "HDFS_LARGE_READ_OPS",
@@ -276,22 +264,22 @@
                 {
                   "counterName": "MAP_INPUT_RECORDS",
                   "counterDisplayName": "MAP_INPUT_RECORDS",
-                  "counterValue": 7648
+                  "counterValue": 110379
                 },
                 {
                   "counterName": "MAP_OUTPUT_RECORDS",
                   "counterDisplayName": "MAP_OUTPUT_RECORDS",
-                  "counterValue": 170
+                  "counterValue": 394097
                 },
                 {
                   "counterName": "MAP_OUTPUT_BYTES",
                   "counterDisplayName": "MAP_OUTPUT_BYTES",
-                  "counterValue": 4475
+                  "counterValue": 34555222
                 },
                 {
                   "counterName": "MAP_OUTPUT_MATERIALIZED_BYTES",
                   "counterDisplayName": "MAP_OUTPUT_MATERIALIZED_BYTES",
-                  "counterValue": 4839
+                  "counterValue": 6136234
                 },
                 {
                   "counterName": "COMBINE_INPUT_RECORDS",
@@ -301,27 +289,27 @@
                 {
                   "counterName": "REDUCE_INPUT_GROUPS",
                   "counterDisplayName": "REDUCE_INPUT_GROUPS",
-                  "counterValue": 90
+                  "counterValue": 104
                 },
                 {
                   "counterName": "REDUCE_SHUFFLE_BYTES",
                   "counterDisplayName": "REDUCE_SHUFFLE_BYTES",
-                  "counterValue": 4839
+                  "counterValue": 6136234
                 },
                 {
                   "counterName": "REDUCE_INPUT_RECORDS",
                   "counterDisplayName": "REDUCE_INPUT_RECORDS",
-                  "counterValue": 98
+                  "counterValue": 1747
                 },
                 {
                   "counterName": "SPILLED_RECORDS",
                   "counterDisplayName": "SPILLED_RECORDS",
-                  "counterValue": 269
+                  "counterValue": 394097
                 },
                 {
                   "counterName": "SHUFFLED_MAPS",
                   "counterDisplayName": "SHUFFLED_MAPS",
-                  "counterValue": 4
+                  "counterValue": 170
                 },
                 {
                   "counterName": "FAILED_SHUFFLE",
@@ -331,32 +319,32 @@
                 {
                   "counterName": "MERGED_MAP_OUTPUTS",
                   "counterDisplayName": "MERGED_MAP_OUTPUTS",
-                  "counterValue": 4
+                  "counterValue": 170
                 },
                 {
                   "counterName": "GC_TIME_MILLIS",
                   "counterDisplayName": "GC_TIME_MILLIS",
-                  "counterValue": 706
+                  "counterValue": 9277
                 },
                 {
                   "counterName": "CPU_MILLISECONDS",
                   "counterDisplayName": "CPU_MILLISECONDS",
-                  "counterValue": -15530
+                  "counterValue": -2881340
                 },
                 {
                   "counterName": "PHYSICAL_MEMORY_BYTES",
                   "counterDisplayName": "PHYSICAL_MEMORY_BYTES",
-                  "counterValue": 1493426176
+                  "counterValue": 238651179008
                 },
                 {
                   "counterName": "VIRTUAL_MEMORY_BYTES",
                   "counterDisplayName": "VIRTUAL_MEMORY_BYTES",
-                  "counterValue": 7776043008
+                  "counterValue": 840369852416
                 },
                 {
                   "counterName": "COMMITTED_HEAP_BYTES",
                   "counterDisplayName": "COMMITTED_HEAP_BYTES",
-                  "counterValue": 1281880064
+                  "counterValue": 273071931392
                 }
               ]
             },
@@ -414,12 +402,12 @@
                 {
                   "counterName": "FILTERED",
                   "counterDisplayName": "FILTERED",
-                  "counterValue": 4921
+                  "counterValue": 0
                 },
                 {
                   "counterName": "PASSED",
                   "counterDisplayName": "PASSED",
-                  "counterValue": 1227
+                  "counterValue": 0
                 }
               ]
             },
@@ -460,10 +448,14 @@
         }
       },
       "primaryfilters": {
-        "dagName": "hive_20140220172727_9cb1b1a3-25bd-457b-81dc-60544c941cfa:11",
-        "user": "hive"
+        "dagName": [
+          null
+        ],
+        "user": [
+          null
+        ]
       },
-      "entity": "dag_1392926503112_0003_1",
+      "entity": "dag_1393012407618_0059_3",
       "entitytype": "TEZ_DAG_ID",
       "relatedentities": {}
     }

+ 8 - 9
ambari-web/app/assets/data/jobs/tezDag.json

@@ -1,16 +1,15 @@
 {
-  "starttime": 1392936257904,
-  "entity": "dag_1392926503112_0003_1",
+  "starttime": 1393031617162,
+  "entity": "dag_1393012407618_0059_3",
   "entitytype": "TEZ_DAG_ID",
   "relatedentities": {
     "TEZ_VERTEX_ID": [
-      "vertex_1392926503112_0003_1_00",
-      "vertex_1392926503112_0003_1_01",
-      "vertex_1392926503112_0003_1_02",
-      "vertex_1392926503112_0003_1_03",
-      "vertex_1392926503112_0003_1_04",
-      "vertex_1392926503112_0003_1_05",
-      "vertex_1392926503112_0003_1_06"
+      "vertex_1393012407618_0059_3_01",
+      "vertex_1393012407618_0059_3_00",
+      "vertex_1393012407618_0059_3_03",
+      "vertex_1393012407618_0059_3_02",
+      "vertex_1393012407618_0059_3_05",
+      "vertex_1393012407618_0059_3_04"
     ]
   }
 }

+ 59 - 99
ambari-web/app/assets/data/jobs/tezDagVertex.json

@@ -1,17 +1,33 @@
 {
-  "starttime": 1392936258722,
+  "starttime": 1393031617901,
   "otherinfo": {
-    "startTime": 1392936259476,
+    "startTime": 1393031617902,
     "status": "SUCCEEDED",
-    "numTasks": 1,
-    "initTime": 1392936258722,
-    "vertexName": "Reducer 7",
-    "timeTaken": 21058,
-    "processorClassName": "org.apache.hadoop.hive.ql.exec.tez.ReduceTezProcessor",
-    "endTime": 1392936280534,
-    "initRequestedTime": 1392936258658,
+    "numTasks": 170,
+    "initTime": 1393031617901,
+    "vertexName": "Map 2",
+    "timeTaken": 6352,
+    "processorClassName": "org.apache.hadoop.hive.ql.exec.tez.MapTezProcessor",
+    "endTime": 1393031624254,
+    "initRequestedTime": 1393031617436,
     "counters": {
       "counterGroups": [
+        {
+          "counterGroupName": "org.apache.tez.common.counters.DAGCounter",
+          "counterGroupDisplayName": "org.apache.tez.common.counters.DAGCounter",
+          "counters": [
+            {
+              "counterName": "DATA_LOCAL_TASKS",
+              "counterDisplayName": "DATA_LOCAL_TASKS",
+              "counterValue": 155
+            },
+            {
+              "counterName": "RACK_LOCAL_TASKS",
+              "counterDisplayName": "RACK_LOCAL_TASKS",
+              "counterValue": 15
+            }
+          ]
+        },
         {
           "counterGroupName": "org.apache.tez.common.counters.FileSystemCounter",
           "counterGroupDisplayName": "File System Counters",
@@ -19,12 +35,12 @@
             {
               "counterName": "FILE_BYTES_READ",
               "counterDisplayName": "FILE: BYTES_READ",
-              "counterValue": 1008
+              "counterValue": 0
             },
             {
               "counterName": "FILE_BYTES_WRITTEN",
               "counterDisplayName": "FILE: BYTES_WRITTEN",
-              "counterValue": 1008
+              "counterValue": 6141674
             },
             {
               "counterName": "FILE_READ_OPS",
@@ -44,17 +60,17 @@
             {
               "counterName": "HDFS_BYTES_READ",
               "counterDisplayName": "HDFS: BYTES_READ",
-              "counterValue": 0
+              "counterValue": 1291299199
             },
             {
               "counterName": "HDFS_BYTES_WRITTEN",
               "counterDisplayName": "HDFS: BYTES_WRITTEN",
-              "counterValue": 622
+              "counterValue": 0
             },
             {
               "counterName": "HDFS_READ_OPS",
               "counterDisplayName": "HDFS: READ_OPS",
-              "counterValue": 2
+              "counterValue": 14094
             },
             {
               "counterName": "HDFS_LARGE_READ_OPS",
@@ -64,7 +80,7 @@
             {
               "counterName": "HDFS_WRITE_OPS",
               "counterDisplayName": "HDFS: WRITE_OPS",
-              "counterValue": 2
+              "counterValue": 0
             }
           ]
         },
@@ -73,139 +89,83 @@
           "counterGroupDisplayName": "org.apache.tez.common.counters.TaskCounter",
           "counters": [
             {
-              "counterName": "MAP_OUTPUT_RECORDS",
-              "counterDisplayName": "MAP_OUTPUT_RECORDS",
-              "counterValue": 0
-            },
-            {
-              "counterName": "COMBINE_INPUT_RECORDS",
-              "counterDisplayName": "COMBINE_INPUT_RECORDS",
-              "counterValue": 0
+              "counterName": "MAP_INPUT_RECORDS",
+              "counterDisplayName": "MAP_INPUT_RECORDS",
+              "counterValue": 108378
             },
             {
-              "counterName": "REDUCE_INPUT_GROUPS",
-              "counterDisplayName": "REDUCE_INPUT_GROUPS",
-              "counterValue": 13
+              "counterName": "MAP_OUTPUT_RECORDS",
+              "counterDisplayName": "MAP_OUTPUT_RECORDS",
+              "counterValue": 394097
             },
             {
-              "counterName": "REDUCE_SHUFFLE_BYTES",
-              "counterDisplayName": "REDUCE_SHUFFLE_BYTES",
-              "counterValue": 1008
+              "counterName": "MAP_OUTPUT_BYTES",
+              "counterDisplayName": "MAP_OUTPUT_BYTES",
+              "counterValue": 34555222
             },
             {
-              "counterName": "REDUCE_INPUT_RECORDS",
-              "counterDisplayName": "REDUCE_INPUT_RECORDS",
-              "counterValue": 19
+              "counterName": "MAP_OUTPUT_MATERIALIZED_BYTES",
+              "counterDisplayName": "MAP_OUTPUT_MATERIALIZED_BYTES",
+              "counterValue": 6136234
             },
             {
               "counterName": "SPILLED_RECORDS",
               "counterDisplayName": "SPILLED_RECORDS",
-              "counterValue": 19
-            },
-            {
-              "counterName": "SHUFFLED_MAPS",
-              "counterDisplayName": "SHUFFLED_MAPS",
-              "counterValue": 1
-            },
-            {
-              "counterName": "FAILED_SHUFFLE",
-              "counterDisplayName": "FAILED_SHUFFLE",
-              "counterValue": 0
-            },
-            {
-              "counterName": "MERGED_MAP_OUTPUTS",
-              "counterDisplayName": "MERGED_MAP_OUTPUTS",
-              "counterValue": 1
+              "counterValue": 394097
             },
             {
               "counterName": "GC_TIME_MILLIS",
               "counterDisplayName": "GC_TIME_MILLIS",
-              "counterValue": 7
+              "counterValue": 9246
             },
             {
               "counterName": "CPU_MILLISECONDS",
               "counterDisplayName": "CPU_MILLISECONDS",
-              "counterValue": -4530
+              "counterValue": -2742060
             },
             {
               "counterName": "PHYSICAL_MEMORY_BYTES",
               "counterDisplayName": "PHYSICAL_MEMORY_BYTES",
-              "counterValue": 245919744
+              "counterValue": 232119492608
             },
             {
               "counterName": "VIRTUAL_MEMORY_BYTES",
               "counterDisplayName": "VIRTUAL_MEMORY_BYTES",
-              "counterValue": 1249353728
+              "counterValue": 793722957824
             },
             {
               "counterName": "COMMITTED_HEAP_BYTES",
               "counterDisplayName": "COMMITTED_HEAP_BYTES",
-              "counterValue": 210309120
-            }
-          ]
-        },
-        {
-          "counterGroupName": "HIVE",
-          "counterGroupDisplayName": "HIVE",
-          "counters": [
-            {
-              "counterName": "CREATED_FILES",
-              "counterDisplayName": "CREATED_FILES",
-              "counterValue": 1
+              "counterValue": 262738477056
             }
           ]
         },
         {
-          "counterGroupName": "Shuffle Errors",
-          "counterGroupDisplayName": "Shuffle Errors",
+          "counterGroupName": "org.apache.hadoop.hive.ql.exec.MapOperator$Counter",
+          "counterGroupDisplayName": "org.apache.hadoop.hive.ql.exec.MapOperator$Counter",
           "counters": [
             {
-              "counterName": "BAD_ID",
-              "counterDisplayName": "BAD_ID",
-              "counterValue": 0
-            },
-            {
-              "counterName": "CONNECTION",
-              "counterDisplayName": "CONNECTION",
-              "counterValue": 0
-            },
-            {
-              "counterName": "IO_ERROR",
-              "counterDisplayName": "IO_ERROR",
-              "counterValue": 0
-            },
-            {
-              "counterName": "WRONG_LENGTH",
-              "counterDisplayName": "WRONG_LENGTH",
-              "counterValue": 0
-            },
-            {
-              "counterName": "WRONG_MAP",
-              "counterDisplayName": "WRONG_MAP",
-              "counterValue": 0
-            },
-            {
-              "counterName": "WRONG_REDUCE",
-              "counterDisplayName": "WRONG_REDUCE",
+              "counterName": "DESERIALIZE_ERRORS",
+              "counterDisplayName": "DESERIALIZE_ERRORS",
               "counterValue": 0
             }
           ]
         },
         {
-          "counterGroupName": "org.apache.hadoop.mapreduce.lib.output.FileOutputFormatCounter",
-          "counterGroupDisplayName": "File Output Format Counters ",
+          "counterGroupName": "org.apache.hadoop.mapreduce.lib.input.FileInputFormatCounter",
+          "counterGroupDisplayName": "File Input Format Counters ",
           "counters": [
             {
-              "counterName": "BYTES_WRITTEN",
-              "counterDisplayName": "Bytes Written",
+              "counterName": "BYTES_READ",
+              "counterDisplayName": "Bytes Read",
               "counterValue": 0
             }
           ]
         }
       ]
     },
-    "startRequestedTime": 1392936259476
+    "startRequestedTime": 1393031617487
   },
-  "entity": "vertex_1392926503112_0003_1_00",
+  "entity": "vertex_1393012407618_0059_3_01",
   "entitytype": "TEZ_VERTEX_ID"
 }

+ 1 - 1
ambari-web/app/mappers/jobs/hive_job_mapper.js

@@ -56,7 +56,7 @@ App.hiveJobMapper = App.QuickDataMapper.create({
       hiveJob.id = json.entity;
       hiveJob.startTime = json.starttime;
       hiveJob.endTime = json.endtime;
-      json.otherinfo.query = $.parseJSON(json.otherinfo.query).query;
+      json.otherinfo.query = $.parseJSON(json.otherinfo.query);
       hiveJob.stages = [];
       var stagePlans = json.otherinfo.query.queryPlan["STAGE PLANS"];
       for ( var stage in stagePlans) {

+ 2 - 2
ambari-web/app/mappers/jobs/hive_jobs_mapper.js

@@ -45,8 +45,8 @@ App.hiveJobsMapper = App.QuickDataMapper.create({
         if (entity.otherinfo && entity.otherinfo.query) {
           hiveJob.has_tez_dag = entity.otherinfo.query.match("\"Tez\".*\"DagName:\"");
           var queryJson = $.parseJSON(entity.otherinfo.query);
-          if (queryJson && queryJson.query) {
-            hiveJob.query_text = queryJson.query.queryText;
+          if (queryJson && queryJson.queryText) {
+            hiveJob.query_text = queryJson.queryText;
           }
         }
         if (entity.events != null) {

+ 11 - 2
ambari-web/app/styles/application.less

@@ -5653,13 +5653,16 @@ i.icon-asterisks {
 #tez-dag-section {
   padding-left: 7px;
   padding-top: 5px;
+  overflow: hidden;
+  #tez-dag-section-top-bar-actions {
+    margin-right: 7px;
+  }
 }
 #tez-dag-section-body {
   display: block;
 }
 #tez-dag-section-body-dag {
-  max-height: 800px;
-  overflow-y: auto;
+  overflow-y: hidden;
 
   .heat-0-20 {
     fill: #ffffff;
@@ -5690,6 +5693,12 @@ i.icon-asterisks {
     text {
       font-weight: lighter;
     }
+    .tez-root-rect {
+      fill: white;
+      stroke: white;
+      opacity: 0;
+      stroke-opacity: 0;
+    }
     .node {
       .background.map {
         fill: #fde0dd;

+ 22 - 3
ambari-web/app/templates/main/jobs/hive_job_details.hbs

@@ -41,7 +41,7 @@
     <div class="row-fluid">
       <div class="span12 sections">
         <!-- Section LHS -->
-        <div id="tez-dag-lhs" class="span6 sections-lhs">
+        <div id="tez-dag-lhs" {{bindAttr class="view.isGraphMaximized:span12:span6 :sections-lhs"}}>
           <div id="tez-dag-section" class="box">
             <div id="tez-dag-section-top-bar"> &nbsp;
               {{t jobs.hive.tez.dag.summary.metric}}
@@ -60,16 +60,35 @@
                 </ul>
               </div>
             <div id="tez-dag-section-top-bar-actions" class="pull-right">
+              <div class="btn-group">
+                <a id="tez-dag-zoom-in-button" {{bindAttr class="view.canGraphZoomIn::disabled :btn"}} {{action "doGraphZoomIn" target="view"}}>
+                  <i class="icon-zoom-in"></i>
+                </a>
+                <a id="tez-dag-zoom-out-button" {{bindAttr class="view.canGraphZoomOut::disabled :btn"}} {{action "doGraphZoomOut" target="view"}}>
+                  <i class="icon-zoom-out"></i>
+                </a>
+                {{#if view.isGraphMaximized}}
+                  <a id="tez-dag-resize-small-button" class="btn" {{action "doGraphMinimize" target="view"}}>
+                    <i class="icon-resize-small"></i>
+                  </a>
+                {{else}}
+                  <a id="tez-dag-resize-full-button" class="btn" {{action "doGraphMaximize" target="view"}}>
+                    <i class="icon-resize-full"></i>
+                  </a>
+                {{/if}}
+              </div>
             </div>
             </div>
             <div id="tez-dag-section-body">
-              {{view App.MainHiveJobDetailsTezDagView controllerBinding="controller" selectedVertexBinding="view.selectedVertex" summaryMetricTypeBinding="view.summaryMetricType"}}
+              {{view App.MainHiveJobDetailsTezDagView controllerBinding="controller" selectedVertexBinding="view.selectedVertex" 
+                summaryMetricTypeBinding="view.summaryMetricType" zoomScaleBinding="view.zoomScale" 
+                zoomScaleFromBinding="view.zoomScaleFrom" zoomScaleToBinding="view.zoomScaleTo"}}
             </div>
           </div>
         </div>
 
         <!-- Section RHS -->
-        <div id="tez-vertices-rhs" class="span6 sections-rhs">
+        <div id="tez-vertices-rhs" {{bindAttr class="view.isGraphMaximized:hidden:span6 :sections-rhs"}}>
 
           <!-- Section RHS Vertices -->
           <div id="tez-vertices-table-section">

+ 176 - 65
ambari-web/app/views/main/jobs/hive_job_details_tez_dag_view.js

@@ -23,13 +23,16 @@ App.MainHiveJobDetailsTezDagView = Em.View.extend({
   templateName : require('templates/main/jobs/hive_job_details_tez_dag'),
   selectedVertex : null,
   summaryMetricType: null,
-  /**
-   * The contents of the <svg> element.
-   */
-  svgVerticesLayer : null,
+  svgVerticesLayer : null, // The contents of the <svg> element.
+  svgTezRoot: null,
   svgWidth : -1,
   svgHeight : -1,
 
+  // zoomScaleFom: -1, // Bound from parent view
+  // zoomScaleTo: -1, // Bound from parent view
+  // zoomScale: -1, // Bound from parent view
+  zoomTranslate: [0, 0],
+
   content : null,
 
   /**
@@ -86,6 +89,7 @@ App.MainHiveJobDetailsTezDagView = Em.View.extend({
   },
 
   createSvg : function() {
+    var self = this;
     var dagVisualModel = this.get('dagVisualModel');
     dagVisualModel.nodes.clear();
     dagVisualModel.links.clear();
@@ -95,11 +99,39 @@ App.MainHiveJobDetailsTezDagView = Em.View.extend({
     this.set('content', this.get('controller.content'));
     var svg = d3.select("#tez-dag-svg");
     d3.selectAll(".tez-dag-canvas").remove();
-    this.set('svgVerticesLayer', svg.append("svg:g").attr("class", "tez-dag-canvas"));
+    var tezRoot = svg.append("svg:g").attr("class", "tez-root");
+    this.set('svgTezRoot', tezRoot);
+    var tezRootRect = tezRoot.append("rect").attr("class", "tez-root-rect");
+    this.set('svgVerticesLayer', tezRoot.append("svg:g").attr("class", "tez-dag-canvas"));
     this.adjustGraphHeight();
-    this.drawTezDag();
+    var canvasSize = this.drawTezDag();
+    var minScale = Math.min(this.get('svgHeight') / canvasSize.height, this.get('svgWidth') / canvasSize.width);
+    if (minScale > 1) {
+      minScale = 1;
+    }
+    tezRootRect.attr("width", canvasSize.width).attr("height", canvasSize.height);
+    var zoom = d3.behavior.zoom().scaleExtent([ minScale, 2 ]).on("zoom", function() {
+      tezRoot.attr("transform", "translate(" + (d3.event.translate) + ")scale(" + d3.event.scale + ")");
+      self.set('zoomScale', d3.event.scale);
+      self.set('zoomTranslate', d3.event.translate);
+    });
+    svg.call(zoom);
+    this.set('zoomTranslate', [0, 0]);
+    this.set('zoomScaleFrom', minScale);
+    this.set('zoomScaleTo', 2);
+    this.set('zoomScale', minScale);
   },
 
+  zoomScaleObserver : function() {
+    var tezRoot = this.get("svgTezRoot");
+    var newScale = this.get('zoomScale');
+    var newScaleFrom = this.get('zoomScaleFrom');
+    var newScaleTo = this.get('zoomScaleTo');
+    var zoomTranslate = this.get('zoomTranslate');
+    console.debug("zoomScaleObserver(): New scale = " + newScale + ", Range = [" + newScaleFrom + ", " + newScaleTo + "]. Translate = ", zoomTranslate.join(','));
+    tezRoot.attr("transform", "translate("+zoomTranslate+")scale(" + newScale + ")");
+  }.observes('zoomScale', 'zoomScaleFrom', 'zoomScaleTo', 'zoomTranslate'),
+
   /**
    * We have to make the height of the DAG section match the height of the
    * Summary section.
@@ -113,12 +145,10 @@ App.MainHiveJobDetailsTezDagView = Em.View.extend({
       var currentHeight = lhsDiv.clientHeight;
       $(lhsDiv).attr('style', "height:" + rhsHeight + "px;");
       var svgHeight = rhsHeight - 20;
-      d3.select("#tez-dag-svg").attr('height', svgHeight).attr('width', currentWidth);
+      d3.select("#tez-dag-svg").attr('height', svgHeight).attr('width', '100%');
       this.set('svgWidth', currentWidth);
       this.set('svgHeight', svgHeight);
-      console.log("SWT SVG Width=", currentWidth, ", Height=", svgHeight);
-      // this.get('svgVerticesLayer').attr('transform', 'translate(' +
-      // (currentWidth / 2) + ',' + (currentHeight / 2) + ')');
+      console.log("SVG Width=", currentWidth, ", Height=", svgHeight);
     }
   },
 
@@ -213,7 +243,6 @@ App.MainHiveJobDetailsTezDagView = Em.View.extend({
    */
   drawTezDag : function() {
     var width = this.get('svgWidth');
-    var height = this.get('svgHeight');
     var svgLayer = this.get('svgVerticesLayer');
     var vertices = this.get('content.tezDag.vertices');
     var edges = this.get('content.tezDag.edges');
@@ -226,20 +255,25 @@ App.MainHiveJobDetailsTezDagView = Em.View.extend({
     //
     // CALCULATE DEPTH - BFS to get correct graph depth
     //
-    var visitVertices = [];
+    var visitEdges = [];
+    var maxRowLength = 0;
+    var maxRowDepth = 0;
     vertices.forEach(function(v) {
       if (v.get('incomingEdges.length') < 1) {
-        visitVertices.push({
+        visitEdges.push({
           depth : 0,
           parent : null,
-          vertex : v
+          toVertex : v
         });
       }
     });
-    function getNodeFromVertex(vertexObj) {
-      var vertex = vertexObj.vertex;
+    function getNodeFromEdge(edgeObj) {
+      var vertex = edgeObj.toVertex;
+      var pName = edgeObj.parent ? edgeObj.parent.name : null;
+      var cName = edgeObj.toVertex ? edgeObj.toVertex.get('name') : null;
+      console.debug("Processing vertex ", edgeObj, " (",pName, " > ", cName,")");
       var node = vertexIdToNode[vertex.get('id')];
-      for ( var k = depthToNodes.length; k <= vertexObj.depth; k++) {
+      for ( var k = depthToNodes.length; k <= edgeObj.depth; k++) {
         depthToNodes.push([]);
       }
       if (!node) {
@@ -247,10 +281,10 @@ App.MainHiveJobDetailsTezDagView = Em.View.extend({
         node = {
           id : vertex.get('id'),
           name : vertex.get('name'),
-          state: vertex.get('state'),
+          state : vertex.get('state'),
           isMap : vertex.get('isMap'),
           operations : vertex.get('operations'),
-          depth : vertexObj.depth,
+          depth : edgeObj.depth,
           parents : [],
           children : [],
           x : 0,
@@ -261,42 +295,50 @@ App.MainHiveJobDetailsTezDagView = Em.View.extend({
           selected : selectedVertex != null ? selectedVertex.get('id') == vertex.get('id') : false,
           fixed : true,
           metrics : {
-            input: -1,
-            output: -1,
-            recordsRead: -1,
-            recordsWrite: -1,
-            tezTasks: -1
+            input : -1,
+            output : -1,
+            recordsRead : -1,
+            recordsWrite : -1,
+            tezTasks : -1
           }
         }
         vertexIdToNode[vertex.get('id')] = node;
         depthToNodes[node.depth].push(node);
       } else {
         // Existing node
-        if (vertexObj.depth > node.depth) {
+        if (edgeObj.depth > node.depth) {
           var oldIndex = depthToNodes[node.depth].indexOf(node);
-          depthToNodes[node.depth] = depthToNodes[node.depth].splice(oldIndex, 1);
-          node.depth = vertex.depth;
+          depthToNodes[node.depth].splice(oldIndex, 1);
+          node.depth = edgeObj.depth;
           depthToNodes[node.depth].push(node);
         }
       }
-      if (vertexObj.parent != null) {
-        node.parents.push(vertexObj.parent);
-        vertexObj.parent.children.push(node);
+      if (depthToNodes[node.depth].length > maxRowLength) {
+        maxRowLength = depthToNodes[node.depth].length;
+        maxRowDepth = node.depth;
+      }
+      if (edgeObj.parent != null) {
+        node.parents.push(edgeObj.parent);
+        edgeObj.parent.children.push(node);
       }
       return node;
     }
-    var vertexObj;
-    while (vertexObj = visitVertices.shift()) {
-      var node = getNodeFromVertex(vertexObj);
-      var outEdges = vertexObj.vertex.get('outgoingEdges');
-      outEdges.forEach(function(oe) {
-        var childVertex = oe.get('toVertex');
-        visitVertices.push({
-          depth : node.depth + 1,
-          parent : node,
-          vertex : childVertex
+    var edgeObj;
+    var visitedVertexMap = {};
+    while (edgeObj = visitEdges.shift()) {
+      var node = getNodeFromEdge(edgeObj);
+      if (!visitedVertexMap[edgeObj.toVertex.get('id')]) {
+        visitedVertexMap[edgeObj.toVertex.get('id')] = true;
+        var outEdges = edgeObj.toVertex.get('outgoingEdges');
+        outEdges.forEach(function(oe) {
+          var childVertex = oe.get('toVertex');
+          visitEdges.push({
+            depth : node.depth + 1,
+            parent : node,
+            toVertex : childVertex
+          });
         });
-      })
+      }
     }
     edges.forEach(function(e) {
       dagVisualModel.links.push({
@@ -309,39 +351,99 @@ App.MainHiveJobDetailsTezDagView = Em.View.extend({
     //
     // LAYOUT - Now with correct depth, we calculate layouts
     //
-    var deltaY = 150;
-    var currentY = 80;
+    // When a node's effective width changes, all its parent nodes are updated.
+    var updateNodeEffectiveWidth = function(node, newEffectiveWidth) {
+      console.debug("Updating effective width of (" + node.id + ") to " + newEffectiveWidth);
+      if (numberUtils.validateInteger(node.effectiveWidth) != null) {
+        node.effectiveWidth = newEffectiveWidth;
+      }
+      var diff = newEffectiveWidth - node.effectiveWidth;
+      if (diff > 0) {
+        var oldEffectiveWidth = node.effectiveWidth;
+        node.effectiveWidth = newEffectiveWidth;
+        if (node.parents != null) {
+          node.parents.forEach(function(parent) {
+            updateNodeEffectiveWidth(parent, parent.effectiveWidth + diff);
+          })
+        }
+      }
+    }
+    var xGap = 20;
+    var yGap = 70;
+    var currentY = 40;
+    // First pass - calculate layout widths, and Y coordinates
     for ( var depth = 0; depth < depthToNodes.length; depth++) {
       var nodes = depthToNodes[depth];
-      var deltaX = 1 / (nodes.length + 1);
-      var startX = deltaX;
+      var maxNodeHeight = 0;
       for ( var nodeIndex = 0; nodeIndex < nodes.length; nodeIndex++) {
         var node = nodes[nodeIndex];
+        var nodeDim = this.getNodeCalculatedDimensions(node);
+        node.width = nodeDim.width;
+        node.height = nodeDim.height;
+        if (maxNodeHeight < node.height) {
+          maxNodeHeight = node.height;
+        }
         if (depth == 0) {
           // Top nodes - position uniformly
-          node.x = startX;
-          startX += deltaX;
+          updateNodeEffectiveWidth(node, xGap + node.width);
+        }
+        if (node.children && node.children.length > 0) {
+          updateNodeEffectiveWidth(node, node.children.length * (xGap + node.width));
         } else {
-          node.x = (node.x / node.parents.length); // Average across parents
+          updateNodeEffectiveWidth(node, xGap + node.width);
         }
-        // Layout children
-        node.children.forEach(function(child) {
-          child.x += node.x;
-        });
-        var nodeDim = this.getNodeCalculatedDimensions(node);
-        node.width = nodeDim.width;
-        node.height = nodeDim.height;
         node.y = currentY;
-        node.x = (node.x * width) - Math.round(nodeDim.width / 2);
-        node.incomingX = node.x + Math.round(nodeDim.width / 2);
         node.incomingY = node.y;
-        node.outgoingX = node.incomingX;
         node.outgoingY = node.incomingY + node.height;
+      }
+      currentY += maxNodeHeight;
+      currentY += yGap;
+    }
+    // Second pass - determine actual X coordinates
+    var maxX = 0;
+    for ( var depth = 0; depth < depthToNodes.length; depth++) {
+      var nodes = depthToNodes[depth];
+      var currentX = -1;
+      var parentCurrentXMap = {};
+      for ( var nodeIndex = 0; nodeIndex < nodes.length; nodeIndex++) {
+        var node = nodes[nodeIndex];
+        var parentsKey = null;
+        if (node.parents != null && node.parents.length > 0) {
+          var parentStart = 0;
+          var parentsKey = '';
+          node.parents.forEach(function(parent) {
+            parentStart += (parent.x - ((parent.effectiveWidth - parent.width) / 2));
+            parentsKey += (parent.id + '//');
+          });
+          parentStart = parentStart / node.parents.length;
+          var parentCurrentX = parentCurrentXMap[parentsKey];
+          if (parentCurrentX == null || parentCurrentX == undefined) {
+            parentCurrentX = parentStart - ((node.effectiveWidth - node.width) / 2) + (xGap / 2);
+            parentCurrentXMap[parentsKey] = parentCurrentX;
+          }
+          currentX = parentCurrentX;
+        } else {
+          if (currentX < 0) {
+            currentX = 0;
+          }
+        }
+        node.x = (currentX + (node.effectiveWidth - node.width) / 2);
+        node.outgoingX = (node.x + node.width / 2);
+        node.incomingX = node.outgoingX;
         console.log("drawTezDag(). Layout Node: ", node);
         dagVisualModel.nodes.push(node);
+        if (parentsKey != null) {
+          parentCurrentXMap[parentsKey] = currentX + node.effectiveWidth;
+        } else {
+          currentX += node.effectiveWidth;
+        }
+        if ((node.x + node.width) > maxX) {
+          maxX = node.x + node.width;
+        }
       }
-      currentY += deltaY;
     }
+    var canvasHeight = currentY;
+    var canvasWidth = maxX + (xGap << 1);
 
     //
     // Draw SVG
@@ -376,7 +478,7 @@ App.MainHiveJobDetailsTezDagView = Em.View.extend({
       return classes;
     }).attr("d", diagonal).attr("title", function(l) {
       var lower = l.edgeType ? l.edgeType.toLowerCase() : '';
-      return Em.I18n.t("jobs.hive.tez.edge."+lower);
+      return Em.I18n.t("jobs.hive.tez.edge." + lower);
     });
     // Create Nodes
     var node = svgLayer.selectAll(".node").data(dagVisualModel.nodes).enter().append("g").attr("class", "node");
@@ -420,6 +522,16 @@ App.MainHiveJobDetailsTezDagView = Em.View.extend({
     $('.svg-tooltip').tooltip({
       placement : 'left'
     });
+
+    // Position in center
+    var translateX = Math.round((width - canvasWidth) / 2);
+    if (translateX > 0) {
+      svgLayer.attr("transform", "translate("+translateX+",0)");
+    }
+    return {
+      width : canvasWidth,
+      height : canvasHeight
+    }
   },
 
   /**
@@ -517,14 +629,13 @@ App.MainHiveJobDetailsTezDagView = Em.View.extend({
    * Determines the node width and height in pixels.
    *
    * Takes into account the various contents of the a node. { width: 200,
-   * height: 60, margin: 15 }
+   * height: 60 }
    */
   getNodeCalculatedDimensions : function(node) {
     var size = {
-      width : 160,
-      height : 40,
-      margin : 15
-    };
+      width : 180,
+      height : 40
+    }
     if (node.operations.length > 0) {
       var opsHeight = Math.ceil(node.operations.length / 3);
       size.height += (opsHeight * 20);

+ 60 - 1
ambari-web/app/views/main/jobs/hive_job_details_view.js

@@ -26,6 +26,19 @@ App.MainHiveJobDetailsView = Em.View.extend({
 
   selectedVertex : null,
   content : null,
+  zoomScaleFrom : 1,
+  zoomScaleTo: 2,
+  zoomScale : 1,
+  zoomStep : function() {
+    var zoomStep = 0.01;
+    var zoomFrom = this.get('zoomScaleFrom');
+    var zoomTo = this.get('zoomScaleTo');
+    if (zoomFrom < zoomTo) {
+      zoomStep = (zoomTo - zoomFrom) / 5;
+    }
+    return zoomStep;
+  }.property('zoomScaleFrom', 'zoomScaleTo'),
+  isGraphMaximized: false,
 
   showQuery : false,
   toggleShowQuery : function () {
@@ -178,5 +191,51 @@ App.MainHiveJobDetailsView = Em.View.extend({
     };
   }.property('selectedVertex.fileReadOps', 'selectedVertex.fileWriteOps', 'selectedVertex.hdfsReadOps', 'selectedVertex.hdfdWriteOps',
       'selectedVertex.fileReadBytes', 'selectedVertex.fileWriteBytes', 'selectedVertex.hdfsReadBytes', 'selectedVertex.hdfdWriteBytes',
-      'selectedVertex.recordReadCount', 'selectedVertex.recordWriteCount', 'selectedVertex.status')
+      'selectedVertex.recordReadCount', 'selectedVertex.recordWriteCount', 'selectedVertex.status'),
+
+  canGraphZoomIn : function() {
+    var zoomTo = this.get('zoomScaleTo');
+    var zoomScale = this.get('zoomScale');
+    console.debug("canGraphZoomIn? : ", (zoomScale < zoomTo), " (scaleTo=", zoomTo,", scale=",zoomScale,")");
+    return zoomScale < zoomTo;
+  }.property('zoomScale', 'zoomScaleTo'),
+
+  canGraphZoomOut : function() {
+    var zoomFrom = this.get('zoomScaleFrom');
+    var zoomScale = this.get('zoomScale');
+    console.debug("canGraphZoomOut? : ", (zoomScale > zoomFrom), " (scaleFrom=", zoomFrom,", scale=",zoomScale,")");
+    return zoomScale > zoomFrom;
+  }.property('zoomScale', 'zoomScaleFrom'),
+
+  doGraphZoomIn: function() {
+    var zoomTo = this.get('zoomScaleTo');
+    var zoomScale = this.get('zoomScale');
+    var zoomStep = this.get('zoomStep');
+    if (zoomScale < zoomTo) {
+      var step = Math.min(zoomStep, (zoomTo - zoomScale));
+      zoomScale += step;
+      console.debug("doGraphZoomIn(): New scale = ", zoomScale);
+      this.set('zoomScale', zoomScale);
+    }
+  },
+
+  doGraphZoomOut: function() {
+    var zoomFrom = this.get('zoomScaleFrom');
+    var zoomScale = this.get('zoomScale');
+    var zoomStep = this.get('zoomStep');
+    if (zoomScale > zoomFrom) {
+      var step = Math.min(zoomStep, (zoomScale - zoomFrom));
+      zoomScale -= step;
+      console.debug("doGraphZoomOut(): New scale = ", zoomScale);
+      this.set('zoomScale', zoomScale);
+    }
+   },
+
+   doGraphMaximize: function() {
+     this.set('isGraphMaximized', true);
+   },
+
+   doGraphMinimize: function() {
+     this.set('isGraphMaximized', false);
+   }
 });

+ 171 - 0
ambari-web/test/views/main/jobs/hive_job_details_tez_test.js

@@ -0,0 +1,171 @@
+/**
+ * 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.
+ */
+
+var App = require('app');
+module.exports = {
+  _createVertex : function(row, col, state, isMap, numOps, inEdges, outEdges, vertexJsons) {
+    var v = {
+      id : 'v_' + row + '_' + col,
+      instance_id : 'vi_' + row + '_' + col,
+      name : 'Vertex ' + row + ', ' + col,
+      state : state,
+      is_map : isMap,
+      operations : [],
+      outgoing_edges : outEdges,
+      incoming_edges : inEdges
+    };
+    for ( var c = 0; c < numOps; c++) {
+      v.operations.push("Op " + c);
+    }
+    vertexJsons.push(v);
+    return v;
+  },
+
+  _createEdge : function(id, type, from, to, edgeJsons) {
+    var e = {
+      id : id,
+      instance_id : 'i_' + id,
+      from_vertex_id : from.id,
+      to_vertex_id : to.id,
+      edge_type : type
+    }
+    edgeJsons.push(e);
+    return e;
+  },
+
+  /**
+   * Creates a Tez DAG for test purposes with 6 nodes in row 1, 1 node in row 2
+   * and 5 nodes in row 3.
+   *
+   * Usage: <code>
+   *     var testDag = jobUtils._test_createTezDag_6x1x5();
+   *     vertices = testDag.get('vertices');
+   *     edges = testDag.get('edges');
+   * </code>
+   */
+  createTezDag_6x1x5 : function() {
+    var vertices = [];
+    var dagJson = {
+      id : 'dag1',
+      instance_id : 'dag1',
+      name : 'Test DAG 1',
+      stage : 'My stage',
+      vertices : [],
+      edges : []
+    };
+    var vertexJsons = [];
+    var edgeJsons = [];
+    // Row 1
+    var v1 = this._test_createVertex(1, 1, "FAILED", true, 30, [], [ 'e1' ], vertexJsons);
+    var v2 = this._test_createVertex(1, 2, "RUNNING", true, 2, [], [ 'e2' ], vertexJsons);
+    var v3 = this._test_createVertex(1, 3, "FAILED", true, 5, [], [ 'e3' ], vertexJsons);
+    var v4 = this._test_createVertex(1, 4, "FAILED", true, 10, [], [ 'e4' ], vertexJsons);
+    var v5 = this._test_createVertex(1, 5, "FAILED", true, 15, [], [ 'e5' ], vertexJsons);
+    var v6 = this._test_createVertex(1, 6, "FAILED", true, 20, [], [ 'e6' ], vertexJsons);
+    // Row 2
+    var v7 = this._test_createVertex(2, 1, "SUCCEEDED", false, 30, [ 'e1', 'e2', 'e3', 'e4', 'e5', 'e6' ], [ 'e7', 'e8', 'e9', 'e10', 'e11' ], vertexJsons);
+    // Row 3
+    var v8 = this._test_createVertex(3, 1, "FAILED", false, 30, [ 'e7' ], [], vertexJsons);
+    var v9 = this._test_createVertex(3, 2, "RUNNING", false, 2, [ 'e8' ], [], vertexJsons);
+    var v10 = this._test_createVertex(3, 3, "FAILED", false, 5, [ 'e9' ], [], vertexJsons);
+    var v11 = this._test_createVertex(3, 4, "FAILED", true, 10, [ 'e10' ], [], vertexJsons);
+    var v12 = this._test_createVertex(3, 5, "FAILED", true, 15, [ 'e11' ], [], vertexJsons);
+    // Edges 1-2
+    this._test_createEdge('e1', 'BROADCAST', v1, v7, edgeJsons);
+    this._test_createEdge('e2', 'BROADCAST', v2, v7, edgeJsons);
+    this._test_createEdge('e3', 'BROADCAST', v3, v7, edgeJsons);
+    this._test_createEdge('e4', 'SCATTER_GATHER', v4, v7, edgeJsons);
+    this._test_createEdge('e5', 'SCATTER_GATHER', v5, v7, edgeJsons);
+    this._test_createEdge('e6', 'SCATTER_GATHER', v6, v7, edgeJsons);
+    // Edges 2-3
+    this._test_createEdge('e7', 'SCATTER_GATHER', v7, v8, edgeJsons);
+    this._test_createEdge('e8', 'SCATTER_GATHER', v7, v9, edgeJsons);
+    this._test_createEdge('e9', 'SCATTER_GATHER', v7, v10, edgeJsons);
+    this._test_createEdge('e10', 'BROADCAST', v7, v11, edgeJsons);
+    this._test_createEdge('e11', 'BROADCAST', v7, v12, edgeJsons);
+    vertexJsons.forEach(function(v) {
+      dagJson.vertices.push(v.id);
+    })
+    edgeJsons.forEach(function(e) {
+      dagJson.edges.push(e.id);
+    })
+    App.store.load(App.TezDag, dagJson);
+    App.store.loadMany(App.TezDagVertex, vertexJsons);
+    App.store.loadMany(App.TezDagEdge, edgeJsons);
+    return App.TezDag.find('dag1');
+  },
+
+  /**
+   * Creates a Tez DAG for test purposes. Each row in the graph is fully
+   * connected to the next row. The number of nodes in each row is passed as
+   * input.
+   *
+   * Usage:
+   * <code>
+   *  var testDag = jobUtils._test_createTezDag_fullyConnected([10,3,8]);
+   *  vertices = testDag.get('vertices');
+   *  edges = testDag.get('edges');
+   * </code>
+   */
+  createTezDag_fullyConnected : function(rowCounts) {
+    var vertices = [];
+    var dagJson = {
+      id : 'dag1',
+      instance_id : 'dag1',
+      name : 'Test DAG 1',
+      stage : 'My stage',
+      vertices : [],
+      edges : []
+    };
+    var vertexJsons = [];
+    var edgeJsons = [];
+    var matrix = new Array(rowCounts.length);
+    for ( var r = 0; r < rowCounts.length; r++) {
+      matrix[r] = new Array(rowCounts[r]);
+      for ( var c = 0; c < rowCounts[r]; c++) {
+        var outs = [];
+        var ins = [];
+        if (r < rowCounts.length - 1) {
+          for ( var c2 = 0; c2 < rowCounts[r + 1]; c2++) {
+            outs.push('e_' + r + c + '_' + (r + 1) + c2);
+          }
+        }
+        if (r > 0) {
+          for ( var c2 = 0; c2 < rowCounts[r - 1]; c2++) {
+            ins.push('e_' + (r - 1) + c2 + '_' + r + c);
+          }
+        }
+        matrix[r][c] = this._test_createVertex(r, c, "RUNNING", true, (r + 1) * (c + 1), ins, outs, vertexJsons);
+        if (r > 0) {
+          for ( var c2 = 0; c2 < rowCounts[r - 1]; c2++) {
+            this._test_createEdge('e_' + (r - 1) + c2 + '_' + r + c, 'BROADCAST', matrix[r - 1][c2], matrix[r][c], edgeJsons);
+          }
+        }
+      }
+    }
+    vertexJsons.forEach(function(v) {
+      dagJson.vertices.push(v.id);
+    })
+    edgeJsons.forEach(function(e) {
+      dagJson.edges.push(e.id);
+    })
+    App.store.load(App.TezDag, dagJson);
+    App.store.loadMany(App.TezDagVertex, vertexJsons);
+    App.store.loadMany(App.TezDagEdge, edgeJsons);
+    return App.TezDag.find('dag1');
+  }
+}

Niektoré súbory nie sú zobrazené, pretože je v týchto rozdielových dátach zmenené mnoho súborov