Files
impala/www/query_finstances.tmpl
Surya Hebbar e419964250 IMPALA-13615: Support row grouping of instances based on fragment names
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>
2025-05-22 05:42:18 +00:00

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 }}