mirror of
https://github.com/apache/impala.git
synced 2025-12-19 09:58:28 -05:00
In the "Fragment Instances" page of a query, even though it is possible to sort the rows based on the fragment's name, it is difficult to distinguish between fragments and their instances. With row grouping based on fragment's name, it becomes easier to distinguish one fragment's instance from the other. The lexographical sorting of instances can still be done based on different columns, which splits the fragment's group and orders the rows lexicographically only based on the column's values. Row grouping has been implemented using the "RowGroup" extension for datatables - https://datatables.net/extensions/rowgroup/. Datatable libraries and its extensions have been added under the directory - "www/datatables". The datatable library's license has been updated according to version 1.13.2, which was previously not updated. The related row grouping extension's license has also been included. Change-Id: If2b7ed6e2a6d605553242a7db4dbeaa7fcae4606 Reviewed-on: http://gerrit.cloudera.org:8080/22226 Reviewed-by: Impala Public Jenkins <impala-public-jenkins@cloudera.com> Tested-by: Impala Public Jenkins <impala-public-jenkins@cloudera.com>
139 lines
4.5 KiB
Cheetah
139 lines
4.5 KiB
Cheetah
<!--
|
|
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.
|
|
-->
|
|
|
|
{{> www/common-header.tmpl }}
|
|
|
|
<link rel="stylesheet" type="text/css" href="{{ __common__.host-url }}/www/datatables/extensions/dataTables.rowGroup-1.5.1.min.css"/>
|
|
<script type="text/javascript" src="{{ __common__.host-url }}/www/datatables/extensions/dataTables.rowGroup-1.5.1.min.js"></script>
|
|
|
|
{{> www/query_detail_tabs.tmpl }}
|
|
<br/>
|
|
{{?backend_instances}}
|
|
<div>
|
|
<label>
|
|
<input type="checkbox" checked="true" id="toggle" onClick="toggleRefresh()"/>
|
|
<span id="refresh_on">Auto-refresh on</span>
|
|
</label> Last updated: <span id="last-updated"></span>
|
|
</div>
|
|
|
|
<br/>
|
|
<table id="finstances" class='table table-hover table-bordered'>
|
|
<thead>
|
|
<tr>
|
|
<th>Host</th>
|
|
<th>Fragment<br/>Name</th>
|
|
<th>Instance ID</th>
|
|
<th>Current state</th>
|
|
<th>Done</th>
|
|
<th>Time since last report (ms)</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
|
|
</tbody>
|
|
</table>
|
|
|
|
<script>
|
|
let interval_id = 0;
|
|
let table = null;
|
|
const refresh = () => {
|
|
table.ajax.reload();
|
|
document.getElementById("last-updated").textContent = new Date();
|
|
};
|
|
|
|
// Unpack Json backend_states by merging the backend host name into every instance stats
|
|
// row. Also clears the last report timestamp field for instances that have not started or
|
|
// have already finished execution.
|
|
function unpackJson(json) {
|
|
const result = new Array();
|
|
if (typeof json.backend_instances === "undefined") {
|
|
// Table will be empty, remove it.
|
|
table.table().destroy(true);
|
|
$("#finstances").remove();
|
|
// Display completion message.
|
|
$("#query_finished_alert").css("visibility", "visible");
|
|
// Stop auto refresh
|
|
$("#toggle").prop("checked", false);
|
|
toggleRefresh();
|
|
return json;
|
|
}
|
|
for (let i = 0; i < json.backend_instances.length; ++i) {
|
|
const backend_state = json.backend_instances[i];
|
|
const instance_stats = backend_state.instance_stats;
|
|
for (let j = 0; j < instance_stats.length; ++j) {
|
|
const instance = instance_stats[j];
|
|
instance.host = backend_state.host;
|
|
if (instance.done) instance.time_since_last_heard_from = "";
|
|
if (!instance.first_status_update_received) {
|
|
instance.time_since_last_heard_from = "";
|
|
}
|
|
delete instance.first_status_update_received;
|
|
result.push(instance);
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
$(document).ready(() => {
|
|
table = $('#finstances').DataTable({
|
|
ajax: { url: make_url("/query_finstances?query_id={{query_id}}&json"),
|
|
dataSrc: unpackJson,
|
|
},
|
|
"columns": [ {data: 'host'},
|
|
{data: 'fragment_name'},
|
|
{data: 'instance_id'},
|
|
{data: 'current_state'},
|
|
{data: 'done'},
|
|
{data: 'time_since_last_heard_from'}],
|
|
"rowGroup": {
|
|
dataSrc : "fragment_name"
|
|
},
|
|
"order": [[ 0, "desc" ]],
|
|
"pageLength": 100
|
|
});
|
|
interval_id = setInterval(refresh, 1000);
|
|
});
|
|
|
|
function toggleRefresh() {
|
|
if (toggle.getElementById("toogle").checked === true) {
|
|
interval_id = setInterval(refresh, 1000);
|
|
document.getElementById("refresh_on").textContent = "Auto-refresh on";
|
|
} else {
|
|
clearInterval(interval_id);
|
|
document.getElementById("refresh_on").textContent = "Auto-refresh off";
|
|
}
|
|
}
|
|
|
|
</script>
|
|
{{/backend_instances}}
|
|
|
|
<div class="alert alert-info" role="alert" id="query_finished_alert"
|
|
style="visibility:hidden">
|
|
Query <strong>{{query_id}}</strong> has completed, or has not started any backends, yet.
|
|
</div>
|
|
{{^backend_instances}}
|
|
<script>$("#query_finished_alert").css("visibility", "visible");</script>
|
|
{{/backend_instances}}
|
|
|
|
<script>
|
|
$("#finstances-tab").addClass("active");
|
|
</script>
|
|
|
|
{{> www/common-footer.tmpl }}
|