flink-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From u..@apache.org
Subject [08/11] flink git commit: [FLINK-4410] [runtime-web] Add new layout for checkpoint stats
Date Tue, 10 Jan 2017 08:49:47 GMT
[FLINK-4410] [runtime-web] Add new layout for checkpoint stats


Project: http://git-wip-us.apache.org/repos/asf/flink/repo
Commit: http://git-wip-us.apache.org/repos/asf/flink/commit/27df8011
Tree: http://git-wip-us.apache.org/repos/asf/flink/tree/27df8011
Diff: http://git-wip-us.apache.org/repos/asf/flink/diff/27df8011

Branch: refs/heads/master
Commit: 27df8011125d486a055937a3e1e224e98b6add2f
Parents: dec0d6b
Author: Ufuk Celebi <uce@apache.org>
Authored: Fri Dec 23 20:44:59 2016 +0100
Committer: Ufuk Celebi <uce@apache.org>
Committed: Tue Jan 10 09:48:52 2017 +0100

----------------------------------------------------------------------
 .../jobs/job.plan.node-list.checkpoints.jade    |  38 ++---
 .../jobs/job.plan.node.checkpoints.config.jade  |  49 ++++++
 .../jobs/job.plan.node.checkpoints.details.jade | 156 +++++++++++++++++++
 .../jobs/job.plan.node.checkpoints.history.jade |  61 ++++++++
 .../job.plan.node.checkpoints.overview.jade     |  69 ++++++++
 .../jobs/job.plan.node.checkpoints.summary.jade |  44 ++++++
 .../app/scripts/common/filters.coffee           |   3 +
 .../web-dashboard/app/scripts/index.coffee      |  36 +++++
 .../app/scripts/modules/jobs/jobs.ctrl.coffee   |  70 ++++++---
 .../app/scripts/modules/jobs/jobs.svc.coffee    |  62 +++++---
 .../web-dashboard/app/styles/job.styl           |  19 +++
 11 files changed, 543 insertions(+), 64 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/flink/blob/27df8011/flink-runtime-web/web-dashboard/app/partials/jobs/job.plan.node-list.checkpoints.jade
----------------------------------------------------------------------
diff --git a/flink-runtime-web/web-dashboard/app/partials/jobs/job.plan.node-list.checkpoints.jade
b/flink-runtime-web/web-dashboard/app/partials/jobs/job.plan.node-list.checkpoints.jade
index 229d878..5db3d28 100644
--- a/flink-runtime-web/web-dashboard/app/partials/jobs/job.plan.node-list.checkpoints.jade
+++ b/flink-runtime-web/web-dashboard/app/partials/jobs/job.plan.node-list.checkpoints.jade
@@ -15,29 +15,19 @@
   See the License for the specific language governing permissions and
   limitations under the License.
 
-div(ng-if="!jobCheckpointStats")
-  p
-    em No checkpoints
+.split
+  nav.navbar.navbar-default.navbar-secondary-additional
+    ul.nav.nav-tabs
+      li(ui-sref-active='active')
+        a(ui-sref=".overview") Overview
+      li(ui-sref-active='active')
+        a(ui-sref=".history") History
+      li(ui-sref-active='active')
+        a(ui-sref=".summary") Summary
+      li(ui-sref-active='active')
+        a(ui-sref=".config") Configuration
+      li(ng-if="checkpointDetails.id != -1").active
+        a Details for Checkpoint {{ checkpointDetails.id }}
 
-div(ng-if="jobCheckpointStats")
-  h2 Overview
+  .clean.checkpoints-view#checkpoints-view(ui-view="checkpoints-view")
 
-  div(ng-include=" 'partials/jobs/job.plan.node.checkpoints.job.html' ")
-
-  h2 Operators
-
-  table.table.table-body-hover.table-clickable.table-activable
-    thead
-      tr
-        th Name
-        th Status
-
-    tbody(ng-repeat="v in job.vertices" ng-class="{ active: v.id == nodeid }" ng-click="v.id
== nodeid || changeNode(v.id)")
-      tr(ng-if="v.type == 'regular'")
-        td {{ v.name | humanizeText }}
-        td
-          bs-label(status="{{v.status}}") {{v.status}}
-
-      tr(ng-if="nodeid && v.id == nodeid")
-        td(colspan="10")
-          div(ng-include=" 'partials/jobs/job.plan.node.checkpoints.operator.html' ")

http://git-wip-us.apache.org/repos/asf/flink/blob/27df8011/flink-runtime-web/web-dashboard/app/partials/jobs/job.plan.node.checkpoints.config.jade
----------------------------------------------------------------------
diff --git a/flink-runtime-web/web-dashboard/app/partials/jobs/job.plan.node.checkpoints.config.jade
b/flink-runtime-web/web-dashboard/app/partials/jobs/job.plan.node.checkpoints.config.jade
new file mode 100644
index 0000000..4cd43f3
--- /dev/null
+++ b/flink-runtime-web/web-dashboard/app/partials/jobs/job.plan.node.checkpoints.config.jade
@@ -0,0 +1,49 @@
+//
+  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.
+
+div(ng-if="checkpointConfig")
+  table.table
+    thead
+      tr
+        td #[strong Option]
+        td #[strong Value]
+    tbody
+      tr
+        td Checkpointing Mode
+        td(ng-if="checkpointConfig['mode'] == 'exactly_once'") Exactly Once
+        td(ng-if="checkpointConfig['mode'] != 'exactly_once'") At Least Once
+      tr
+        td Interval
+        td(ng-if="checkpointConfig['interval'] == '0x7fffffffffffffff'") Periodic checkpoints
disabled
+        td(ng-if="checkpointConfig['interval'] != '0x7fffffffffffffff'") {{ checkpointConfig['interval']
| humanizeDuration }}
+      tr
+        td Timeout
+        td {{ checkpointConfig['timeout'] | humanizeDuration }}
+      tr
+        td Minimum Pause Between Checkpoints
+        td {{ checkpointConfig['min_pause'] | humanizeDuration }}
+      tr
+        td Maximum Concurrent Checkpoints
+        td {{ checkpointConfig['max_concurrent'] }}
+      tr
+        td Persist Checkpoints Externally
+        td(ng-if="checkpointConfig['externalization']['enabled']")
+          | Enabled
+          = ' '
+          span(ng-if="checkpointConfig['externalization']['delete_on_cancellation']") (delete
on cancellation)
+          span(ng-if="!checkpointConfig['externalization']['delete_on_cancellation']") (retain
on cancellation)
+        td(ng-if="!checkpointConfig['externalization']['enabled']") Disabled

http://git-wip-us.apache.org/repos/asf/flink/blob/27df8011/flink-runtime-web/web-dashboard/app/partials/jobs/job.plan.node.checkpoints.details.jade
----------------------------------------------------------------------
diff --git a/flink-runtime-web/web-dashboard/app/partials/jobs/job.plan.node.checkpoints.details.jade
b/flink-runtime-web/web-dashboard/app/partials/jobs/job.plan.node.checkpoints.details.jade
new file mode 100644
index 0000000..e2b1038
--- /dev/null
+++ b/flink-runtime-web/web-dashboard/app/partials/jobs/job.plan.node.checkpoints.details.jade
@@ -0,0 +1,156 @@
+//
+  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.
+
+div(ng-if="checkpoint")
+  table.table.table-inner
+    thead
+      tr
+        td #[strong ID]
+        td #[strong Status]
+        td #[strong Acknowledged]
+        td #[strong Trigger Time]
+        td #[strong Latest Acknowledgement]
+        td(ng-if="checkpoint['failure_timestamp']") #[strong Failure Time]
+        td #[strong End to End Duration]
+        td #[strong State Size]
+        td #[strong Buffered During Alignment]
+        td(ng-if="checkpoint['status'] == 'COMPLETED'") #[strong Discarded]
+        td(ng-if="checkpoint['external_path']") #[strong Path]
+        td(ng-if="checkpoint['failure_message']") #[strong Failure Message]
+    tbody
+      tr
+        td {{ checkpoint['id'] }}
+        td(ng-if="checkpoint['status'] == 'IN_PROGRESS'") #[i(aria-hidden="true").fa.fa-circle-o-notch.fa-spin.fa-fw]
In progress #[i(ng-if="checkpoint['is_savepoint']") savepoint]
+        td(ng-if="checkpoint['status'] == 'COMPLETED'") #[i(aria-hidden="true").fa.fa-check]
Completed #[i(ng-if="checkpoint['is_savepoint']") savepoint]
+        td(ng-if="checkpoint['status'] == 'FAILED'") #[i(aria-hidden="true").fa.fa-remove]
Failed #[i(ng-if="checkpoint['is_savepoint']") savepoint]
+        td {{ checkpoint['num_acknowledged_subtasks'] }}/{{ checkpoint['num_subtasks'] }}
({{ checkpoint['num_acknowledged_subtasks']/checkpoint['num_subtasks'] | percentage }})
+        td {{ checkpoint['trigger_timestamp'] | amDateFormat:'H:mm:ss' }}
+        td(ng-if="checkpoint['latest_ack_timestamp'] >= 0") {{ checkpoint['latest_ack_timestamp']
| amDateFormat:'H:mm:ss' }}
+        td(ng-if="checkpoint['latest_ack_timestamp'] < 0") n/a
+        td(ng-if="checkpoint['failure_timestamp']") {{ checkpoint['failure_timestamp'] |
amDateFormat:'H:mm:ss' }}
+        td(ng-if="checkpoint['end_to_end_duration'] >= 0") {{ checkpoint['end_to_end_duration']
| humanizeDuration }}
+        td(ng-if="heckpoint['end_to_end_duration'] < 0") n/a
+        td {{ checkpoint['state_size'] | humanizeBytes }}
+        td  {{ checkpoint['alignment_buffered'] | humanizeBytes }}
+        td(ng-if="checkpoint['status'] == 'COMPLETED'") #[span(ng-if="checkpoint['discarded']")
Yes]#[span(ng-if="!checkpoint['discarded']") No]
+        td(ng-if="checkpoint['external_path']") {{ checkpoint['external_path'] }}
+        td(ng-if="checkpoint['status'] == 'FAILED' && checkpoint['failure_message']")
{{ checkpoint['failure_message'] }}
+        td(ng-if="checkpoint['status'] == 'FAILED' && !checkpoint['failure_message']")
n/a
+
+  h4 Operators
+  table.table.table-body-hover.table-clickable.table-activable.subtask-details
+    thead
+      tr
+        td #[strong Name]
+        td #[strong Acknowleged]
+        td #[strong Latest Acknowledgment]
+        td #[strong End to End Duration]
+        td #[strong State Size]
+        td #[strong Buffered During Alignment]
+        td
+    tbody(ng-repeat="v in job.vertices" ng-class="{ active: v.id == nodeid }" ng-click="changeNode(v.id)")
+      tr(ng-if="v.type == 'regular'")
+        td {{ v.name | humanizeText }}
+        td {{ checkpoint['tasks'][v.id]['num_acknowledged_subtasks'] }}/{{ checkpoint['tasks'][v.id]['num_subtasks']
}} ({{ checkpoint['tasks'][v.id]['num_acknowledged_subtasks']/checkpoint['tasks'][v.id]['num_subtasks']
| percentage }})
+        td(ng-if="checkpoint['tasks'][v.id]['latest_ack_timestamp'] >= 0") {{ checkpoint['tasks'][v.id]['latest_ack_timestamp']
| amDateFormat:'H:mm:ss' }}
+        td(ng-if="checkpoint['tasks'][v.id]['latest_ack_timestamp'] < 0") n/a
+        td(ng-if="checkpoint['tasks'][v.id]['end_to_end_duration'] >= 0") {{ checkpoint['tasks'][v.id]['end_to_end_duration']
| humanizeDuration }}
+        td(ng-if="checkpoint['tasks'][v.id]['end_to_end_duration'] < 0") n/a
+        td {{ checkpoint['tasks'][v.id]['state_size'] | humanizeBytes }}
+        td {{ checkpoint['tasks'][v.id]['alignment_buffered'] | humanizeBytes }}
+        td
+          div(ng-if="!nodeid || v.id != nodeid")
+            a.btn.btn-default(ng-click="toggleFold()")
+              | Show Subtasks
+              = ' '
+              i.fa.fa-chevron-down
+          div(ng-if="nodeid && v.id == nodeid")
+            a.btn.btn-default(ng-click="toggleFold()")
+              | Hide Subtasks
+              = ' '
+              i.fa.fa-chevron-up
+      tr(ng-if="nodeid && v.id == nodeid")
+        td(colspan=7)
+          table.table.table-body-hover.table-inner.subtask-details
+            thead(ng-if="subtaskDetails[v.id]['summary']")
+              tr
+                td
+                td
+                td #[strong End to End Duration]
+                td #[strong State Size]
+                td #[strong Checkpoint Duration (Sync)]
+                td #[strong Checkpoint Duration (Async)]
+                td #[strong Alignment Buffered]
+                td #[strong Alignment Duration]
+              tr
+                td
+                td #[strong Minimum]
+                td {{ subtaskDetails[v.id]['summary']['end_to_end_duration']['min'] | humanizeDuration
}}
+                td {{ subtaskDetails[v.id]['summary']['state_size']['min'] | humanizeBytes
}}
+                td {{ subtaskDetails[v.id]['summary']['checkpoint_duration']['sync']['min']
| humanizeDuration }}
+                td {{ subtaskDetails[v.id]['summary']['checkpoint_duration']['async']['min']
| humanizeDuration }}
+                td {{ subtaskDetails[v.id]['summary']['alignment']['buffered']['min'] | humanizeBytes
}}
+                td {{ subtaskDetails[v.id]['summary']['alignment']['duration']['min'] | humanizeDuration
}}
+              tr
+                td
+                td #[strong Average]
+                td {{ subtaskDetails[v.id]['summary']['end_to_end_duration']['avg'] | humanizeDuration
}}
+                td {{ subtaskDetails[v.id]['summary']['state_size']['avg'] | humanizeBytes
}}
+                td {{ subtaskDetails[v.id]['summary']['checkpoint_duration']['sync']['avg']
| humanizeDuration }}
+                td {{ subtaskDetails[v.id]['summary']['checkpoint_duration']['async']['avg']
| humanizeDuration }}
+                td {{ subtaskDetails[v.id]['summary']['alignment']['buffered']['avg'] | humanizeBytes
}}
+                td {{ subtaskDetails[v.id]['summary']['alignment']['duration']['avg'] | humanizeDuration
}}
+              tr
+                td
+                td #[strong Maximum]
+                td {{ subtaskDetails[v.id]['summary']['end_to_end_duration']['max'] | humanizeDuration
}}
+                td {{ subtaskDetails[v.id]['summary']['state_size']['max'] | humanizeBytes
}}
+                td {{ subtaskDetails[v.id]['summary']['checkpoint_duration']['sync']['max']
| humanizeDuration }}
+                td {{ subtaskDetails[v.id]['summary']['checkpoint_duration']['async']['max']
| humanizeDuration }}
+                td {{ subtaskDetails[v.id]['summary']['alignment']['buffered']['max'] | humanizeBytes
}}
+                td {{ subtaskDetails[v.id]['summary']['alignment']['duration']['max'] | humanizeDuration
}}
+              tr.blank
+                td(colspan=8)
+            thead
+              tr
+                td #[strong Subtask #]
+                td #[strong Acknowledgement Time]
+                td #[strong End to End Duration]
+                td #[strong State Size]
+                td #[strong Checkpoint Duration (Sync)]
+                td #[strong Checkpoint Duration (Async)]
+                td #[strong Alignment Buffered]
+                td #[strong Alignment Duration]
+            tbody
+              tr(ng-repeat="subtask in subtaskDetails[v.id]['subtasks']")
+                td {{ subtask['index'] + 1 }}
+                td(ng-if-start="subtask['status'] == 'completed'") {{ subtask['ack_timestamp']
| amDateFormat:'H:mm:ss' }}
+                td {{ subtask['end_to_end_duration'] | humanizeDuration }}
+                td {{ subtask['state_size'] | humanizeBytes }}
+                td {{ subtask['checkpoint']['sync'] | humanizeDuration }}
+                td {{ subtask['checkpoint']['async'] | humanizeDuration }}
+                td {{ subtask['alignment']['buffered'] | humanizeBytes}}
+                td(ng-if-end) {{ subtask['alignment']['duration'] | humanizeDuration }}
+                td(ng-if="subtask['status'] == 'pending'" colspan=7) n/a
+
+div(ng-if="!checkpoint")
+  p(ng-if="unknown_checkpoint" role="alert").alert.alert-danger
+    strong Unknown or expired checkpoint ID.
+  p(ng-if="!unknown_checkpoint" role="alert").alert.alert-info
+    strong Waiting for response from JobManager with checkpoint details...
+    = ' '
+    i(aria-hidden="true").fa.fa-circle-o-notch.fa-spin.fa-fw

http://git-wip-us.apache.org/repos/asf/flink/blob/27df8011/flink-runtime-web/web-dashboard/app/partials/jobs/job.plan.node.checkpoints.history.jade
----------------------------------------------------------------------
diff --git a/flink-runtime-web/web-dashboard/app/partials/jobs/job.plan.node.checkpoints.history.jade
b/flink-runtime-web/web-dashboard/app/partials/jobs/job.plan.node.checkpoints.history.jade
new file mode 100644
index 0000000..44cd3db
--- /dev/null
+++ b/flink-runtime-web/web-dashboard/app/partials/jobs/job.plan.node.checkpoints.history.jade
@@ -0,0 +1,61 @@
+//
+  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.
+
+div(ng-if="checkpointStats['history'] && checkpointStats['history'].length > 0")
+  table.table
+    thead
+      tr
+        td #[strong ID]
+        td #[strong Status]
+        td #[strong Acknowledged]
+        td #[strong Trigger Time]
+        td #[strong Latest Acknowledgement]
+        td #[strong End to End Duration]
+        td #[strong State Size]
+        td #[strong Buffered During Alignment]
+        td
+    tbody
+      tr(ng-repeat="checkpoint in checkpointStats['history']" ng-class="{'bg-danger': checkpoint['status']
== 'FAILED'}")
+        td {{ checkpoint['id'] }}
+        td(ng-if="checkpoint['status'] == 'IN_PROGRESS'") #[i(aria-hidden="true").fa.fa-circle-o-notch.fa-spin.fa-fw]
#[i(ng-if="checkpoint['is_savepoint']" aria-hidden="true").fa.fa-floppy-o]
+        td(ng-if="checkpoint['status'] == 'COMPLETED'") #[i(aria-hidden="true").fa.fa-check]
#[i(ng-if="checkpoint['is_savepoint']" aria-hidden="true").fa.fa-floppy-o]
+        td(ng-if="checkpoint['status'] == 'FAILED'") #[i(aria-hidden="true").fa.fa-remove]
#[i(ng-if="checkpoint['is_savepoint']" aria-hidden="true").fa.fa-floppy-o]
+        td {{ checkpoint['num_acknowledged_subtasks'] }}/{{ checkpoint['num_subtasks'] }}
+          = ' '
+          span(ng-if="checkpoint['status'] == 'IN_PROGRESS'") ({{ checkpoint['num_acknowledged_subtasks']/checkpoint['num_subtasks']
| percentage }})
+        td {{ checkpoint['trigger_timestamp'] | amDateFormat:'H:mm:ss' }}
+        td(ng-if="checkpoint['latest_ack_timestamp'] >= 0") {{ checkpoint['latest_ack_timestamp']
| amDateFormat:'H:mm:ss' }}
+        td(ng-if="checkpoint['latest_ack_timestamp'] < 0") n/a
+        td(ng-if="checkpoint['end_to_end_duration'] >= 0") {{ checkpoint['end_to_end_duration']
| humanizeDuration }}
+        td(ng-if="checkpoint['end_to_end_duration'] < 0") n/a
+        td {{ checkpoint['state_size'] | humanizeBytes }}
+        td {{ checkpoint['alignment_buffered'] | humanizeBytes }}
+        td
+          a.btn.btn-default(ui-sref="^.details({checkpointId: checkpoint['id']})")
+            i(aria-hidden="true").fa.fa-chevron-right
+            = ' '
+            strong More details
+  p
+    strong.small Status:
+    ul.small
+      li In Progress: #[i(aria-hidden="true").fa.fa-circle-o-notch.fa-spin.fa-fw]
+      li Completed: #[i(aria-hidden="true").fa.fa-check]
+      li Failed: #[i(aria-hidden="true").fa.fa-remove]
+      li Savepoint: #[i(aria-hidden="true").fa.fa-floppy-o]
+
+div(ng-if="checkpointStats['history'] && checkpointStats['history'].length == 0")
+  p(role="alert").alert.alert-info #[strong No checkpoint history available.]

http://git-wip-us.apache.org/repos/asf/flink/blob/27df8011/flink-runtime-web/web-dashboard/app/partials/jobs/job.plan.node.checkpoints.overview.jade
----------------------------------------------------------------------
diff --git a/flink-runtime-web/web-dashboard/app/partials/jobs/job.plan.node.checkpoints.overview.jade
b/flink-runtime-web/web-dashboard/app/partials/jobs/job.plan.node.checkpoints.overview.jade
new file mode 100644
index 0000000..2a1af51
--- /dev/null
+++ b/flink-runtime-web/web-dashboard/app/partials/jobs/job.plan.node.checkpoints.overview.jade
@@ -0,0 +1,69 @@
+//
+  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.
+
+div(ng-if="checkpointStats")
+  table.table.checkpoint-overview
+    thead
+      tr
+        td #[strong Checkpoint Counts]
+        td Triggered: {{ checkpointStats['counts']['total'] }}
+          span In Progress: {{ checkpointStats['counts']['in_progress'] }}
+          span Completed: {{ checkpointStats['counts']['completed'] }}
+          span Failed: {{ checkpointStats['counts']['failed'] }}
+          span Restored: {{ checkpointStats['counts']['restored'] }}
+      tr
+        td #[strong Latest Completed Checkpoint]
+        td(ng-if="checkpointStats['latest']['completed']") ID: {{ checkpointStats['latest']['completed']['id']
}}
+          span Completion Time: {{ checkpointStats['latest']['completed']['latest_ack_timestamp']
| amDateFormat:'H:mm:ss' }}
+          span End to End Duration: {{ checkpointStats['latest']['completed']['end_to_end_duration']
| humanizeDuration }}
+          span State Size: {{ checkpointStats['latest']['completed']['state_size'] | humanizeBytes
}}
+          span
+            i(aria-hidden="true").fa.fa-caret-square-o-right
+            = ' '
+            a(ui-sref="^.details({checkpointId: checkpointStats['latest']['completed']['id']})")
More details
+        td(ng-if="!checkpointStats['latest']['completed']") None
+      tr
+        td #[strong Latest Failed Checkpoint]
+        td(ng-if="checkpointStats['latest']['failed']")
+          | ID: {{ checkpointStats['latest']['failed']['id'] }}
+          span Failure Time: {{ checkpointStats['latest']['failed']['failure_timestamp']
| amDateFormat:'H:mm:ss' }}
+          span(ng-if="checkpointStats['latest']['failed']['failure_message']") Cause: {{
checkpointStats['latest']['failed']['failure_message'] }}
+          span(ng-if="!checkpointStats['latest']['failed']['failure_message']") Cause: n/a
+          span
+            i(aria-hidden="true").fa.fa-caret-square-o-right
+            = ' '
+            a(ui-sref="^.details({checkpointId: checkpointStats['latest']['failed']['id']})")
More details
+        td(ng-if="!checkpointStats['latest']['failed']") None
+      tr
+        td #[strong Latest Savepoint]
+        td(ng-if="checkpointStats['latest']['savepoint']") ID: {{ checkpointStats['latest']['savepoint']['id']
}}
+          span Completion Time: {{ checkpointStats['latest']['savepoint']['latest_ack_timestamp']
| amDateFormat:'H:mm:ss' }}
+          span State Size: {{ checkpointStats['latest']['savepoint']['state_size'] | humanizeBytes
}}
+          span Path: {{ checkpointStats['latest']['savepoint']['external_path'] }}
+          span
+            i(aria-hidden="true").fa.fa-caret-square-o-right
+            = ' '
+            a(ui-sref="^.details({checkpointId: checkpointStats['latest']['savepoint']['id']})")
More details
+        td(ng-if="!checkpointStats['latest']['savepoint']") None
+      tr
+        td #[strong Latest Restore]
+        td(ng-if="checkpointStats['latest']['restored']") ID: {{ checkpointStats['latest']['restored']['id']
}}
+          span Restore Time: {{ checkpointStats['latest']['restored']['restore_timestamp']
| amDateFormat:'H:mm:ss' }}
+          span(ng-if="checkpointStats['latest']['restored']['is_savepoint']") Type: Savepoint
+          span(ng-if="!checkpointStats['latest']['restored']['is_savepoint']") Type: Checkpoint
+          span(ng-if="checkpointStats['latest']['restored']['external_path']") Path: {{ checkpointStats['latest']['restored']['external_path']
}}
+        td(ng-if="!checkpointStats['latest']['restored']") None

http://git-wip-us.apache.org/repos/asf/flink/blob/27df8011/flink-runtime-web/web-dashboard/app/partials/jobs/job.plan.node.checkpoints.summary.jade
----------------------------------------------------------------------
diff --git a/flink-runtime-web/web-dashboard/app/partials/jobs/job.plan.node.checkpoints.summary.jade
b/flink-runtime-web/web-dashboard/app/partials/jobs/job.plan.node.checkpoints.summary.jade
new file mode 100644
index 0000000..503c243
--- /dev/null
+++ b/flink-runtime-web/web-dashboard/app/partials/jobs/job.plan.node.checkpoints.summary.jade
@@ -0,0 +1,44 @@
+//
+  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.
+
+div(ng-if="checkpointStats['summary']")
+  table.table
+    thead
+      tr
+        td
+        td #[strong State Size]
+        td #[strong End to End Duration]
+        td #[strong Buffered During Alignment]
+    tbody
+      tr
+        td #[strong Minimum]
+        td {{ checkpointStats['summary']['end_to_end_duration']['min'] | humanizeDuration
}}
+        td {{ checkpointStats['summary']['state_size']['min'] | humanizeBytes }}
+        td {{ checkpointStats['summary']['alignment_buffered']['min'] | humanizeBytes }}
+      tr
+        td #[strong Average]
+        td {{ checkpointStats['summary']['end_to_end_duration']['avg'] | humanizeDuration
}}
+        td {{ checkpointStats['summary']['state_size']['avg'] | humanizeBytes }}
+        td {{ checkpointStats['summary']['alignment_buffered']['avg'] | humanizeBytes }}
+      tr
+        td #[strong Maximum]
+        td {{ checkpointStats['summary']['end_to_end_duration']['max'] | humanizeDuration
}}
+        td {{ checkpointStats['summary']['state_size']['max'] | humanizeBytes }}
+        td {{ checkpointStats['summary']['alignment_buffered']['max'] | humanizeBytes }}
+  p These number are computed over #[i all] completed checkpoints.
+
+p(ng-if="!checkpointStats['summary']") No checkpoint statistics summary available.

http://git-wip-us.apache.org/repos/asf/flink/blob/27df8011/flink-runtime-web/web-dashboard/app/scripts/common/filters.coffee
----------------------------------------------------------------------
diff --git a/flink-runtime-web/web-dashboard/app/scripts/common/filters.coffee b/flink-runtime-web/web-dashboard/app/scripts/common/filters.coffee
index c3030a9..e7e831c 100644
--- a/flink-runtime-web/web-dashboard/app/scripts/common/filters.coffee
+++ b/flink-runtime-web/web-dashboard/app/scripts/common/filters.coffee
@@ -78,3 +78,6 @@ angular.module('flinkApp')
 
 .filter "toUpperCase", ->
   (text) -> text.toUpperCase()
+
+.filter "percentage", ->
+  (number) -> (number * 100).toFixed(0) + '%'

http://git-wip-us.apache.org/repos/asf/flink/blob/27df8011/flink-runtime-web/web-dashboard/app/scripts/index.coffee
----------------------------------------------------------------------
diff --git a/flink-runtime-web/web-dashboard/app/scripts/index.coffee b/flink-runtime-web/web-dashboard/app/scripts/index.coffee
index 98ce76a..95bb356 100644
--- a/flink-runtime-web/web-dashboard/app/scripts/index.coffee
+++ b/flink-runtime-web/web-dashboard/app/scripts/index.coffee
@@ -130,11 +130,47 @@ angular.module('flinkApp', ['ui.router', 'angularMoment', 'dndLists'])
 
   .state "single-job.plan.checkpoints",
     url: "/checkpoints"
+    redirectTo: "single-job.plan.checkpoints.overview"
     views:
       'node-details':
         templateUrl: "partials/jobs/job.plan.node-list.checkpoints.html"
         controller: 'JobPlanCheckpointsController'
 
+  .state "single-job.plan.checkpoints.overview",
+    url: "/overview"
+    views:
+      'checkpoints-view':
+        templateUrl: "partials/jobs/job.plan.node.checkpoints.overview.html"
+        controller: 'JobPlanCheckpointsController'
+
+  .state "single-job.plan.checkpoints.summary",
+    url: "/summary"
+    views:
+      'checkpoints-view':
+        templateUrl: "partials/jobs/job.plan.node.checkpoints.summary.html"
+        controller: 'JobPlanCheckpointsController'
+
+  .state "single-job.plan.checkpoints.history",
+    url: "/history"
+    views:
+      'checkpoints-view':
+        templateUrl: "partials/jobs/job.plan.node.checkpoints.history.html"
+        controller: 'JobPlanCheckpointsController'
+
+  .state "single-job.plan.checkpoints.config",
+    url: "/config"
+    views:
+      'checkpoints-view':
+        templateUrl: "partials/jobs/job.plan.node.checkpoints.config.html"
+        controller: 'JobPlanCheckpointsController'
+
+  .state "single-job.plan.checkpoints.details",
+    url: "/details/{checkpointId}"
+    views:
+      'checkpoints-view':
+        templateUrl: "partials/jobs/job.plan.node.checkpoints.details.html"
+        controller: 'JobPlanCheckpointDetailsController'
+
   .state "single-job.plan.backpressure",
     url: "/backpressure"
     views:

http://git-wip-us.apache.org/repos/asf/flink/blob/27df8011/flink-runtime-web/web-dashboard/app/scripts/modules/jobs/jobs.ctrl.coffee
----------------------------------------------------------------------
diff --git a/flink-runtime-web/web-dashboard/app/scripts/modules/jobs/jobs.ctrl.coffee b/flink-runtime-web/web-dashboard/app/scripts/modules/jobs/jobs.ctrl.coffee
index 2bcbc13..bbb57c5 100644
--- a/flink-runtime-web/web-dashboard/app/scripts/modules/jobs/jobs.ctrl.coffee
+++ b/flink-runtime-web/web-dashboard/app/scripts/modules/jobs/jobs.ctrl.coffee
@@ -47,8 +47,6 @@ angular.module('flinkApp')
   $scope.job = null
   $scope.plan = null
   $scope.vertices = null
-  $scope.jobCheckpointStats = null
-  $scope.showHistory = false
   $scope.backPressureOperatorStats = {}
 
   JobsService.loadJob($stateParams.jobid).then (data) ->
@@ -69,7 +67,6 @@ angular.module('flinkApp')
     $scope.job = null
     $scope.plan = null
     $scope.vertices = null
-    $scope.jobCheckpointStats = null
     $scope.backPressureOperatorStats = null
 
     $interval.cancel(refresher)
@@ -84,9 +81,6 @@ angular.module('flinkApp')
     JobsService.stopJob($stateParams.jobid).then (data) ->
       {}
 
-  $scope.toggleHistory = ->
-    $scope.showHistory = !$scope.showHistory
-
 # --------------------------------------
 
 .controller 'JobPlanController', ($scope, $state, $stateParams, $window, JobsService) ->
@@ -166,26 +160,60 @@ angular.module('flinkApp')
 
 # --------------------------------------
 
-.controller 'JobPlanCheckpointsController', ($scope, JobsService) ->
-  getJobCheckpointStats = ->
-    JobsService.getJobCheckpointStats($scope.jobid).then (data) ->
-      $scope.jobCheckpointStats = data
+.controller 'JobPlanCheckpointsController', ($scope, $state, $stateParams, JobsService) ->
+  # Updated by the details handler for the sub checkpoints nav bar.
+  $scope.checkpointDetails = {}
+  $scope.checkpointDetails.id = -1
 
-  getOperatorCheckpointStats = ->
-    JobsService.getOperatorCheckpointStats($scope.nodeid).then (data) ->
-      $scope.operatorCheckpointStats = data.operatorStats
-      $scope.subtasksCheckpointStats = data.subtasksStats
+  # Request the config once (it's static)
+  JobsService.getCheckpointConfig().then (data) ->
+    $scope.checkpointConfig = data
 
-  # Get the per job stats
-  getJobCheckpointStats()
+  # General stats like counts, history, etc.
+  getGeneralCheckpointStats = ->
+    JobsService.getCheckpointStats().then (data) ->
+      if (data != null)
+        $scope.checkpointStats = data
 
-  # Get the per operator stats
-  if $scope.nodeid and (!$scope.vertex or !$scope.vertex.operatorCheckpointStats)
-    getOperatorCheckpointStats()
+  # Trigger request
+  getGeneralCheckpointStats()
 
   $scope.$on 'reload', (event) ->
-    getJobCheckpointStats()
-    getOperatorCheckpointStats() if $scope.nodeid
+    # Retrigger request
+    getGeneralCheckpointStats()
+
+# --------------------------------------
+
+.controller 'JobPlanCheckpointDetailsController', ($scope, $state, $stateParams, JobsService)
->
+  $scope.subtaskDetails = {}
+  $scope.checkpointDetails.id = $stateParams.checkpointId
+
+  # Detailed stats for a single checkpoint
+  getCheckpointDetails = (checkpointId) ->
+    JobsService.getCheckpointDetails(checkpointId).then (data) ->
+      if (data != null)
+        $scope.checkpoint = data
+      else
+        $scope.unknown_checkpoint = true
+
+  getCheckpointSubtaskDetails = (checkpointId, vertexId) ->
+    JobsService.getCheckpointSubtaskDetails(checkpointId, vertexId).then (data) ->
+      if (data != null)
+        $scope.subtaskDetails[vertexId] = data
+
+  getCheckpointDetails($stateParams.checkpointId)
+
+  if ($scope.nodeid)
+    getCheckpointSubtaskDetails($stateParams.checkpointId, $scope.nodeid)
+
+  $scope.$on 'reload', (event) ->
+    getCheckpointDetails($stateParams.checkpointId)
+
+    if ($scope.nodeid)
+      getCheckpointSubtaskDetails($stateParams.checkpointId, $scope.nodeid)
+
+  $scope.$on '$destroy', ->
+    $scope.checkpointDetails.id = -1
 
 # --------------------------------------
 

http://git-wip-us.apache.org/repos/asf/flink/blob/27df8011/flink-runtime-web/web-dashboard/app/scripts/modules/jobs/jobs.svc.coffee
----------------------------------------------------------------------
diff --git a/flink-runtime-web/web-dashboard/app/scripts/modules/jobs/jobs.svc.coffee b/flink-runtime-web/web-dashboard/app/scripts/modules/jobs/jobs.svc.coffee
index 71f0921..7351de8 100644
--- a/flink-runtime-web/web-dashboard/app/scripts/modules/jobs/jobs.svc.coffee
+++ b/flink-runtime-web/web-dashboard/app/scripts/modules/jobs/jobs.svc.coffee
@@ -199,7 +199,7 @@ angular.module('flinkApp')
 
     deferreds.job.promise.then (data) =>
       # vertex = @seekVertex(vertexid)
-
+      console.log(currentJob.jid)
       $http.get flinkConfig.jobServer + "jobs/" + currentJob.jid + "/vertices/" + vertexid
+ "/accumulators"
       .success (data) ->
         accumulators = data['user-accumulators']
@@ -212,37 +212,61 @@ angular.module('flinkApp')
 
     deferred.promise
 
-  # Job-level checkpoint stats
-  @getJobCheckpointStats = (jobid) ->
+  # Checkpoint config
+  @getCheckpointConfig =  ->
     deferred = $q.defer()
 
-    $http.get flinkConfig.jobServer + "jobs/" + jobid + "/checkpoints"
-    .success (data, status, headers, config) =>
-      if (angular.equals({}, data))
-        deferred.resolve(deferred.resolve(null))
-      else
-        deferred.resolve(data)
+    deferreds.job.promise.then (data) =>
+      $http.get flinkConfig.jobServer + "jobs/" + currentJob.jid + "/checkpoints/config"
+      .success (data) ->
+        if (angular.equals({}, data))
+          deferred.resolve(null)
+        else
+          deferred.resolve(data)
 
     deferred.promise
 
-  # Operator-level checkpoint stats
-  @getOperatorCheckpointStats = (vertexid) ->
+  # General checkpoint stats like counts, history, etc.
+  @getCheckpointStats = ->
     deferred = $q.defer()
 
     deferreds.job.promise.then (data) =>
-      $http.get flinkConfig.jobServer + "jobs/" + currentJob.jid + "/vertices/" + vertexid
+ "/checkpoints"
+      $http.get flinkConfig.jobServer + "jobs/" + currentJob.jid + "/checkpoints"
+      .success (data, status, headers, config) =>
+        if (angular.equals({}, data))
+          deferred.resolve(null)
+        else
+          deferred.resolve(data)
+
+    deferred.promise
+
+  # Detailed checkpoint stats for a single checkpoint
+  @getCheckpointDetails = (checkpointid) ->
+    deferred = $q.defer()
+
+    deferreds.job.promise.then (data) =>
+      $http.get flinkConfig.jobServer + "jobs/" + currentJob.jid + "/checkpoints/details/"
+ checkpointid
       .success (data) ->
         # If no data available, we are done.
         if (angular.equals({}, data))
-          deferred.resolve({ operatorStats: null, subtasksStats: null })
+          deferred.resolve(null)
         else
-          operatorStats = { id: data['id'], timestamp: data['timestamp'], duration: data['duration'],
size: data['size'] }
+          deferred.resolve(data)
+
+    deferred.promise
+
+  # Detailed subtask stats for a single checkpoint
+  @getCheckpointSubtaskDetails = (checkpointid, vertexid) ->
+    deferred = $q.defer()
 
-          if (angular.equals({}, data['subtasks']))
-            deferred.resolve({ operatorStats: operatorStats, subtasksStats: null })
-          else
-            subtaskStats = data['subtasks']
-            deferred.resolve({ operatorStats: operatorStats, subtasksStats: subtaskStats
})
+    deferreds.job.promise.then (data) =>
+      $http.get flinkConfig.jobServer + "jobs/" + currentJob.jid + "/checkpoints/details/"
+ checkpointid + "/subtasks/" + vertexid
+      .success (data) ->
+        # If no data available, we are done.
+        if (angular.equals({}, data))
+          deferred.resolve(null)
+        else
+          deferred.resolve(data)
 
     deferred.promise
 

http://git-wip-us.apache.org/repos/asf/flink/blob/27df8011/flink-runtime-web/web-dashboard/app/styles/job.styl
----------------------------------------------------------------------
diff --git a/flink-runtime-web/web-dashboard/app/styles/job.styl b/flink-runtime-web/web-dashboard/app/styles/job.styl
index e0b11fc..fc61d50 100644
--- a/flink-runtime-web/web-dashboard/app/styles/job.styl
+++ b/flink-runtime-web/web-dashboard/app/styles/job.styl
@@ -50,3 +50,22 @@
   font-family: inherit
   margin-top: -2px
 
+.checkpoints-view {
+  padding-top: 1em
+}
+
+.subtask-details {
+  .blank {
+    height: 2em
+  }
+}
+
+.checkpoint-overview {
+  td span {
+    padding-left: 2em
+  }
+
+  a {
+    color: black;
+  }
+}


Mime
View raw message