mirror of
https://github.com/apache/impala.git
synced 2025-12-19 18:12:08 -05:00
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>
137 lines
5.0 KiB
JavaScript
137 lines
5.0 KiB
JavaScript
// 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.
|
|
|
|
import {maxts, set_maxts, clearDOMChildren} from "./global_members.js";
|
|
|
|
export var exportedForTest;
|
|
// In the data array provided for c3's line chart,
|
|
// 0th element is name of dataset
|
|
// 1st element is zero in all datasets(to compensate missing value for line chart)
|
|
// Hence the values index start at 2
|
|
export var array_values_start_index = 2;
|
|
|
|
function accumulateTimeseriesValues(values_array, time_series_counter, max_samples) {
|
|
var samples = time_series_counter.data.split(",").map(el => parseInt(el));
|
|
var max_traverse_len = Math.min(samples.length, values_array.length - 2);
|
|
if (isNaN(samples[0])) return;
|
|
for (var j = 0; j < max_traverse_len; ++j) {
|
|
values_array[j + 2] += samples[j];
|
|
}
|
|
if (time_series_counter.num > max_samples.collected || time_series_counter.period
|
|
> max_samples.period) {
|
|
max_samples.available = samples.length;
|
|
max_samples.period = time_series_counter.period;
|
|
max_samples.collected = time_series_counter.num;
|
|
}
|
|
}
|
|
|
|
export function generateTimesamples(timesamples_array, max_samples, extend) {
|
|
var avg_period = max_samples.collected * max_samples.period / max_samples.available;
|
|
avg_period = avg_period / 1000;
|
|
var max_traverse_len = Math.min(max_samples.available, timesamples_array.length - 2);
|
|
for (var k = 0; k <= max_traverse_len; ++k) {
|
|
timesamples_array[k + 1] = (k * avg_period);
|
|
}
|
|
if (maxts / 1e9 > timesamples_array[max_samples.available + 1]) {
|
|
// extend by one additional point or correct the final point
|
|
if (extend) {
|
|
// extend
|
|
timesamples_array[max_samples.available + 2] = maxts / 1e9;
|
|
} else {
|
|
// correct
|
|
timesamples_array[max_samples.available + 1] = maxts / 1e9;
|
|
}
|
|
} else {
|
|
set_maxts(timesamples_array[max_samples.available + 1] * 1e9);
|
|
}
|
|
var j = max_samples.available + (extend ? 3 : 2);
|
|
for (; j < timesamples_array.length && timesamples_array[j] != null; ++j) {
|
|
timesamples_array[j] = null;
|
|
}
|
|
}
|
|
|
|
export function mapTimeseriesCounters(time_series_counters, counters) {
|
|
for (var i = 0; i < counters.length; i++) {
|
|
var no_change = true;
|
|
for (var j = 0; j < time_series_counters.length; j++) {
|
|
if (time_series_counters[j].counter_name == counters[i][0]) {
|
|
counters[i][2] = j;
|
|
no_change = false;
|
|
}
|
|
}
|
|
if (no_change) {
|
|
throw new Error(`"${counters[i][0]}" not found within profile`);
|
|
}
|
|
}
|
|
}
|
|
|
|
export function clearTimeseriesValues(values_array, max_samples) {
|
|
var max_traverse_len = Math.min(max_samples.available + 1, values_array.length - 1);
|
|
for (var j = array_values_start_index; j <= max_traverse_len; ++j) {
|
|
values_array[j] = null;
|
|
}
|
|
}
|
|
|
|
export function aggregateProfileTimeseries(parent_profile, aggregate_array,
|
|
counters, max_samples) {
|
|
parent_profile.child_profiles.forEach(function (time_series_profiles) {
|
|
for (var i = 0; i < aggregate_array.length; ++i) {
|
|
accumulateTimeseriesValues(aggregate_array[i],
|
|
time_series_profiles.time_series_counters[counters[i][2]],
|
|
max_samples);
|
|
}
|
|
});
|
|
}
|
|
|
|
export function showTooltip(chart, x) {
|
|
if (chart == undefined) return;
|
|
chart.tooltip.show({x : chart.internal.findClosestFromTargetsByX(
|
|
chart.internal.getTargets(), x).x});
|
|
}
|
|
|
|
export function hideTooltip(chart) {
|
|
if (chart == undefined) return;
|
|
chart.tooltip.hide();
|
|
}
|
|
|
|
export function displayWarning(parent_element, msg, diagram_width, margin_l, margin_r) {
|
|
clearDOMChildren(parent_element);
|
|
parent_element.style.display = "flex";
|
|
parent_element.style.width = `${diagram_width - margin_l - margin_r}px`;
|
|
parent_element.style.height = "200px";
|
|
parent_element.style.justifyContent = "center";
|
|
parent_element.style.alignItems = "center";
|
|
parent_element.style.padding = "20px";
|
|
parent_element.style.textAlign = "center";
|
|
parent_element.style.marginLeft = `${margin_l}px`;
|
|
parent_element.style.border = "1px solid black";
|
|
parent_element.innerHTML = `<span style="color:#ff0f0f;font-size:20px;">${msg}</span>`;
|
|
}
|
|
|
|
export function destroyChart(chart, chart_dom_obj) {
|
|
try {
|
|
chart.destroy();
|
|
} catch (e) {
|
|
}
|
|
clearDOMChildren(chart_dom_obj);
|
|
return null;
|
|
}
|
|
|
|
if (typeof process != "undefined" && process.env.NODE_ENV === 'test') {
|
|
exportedForTest = {accumulateTimeseriesValues};
|
|
}
|