aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMartin Ridgers <[email protected]>2024-11-26 08:53:06 +0100
committerGitHub Enterprise <[email protected]>2024-11-26 08:53:06 +0100
commit642ef2d3606b6a89d0750a88d0f40585965b989d (patch)
tree253f58083014ee902016e42cfe7bda93ea778200 /src
parent5.5.14-pre1 (diff)
downloadzen-642ef2d3606b6a89d0750a88d0f40585965b989d.tar.xz
zen-642ef2d3606b6a89d0750a88d0f40585965b989d.zip
Dashboard: display package data sizes in oplog entry and tree views. (#232)
* Wrong divisor for friendly giga-values * We want Explorer style for kilo/kibi units; round up * var -> const - zero idea if this matters * Include sum of an entry's package data sizes in index * Method to enurate all properties of a loaded oplog index * Include bulkdata size in an oplog index * Found a space that was missing * Show package data sizes when viewing an oplog entry * Navigating a component tree would error out at the end of the chain * Parameterise friendly rounding * Added size and rawsize columns to oplog tree view * Sort of parameterised indexer's worker count and page size * Right-align size columns on entry view page * Updated frontend .zip archive * A changelog update
Diffstat (limited to 'src')
-rw-r--r--src/zenserver/frontend/html.zipbin146336 -> 150189 bytes
-rw-r--r--src/zenserver/frontend/html/indexer/indexer.js12
-rw-r--r--src/zenserver/frontend/html/indexer/worker.js45
-rw-r--r--src/zenserver/frontend/html/pages/entry.js21
-rw-r--r--src/zenserver/frontend/html/pages/tree.js81
-rw-r--r--src/zenserver/frontend/html/util/component.js9
-rw-r--r--src/zenserver/frontend/html/util/friendly.js12
-rw-r--r--src/zenserver/frontend/html/zen.css30
8 files changed, 168 insertions, 42 deletions
diff --git a/src/zenserver/frontend/html.zip b/src/zenserver/frontend/html.zip
index 30d67ea51..5f53d9f38 100644
--- a/src/zenserver/frontend/html.zip
+++ b/src/zenserver/frontend/html.zip
Binary files differ
diff --git a/src/zenserver/frontend/html/indexer/indexer.js b/src/zenserver/frontend/html/indexer/indexer.js
index 5bbb7c352..4412e3a57 100644
--- a/src/zenserver/frontend/html/indexer/indexer.js
+++ b/src/zenserver/frontend/html/indexer/indexer.js
@@ -55,6 +55,13 @@ class Indexer
for (const [_, name] of page)
yield name;
}
+
+ *enum_all()
+ {
+ for (const page of this._pages)
+ for (const [_, name, size, raw_size] of page)
+ yield [name, size|0, raw_size|0];
+ }
}
@@ -90,14 +97,13 @@ async function save(progress_cb, oplog_info, pages)
}
////////////////////////////////////////////////////////////////////////////////
-async function build(progress_cb, oplog_info)
+async function build(progress_cb, oplog_info, max_workers=6, page_size=48 << 10)
{
const project_id = oplog_info["project"];
const oplog = oplog_info["id"];
const init_msg = Message.create(Message.Init, project_id, oplog);
- const worker_n = Math.min(navigator.hardwareConcurrency / 2, 6);
- const page_size = 48 << 10;
+ const worker_n = Math.min(navigator.hardwareConcurrency / 2, max_workers);
const stride = page_size * worker_n;
const end = oplog_info["opcount"];
var entry_count = 0;
diff --git a/src/zenserver/frontend/html/indexer/worker.js b/src/zenserver/frontend/html/indexer/worker.js
index b8183cc6f..25c8d7671 100644
--- a/src/zenserver/frontend/html/indexer/worker.js
+++ b/src/zenserver/frontend/html/indexer/worker.js
@@ -31,7 +31,7 @@ async function map_id_to_key(project_id, oplog, start, end, page_size, stride)
.resource(uri)
.param("start", index)
.param("count", page_size)
- .param("fieldfilter", "packagedata,key")
+ .param("fieldfilter", "packagedata,bulkdata,key")
.cbo()
const entry_count = Math.min(page_size, -(index - end));
@@ -66,34 +66,63 @@ async function map_id_to_key(project_id, oplog, start, end, page_size, stride)
var key = undefined;
var pkg_data = undefined;
+ var bulk_data = undefined;
for (const field of entry)
{
- if (field.is_named("key")) key = field;
+ if (field.is_named("key")) key = field;
else if (field.is_named("packagedata")) pkg_data = field;
+ else if (field.is_named("bulkdata")) bulk_data = field;
}
if (key == undefined || pkg_data == undefined)
continue;
var id = 0n;
- for (var item of pkg_data.as_array())
+ var size = 0;
+ var raw_size = 0;
+ for (const item of pkg_data.as_array())
{
- var pkg_id = item.as_object().find("id");
- if (pkg_id == undefined)
+ var found = 0, pkg_id;
+ for (const field of item.as_object())
+ {
+ if (!id && field.is_named("id")) pkg_id = field.as_value();
+ else if (field.is_named("size")) size += field.as_value();
+ else if (field.is_named("rawsize")) raw_size += field.as_value();
+ else continue;
+ if (found++ >= 3)
+ break;
+ }
+
+ if (pkg_id === undefined)
continue;
- pkg_id = pkg_id.as_value().subarray(0, 8);
+ pkg_id = pkg_id.subarray(0, 8);
for (var i = 7; i >= 0; --i)
{
id <<= 8n;
id |= BigInt(pkg_id[i]);
}
- break;
+ }
+
+ if (bulk_data)
+ {
+ for (const item of bulk_data.as_array())
+ {
+ var found = 0;
+ for (const field of item.as_object())
+ {
+ if (field.is_named("size")) size += field.as_value();
+ else if (field.is_named("rawsize")) raw_size += field.as_value();
+ else continue;
+ if (found++ >= 2)
+ break;
+ }
+ }
}
if (id == 0)
continue;
- result[count] = [id, key.as_value()];
+ result[count] = [id, key.as_value(), size, raw_size];
count++;
}
diff --git a/src/zenserver/frontend/html/pages/entry.js b/src/zenserver/frontend/html/pages/entry.js
index b166d0a6f..a0e3ee915 100644
--- a/src/zenserver/frontend/html/pages/entry.js
+++ b/src/zenserver/frontend/html/pages/entry.js
@@ -4,6 +4,7 @@
import { ZenPage } from "./page.js"
import { Fetcher } from "../util/fetcher.js"
+import { Friendly } from "../util/friendly.js"
import { Table, PropTable, Toolbar, ProgressBar } from "../util/widgets.js"
import { create_indexer } from "../indexer/indexer.js"
@@ -84,7 +85,11 @@ export class Page extends ZenPage
// data
{
const sub_section = section.add_section("data");
- const table = sub_section.add_widget(Table, ["name", "actions"], Table.Flag_PackRight);
+ const table = sub_section.add_widget(
+ Table,
+ ["name", "size", "rawsize", "actions"], Table.Flag_PackRight
+ );
+ table.id("datatable");
for (const field_name of ["packagedata", "bulkdata"])
{
var pkg_data = entry.find(field_name);
@@ -93,12 +98,13 @@ export class Page extends ZenPage
for (const item of pkg_data.as_array())
{
- var io_hash;
- var file_name;
+ var io_hash, size, raw_size, file_name;
for (const field of item.as_object())
{
- if (field.is_named("data")) io_hash = field.as_value();
- else if (field.is_named("filename")) file_name = field.as_value();
+ if (field.is_named("data")) io_hash = field.as_value();
+ else if (field.is_named("filename")) file_name = field.as_value();
+ else if (field.is_named("size")) size = field.as_value();
+ else if (field.is_named("rawsize")) raw_size = field.as_value();
}
if (io_hash instanceof Uint8Array)
@@ -109,7 +115,10 @@ export class Page extends ZenPage
io_hash = ret;
}
- const row = table.add_row(file_name);
+ size = (size !== undefined) ? Friendly.kib(size) : "";
+ raw_size = (raw_size !== undefined) ? Friendly.kib(raw_size) : "";
+
+ const row = table.add_row(file_name, size, raw_size);
const project = this.get_param("project");
const oplog = this.get_param("oplog");
diff --git a/src/zenserver/frontend/html/pages/tree.js b/src/zenserver/frontend/html/pages/tree.js
index c3cea0eb5..23ff3e819 100644
--- a/src/zenserver/frontend/html/pages/tree.js
+++ b/src/zenserver/frontend/html/pages/tree.js
@@ -3,6 +3,7 @@
"use strict";
import { ZenPage } from "./page.js"
+import { Friendly } from "../util/friendly.js"
import { ProgressBar } from "../util/widgets.js"
import { create_indexer } from "../indexer/indexer.js"
@@ -13,17 +14,31 @@ export class Page extends ZenPage
{
const project = this.get_param("project");
const oplog = this.get_param("oplog");
+ const sort_by = this.get_param("sort", -1);
this._indexer = this._load_indexer(project, oplog);
this.set_title("tree - " + oplog);
const section = this.add_section(project + " - " + oplog);
+ this._create_tree(section);
+ this._expand(this._root);
+ this._activate_sort_header(-1, sort_by);
+ }
+
+ _create_tree(section)
+ {
const list = section.tag().id("tree_root").tag("ul");
const root = list.tag("li");
root.attr("part", "/");
- root.tag().text("/");
- this._expand(root);
+ const header = root.tag();
+ header.tag().text("/");
+ this._sort_headers = [
+ header.tag().text("size").on_click(() => this._change_sort(0)),
+ header.tag().text("rawsize").on_click(() => this._change_sort(1)),
+ header.tag().text("count").on_click(() => this._change_sort(2)),
+ ];
+ this._root = root;
}
async _load_indexer(project, oplog)
@@ -47,12 +62,11 @@ export class Page extends ZenPage
if (!item.is("li")) continue;
prefix = item.attr("part") + prefix;
}
- console.log(prefix);
const indexer = await this._indexer;
const new_nodes = new Object();
- for (var name of indexer.enum_names())
+ for (var [name, size, raw_size] of indexer.enum_all())
{
if (!name.startsWith(prefix))
continue;
@@ -62,19 +76,25 @@ export class Page extends ZenPage
if (slash != -1)
name = name.substr(0, slash + 1);
- if (new_nodes[name] === undefined)
- new_nodes[name] = 1;
+ if (new_nodes[name] !== undefined)
+ {
+ new_nodes[name][0] += size;
+ new_nodes[name][1] += raw_size;
+ new_nodes[name][2] += 1;
+ }
else
- new_nodes[name] += 1;
+ new_nodes[name] = [size, raw_size, 1];
}
- const by_count = this.get_param("bycount", 0)|0;
+ var sort_by = this.get_param("sort", -1)|0;
+ sort_by = Math.min(Math.max(sort_by, -1), 3);
+
const sorted_keys = Object.keys(new_nodes).sort((l, r) => {
const is_node_l = l.endsWith("/");
const any_nodes = is_node_l + r.endsWith("/");
- if (any_nodes == 0) return r < l;
if (any_nodes == 1) return is_node_l ? -1 : 1;
- return by_count ? (new_nodes[r] - new_nodes[l]) : (r < l);
+ if (sort_by >= 0) return (new_nodes[r][sort_by] - new_nodes[l][sort_by]);
+ return r < l;
})
const list = node.tag("ul");
@@ -83,10 +103,18 @@ export class Page extends ZenPage
const item = list.tag("li").attr("part", name);
const info = item.tag();
const label = info.tag().text(name);
+
+ for (var i = 0; i < 2; ++i)
+ {
+ const size = Friendly.kib(new_nodes[name][i]);
+ info.tag().text(size);
+ }
+
if (name.endsWith("/"))
{
+ const count = Friendly.sep(new_nodes[name][2]);
+ info.tag().text(count);
label.on_click((x) => this.expand_collapse(x), item);
- info.tag().text(new_nodes[name]);
continue;
}
@@ -115,4 +143,35 @@ export class Page extends ZenPage
return this._expand(node);
return this._collapse(node);
}
+
+ _activate_sort_header(current, next)
+ {
+ const impl = (index, is_on) => {
+ if (index >= 0 && index < this._sort_headers.length)
+ this._sort_headers[index].attr("active", is_on ? "" : null);
+ };
+ impl(current, false);
+ impl(next, true);
+ }
+
+ _change_sort(sort_by)
+ {
+ const current = this.get_param("sort");
+ if (current == sort_by)
+ sort_by = -1;
+
+ this._activate_sort_header(current, sort_by);
+
+ this.set_param("sort", sort_by);
+
+ for (var node = this._root.first_child(); node;)
+ {
+ const next = node.next_sibling();
+ if (node.is("ul"))
+ node.destroy();
+ node = next;
+ }
+
+ this._expand(this._root);
+ }
}
diff --git a/src/zenserver/frontend/html/util/component.js b/src/zenserver/frontend/html/util/component.js
index 39a9f2fe6..205aa038e 100644
--- a/src/zenserver/frontend/html/util/component.js
+++ b/src/zenserver/frontend/html/util/component.js
@@ -20,17 +20,20 @@ class ComponentBase
parent()
{
- return this.new_component(this._element.parentElement);
+ const e = this._element.parentElement;
+ return e ? this.new_component(e) : null;
}
first_child()
{
- return this.new_component(this._element.firstElementChild);
+ const e = this._element.firstElementChild;
+ return e ? this.new_component(e) : null;
}
next_sibling()
{
- return this.new_component(this._element.nextElementSibling);
+ const e = this._element.nextElementSibling;
+ return e ? this.new_component(e) : null;
}
destroy()
diff --git a/src/zenserver/frontend/html/util/friendly.js b/src/zenserver/frontend/html/util/friendly.js
index 6eee3a5b8..b27721964 100644
--- a/src/zenserver/frontend/html/util/friendly.js
+++ b/src/zenserver/frontend/html/util/friendly.js
@@ -14,10 +14,10 @@ export class Friendly
});
}
- static k(x) { return Friendly.sep((x + 999) / Math.pow(10, 3), 0) + "K"; }
- static m(x) { return Friendly.sep( x / Math.pow(10, 6), 1) + "M"; }
- static g(x) { return Friendly.sep( x / Math.pow(10, 6), 2) + "G"; }
- static kib(x) { return Friendly.sep((x + 1023) / (1 << 10), 0) + " KiB"; }
- static mib(x) { return Friendly.sep( x / (1 << 20), 1) + " MiB"; }
- static gib(x) { return Friendly.sep( x / (1 << 30), 2) + " GiB"; }
+ static k(x, p=0) { return Friendly.sep((x + 999) / Math.pow(10, 3)|0, p) + "K"; }
+ static m(x, p=1) { return Friendly.sep( x / Math.pow(10, 6), p) + "M"; }
+ static g(x, p=2) { return Friendly.sep( x / Math.pow(10, 9), p) + "G"; }
+ static kib(x, p=0) { return Friendly.sep((x + 1023) / (1 << 10)|0, p) + " KiB"; }
+ static mib(x, p=1) { return Friendly.sep( x / (1 << 20), p) + " MiB"; }
+ static gib(x, p=2) { return Friendly.sep( x / (1 << 30), p) + " GiB"; }
}
diff --git a/src/zenserver/frontend/html/zen.css b/src/zenserver/frontend/html/zen.css
index 2463a6b5d..c9dc0d83e 100644
--- a/src/zenserver/frontend/html/zen.css
+++ b/src/zenserver/frontend/html/zen.css
@@ -405,17 +405,26 @@ a {
min-width: 15%;
}
+/* entry -------------------------------------------------------------------- */
+
+#entry {
+ #datatable > div {
+ > div:nth-child(3), > div:nth-child(4) {
+ text-align: right;
+ }
+ }
+}
+
/* tree --------------------------------------------------------------------- */
#tree {
- #tree_root {
- margin-left: 5em;
- margin-right: 10em;
+ #tree_root > ul {
+ margin-left: 0em;
}
ul {
list-style-type: none;
padding-left: 0;
- margin-left: 2em;
+ margin-left: 1em;
}
li > div {
display: flex;
@@ -423,9 +432,20 @@ a {
padding-left: 0.3em;
padding-right: 0.3em;
}
- li > div > div:last-child {
+ li > div > div[active] {
+ text-transform: uppercase;
+ }
+ li > div > div:nth-last-child(3) {
margin-left: auto;
}
+ li > div > div:nth-last-child(-n + 3) {
+ font-size: 0.8em;
+ width: 10em;
+ text-align: right;
+ }
+ li > div > div:nth-last-child(1) {
+ width: 6em;
+ }
li > div:hover {
background-color: var(--theme_p4);
border-bottom: 1px solid var(--theme_g2);