Files
impala/www/query_profile.tmpl
Surya Hebbar 42e5ea7ea3 IMPALA-13106: Support larger imported query profile sizes through compression
Imported query profiles are currently being stored in IndexedDB.
Although IndexedDB does not have storage limitations like other
browser storage APIs, there is a storage limit for a single
attribute / field.

For supporting larger query profiles, 'pako' compression library's
v2.1.0 has been added along with its associated license.

Before adding query profile JSON to indexedDB, it undergoes compression
using this library.

As compression and parsing profile is a long running process
that can block the main thread, this has been delegated to
a worker script running in the background. The worker script
returns parsed query attributes and compressed profile text sent to it.

The process of compression consumes time; hence, an alert message is
displayed on the queries page warning user to refrain from closing or
reloading the page. On completion, the raw total size, compressed
total size, and total processing time are logged to the browser console.

When multiple profiles are chosen, after each query profile insertion,
the subsequent one is not triggered until compression and insertion
are finished.

The inserted query profile field is decompressed before parsing on
the query plan, query profile, query statement, and query timeline page.

Added tests for the compression library methods utilized by
the worker script.

Manual testing has been done on Firefox 126.0.1 and Chrome 126.0.6478.

Change-Id: I8c4f31beb9cac89051460bf764b6d50c3933bd03
Reviewed-on: http://gerrit.cloudera.org:8080/21463
Reviewed-by: Impala Public Jenkins <impala-public-jenkins@cloudera.com>
Tested-by: Impala Public Jenkins <impala-public-jenkins@cloudera.com>
2024-06-25 22:06:24 +00:00

128 lines
4.6 KiB
Cheetah

{{?__raw__}}{{{profile}}}{{/__raw__}}
{{^__raw__}}
<!--
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 }}
{{> www/query_detail_tabs.tmpl }}
<script src="{{ __common__.host-url }}/www/scripts/compression_util.js" type="module"></script>
<br/>
<div id="profile_download_section">
<h4>Download Profile (Available Formats):
<a style="font-size:16px;" class="btn btn-primary profile-download"
href="{{ __common__.host-url }}/query_profile_encoded?query_id={{query_id}}"
download="thrift_profile_{{query_id}}">Thrift</a>
<a style="font-size:16px;" class="btn btn-primary profile-download"
href="{{ __common__.host-url }}/query_profile_json?query_id={{query_id}}"
download="json_profile_{{query_id}}">Json</a>
<a style="font-size:16px;" class="btn btn-primary profile-download"
href="{{ __common__.host-url }}/query_profile_plain_text?query_id={{query_id}}"
download="profile_{{query_id}}">Text</a>
</h4>
</div>
<pre id="plain_text_profile_field">{{profile}}</pre>
<script type="module">
$("#profile-tab").addClass("active");
import {inflateParseJSON} from "./www/scripts/compression_util.js";
var dbOpenReq = indexedDB.open("imported_queries");
var db;
var supported_tabs = ["Query", "Timeline", "Text plan", "Profile"];
function profileToString(profile, indent="") {
let info_strings = "";
if (profile.info_strings) {
profile.info_strings.forEach(info => {
info_strings = `${info_strings}${indent} ${info.key}: ${info.value}\n`;
});
}
let event_sequences = "";
if (profile.event_sequences && profile.event_sequences.length > 0) {
event_sequences = `${event_sequences}${indent} Event Sequences:\n`;
profile.event_sequences.forEach(eventSeq => {
event_sequences = `${event_sequences}${indent} Offset: ${eventSeq.offset}\n`;
event_sequences = `${event_sequences}${indent} Events:\n`;
eventSeq.events.forEach(event => {
event_sequences = `${event_sequences}${indent} ${event.label}: ${new Date(event.timestamp).toISOString()}\n`;
});
});
}
let child_profiles = "";
if (profile.child_profiles) {
profile.child_profiles.forEach(childProfile => {
child_profiles = `${child_profiles}${profileToString(childProfile, indent + " ")}`;
});
}
let counters = "";
if (profile.counters && profile.counters.length > 0) {
counters = `${counters}${indent} Counters:\n`;
profile.counters.forEach(counter => {
counters = `${counters}${indent} ${counter.counter_name}: ${counter.value} ${counter.unit}\n`;
});
}
return `${indent}${profile.profile_name}:\n${info_strings}${event_sequences}${child_profiles}${counters}`;
}
document.querySelectorAll('.profile-download').forEach(function (profile_link) {
profile_link.download = profile_link.download.replace(/\W/g,'_');
});
if (window.location.search.includes("imported")) {
profile_download_section.remove();
var alertMessage = document.getElementsByClassName("alert alert-danger")[0];
if (alertMessage) {
alertMessage.remove();
}
var nav_links = document.getElementsByClassName("nav nav-tabs")[0];
nav_links = nav_links.getElementsByClassName("nav-link");
for (var i = 0; i < nav_links.length;) {
if (supported_tabs.includes(nav_links[i].textContent)) {
nav_links[i].href = `${nav_links[i].href}&imported=true`;
i++;
} else {
nav_links[i].parentElement.remove();
}
}
dbOpenReq.onsuccess = (e) => {
db = e.target.result;
db.onerror = (e) => {
console.log("IndexedDB error");
console.log(e);
}
var profileStore = db.transaction("profiles", "readonly").objectStore("profiles");
profileStore.get(getQueryID()).onsuccess = (e) => {
plain_text_profile_field.textContent = profileToString(
inflateParseJSON(e.target.result.profile).contents);
};
};
}
</script>
{{> www/common-footer.tmpl }}
{{/__raw__}}