Skip to content

Commit

Permalink
Various dashboard improvements for the demo (#481)
Browse files Browse the repository at this point in the history
* UI improvements

* Additional improvements, add generated metrics for visualization

* Shutdown fixes

* Add filtering for screenshot

* Fix formatting, check in new logo

* Fix types
  • Loading branch information
geoffxy authored Mar 22, 2024
1 parent 3bf2524 commit f4e6f7b
Show file tree
Hide file tree
Showing 11 changed files with 82 additions and 23 deletions.
5 changes: 3 additions & 2 deletions src/brad/front_end/front_end.py
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,8 @@ async def serve_forever(self):
await self._run_setup()

# Start FlightSQL server
self._flight_sql_server.start()
if self._flight_sql_server is not None:
self._flight_sql_server.start()

try:
grpc_server = grpc.aio.server()
Expand Down Expand Up @@ -288,7 +289,7 @@ async def _run_teardown(self):
logger.debug("Starting BRAD front end _run_teardown()")

# Shutdown FlightSQL server
if self._flight_sql_server:
if self._flight_sql_server is not None:
self._flight_sql_server.stop()

await self._sessions.end_all_sessions()
Expand Down
42 changes: 37 additions & 5 deletions src/brad/ui/manager_impl.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,14 @@
import uvicorn
import logging
import importlib.resources as pkg_resources
import numpy as np
from fastapi import FastAPI
from fastapi.staticfiles import StaticFiles
from typing import Optional, List

import brad.ui.static as brad_app
from brad.blueprint import Blueprint
from brad.blueprint.table import Table
from brad.blueprint.manager import BlueprintManager
from brad.config.engine import Engine
from brad.config.file import ConfigFile
Expand Down Expand Up @@ -72,13 +74,20 @@ async def serve_forever(self) -> None:


@app.get("/api/1/metrics")
def get_metrics(num_values: int = 3) -> MetricsData:
def get_metrics(num_values: int = 3, use_generated: bool = False) -> MetricsData:
assert manager is not None
metrics = manager.monitor.front_end_metrics().read_k_most_recent(k=num_values)
qlat = metrics[FrontEndMetric.QueryLatencySecondP90.value]
qlat_tm = TimestampedMetrics(timestamps=list(qlat.index), values=list(qlat))
tlat = metrics[FrontEndMetric.TxnLatencySecondP90.value]
tlat_tm = TimestampedMetrics(timestamps=list(tlat.index), values=list(tlat))

if use_generated:
qlat_gen = np.random.normal(loc=15.0, scale=5.0, size=len(qlat))
tlat_gen = np.random.normal(loc=0.015, scale=0.005, size=len(tlat))
qlat_tm.values = list(qlat_gen)
tlat_tm.values = list(tlat_gen)

return MetricsData(
named_metrics={
FrontEndMetric.QueryLatencySecondP90.value: qlat_tm,
Expand All @@ -88,17 +97,40 @@ def get_metrics(num_values: int = 3) -> MetricsData:


@app.get("/api/1/system_state")
def get_system_state() -> SystemState:
def get_system_state(filter_tables_for_demo: bool = False) -> SystemState:
assert manager is not None
blueprint = manager.blueprint_mgr.get_blueprint()
dbp = DisplayableBlueprint.from_blueprint(blueprint)

# TODO: Hardcoded virtualized infrasturcture and writers.
txn_tables = ["theatres", "showings", "ticket_orders", "movie_info", "aka_title"]
txn_only = ["theatres", "showings", "ticket_orders"]

if filter_tables_for_demo:
# To improve how the UI looks in a screenshot, we filter out some tables
# to reduce the amount of information shown. We keep up to 5 +
# len(txn_tables) around (upper bound).
relevant_tables: List[Table] = []
max_tables = min(5, len(blueprint.tables()))
for table in blueprint.tables():
if table.name in txn_tables or len(relevant_tables) < max_tables:
relevant_tables.append(table)

new_locations = {}
for table in relevant_tables:
new_locations[table.name] = blueprint.get_table_locations(table.name)
blueprint = Blueprint(
schema_name=blueprint.schema_name(),
table_schemas=relevant_tables,
table_locations=new_locations,
aurora_provisioning=blueprint.aurora_provisioning(),
redshift_provisioning=blueprint.redshift_provisioning(),
full_routing_policy=blueprint.get_routing_policy(),
)

dbp = DisplayableBlueprint.from_blueprint(blueprint)
vdbe1 = DisplayableVirtualEngine(
name="VDBE 1",
freshness="Serializable",
freshness="No staleness (SI)",
dialect="PostgreSQL SQL",
peak_latency_s=0.030,
tables=[
Expand All @@ -115,7 +147,7 @@ def get_system_state() -> SystemState:
vdbe1.tables.sort(key=lambda t: t.name)
vdbe2 = DisplayableVirtualEngine(
name="VDBE 2",
freshness="≤ 10 minutes stale",
freshness="≤ 10 minutes stale (SI)",
dialect="PostgreSQL SQL",
peak_latency_s=30.0,
tables=[
Expand Down
2 changes: 1 addition & 1 deletion ui/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
href="https://fonts.googleapis.com/css2?family=Source+Sans+3:ital,wght@0,200..900;1,200..900&display=swap"
rel="stylesheet"
/>
<title>BRAD</title>
<title>BRAD Dashboard</title>
</head>
<body>
<div id="root"></div>
Expand Down
4 changes: 3 additions & 1 deletion ui/src/App.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,9 @@ function App() {
useEffect(() => {
let timeoutId = null;
const refreshData = async () => {
const newSystemState = await fetchSystemState();
const newSystemState = await fetchSystemState(
/*filterTablesForDemo=*/ true,
);
// TODO: Not the best way to check for equality.
if (JSON.stringify(systemState) !== JSON.stringify(newSystemState)) {
setSystemState(newSystemState);
Expand Down
14 changes: 10 additions & 4 deletions ui/src/api.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,21 @@ import axios from "axios";

const API_PREFIX = "/api/1";

async function fetchMetrics(numHistoricalValues) {
function flagToString(name, value) {
return `${name}=${value ? "true" : "false"}`;
}

async function fetchMetrics(numHistoricalValues, useGenerated) {
const result = await axios.get(
`${API_PREFIX}/metrics?num_values=${numHistoricalValues}`,
`${API_PREFIX}/metrics?num_values=${numHistoricalValues}&${flagToString("use_generated", useGenerated)}`,
);
return result.data;
}

async function fetchSystemState() {
const result = await axios.get(`${API_PREFIX}/system_state`);
async function fetchSystemState(filterTablesForDemo) {
const result = await axios.get(
`${API_PREFIX}/system_state?${flagToString("filter_tables_for_demo", filterTablesForDemo)}`,
);
return result.data;
}

Expand Down
Binary file added ui/src/assets/brad_logo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
5 changes: 1 addition & 4 deletions ui/src/components/BlueprintView.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,7 @@ function BlueprintView({
onTableHoverExit,
}) {
return (
<Panel
heading="Current Blueprint (Physical Infrastructure)"
className="infra-column-panel"
>
<Panel heading="Physical Infrastructure" className="infra-column-panel">
<div class="bp-view-wrap">
{blueprint &&
blueprint.engines &&
Expand Down
4 changes: 2 additions & 2 deletions ui/src/components/Header.jsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import "./styles/Header.css";
import dbLogo from "../assets/db.svg";
import bradLogo from "../assets/brad_logo.png";

function StatusText({ status, schema }) {
if (!!schema) {
Expand Down Expand Up @@ -28,7 +28,7 @@ function Header() {
<div class="header-inner">
<div class="header-logo">
<div class="header-logo-img">
<img src={dbLogo} style={{ width: "60px", height: "60px" }} />
<img src={bradLogo} />
</div>
<div class="header-logo-txt">
<strong>BRAD</strong> Dashboard
Expand Down
2 changes: 1 addition & 1 deletion ui/src/components/PerfView.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ function PerfView({ virtualInfra }) {
useEffect(() => {
let timeoutId = null;
const refreshData = async () => {
const rawMetrics = await fetchMetrics(60);
const rawMetrics = await fetchMetrics(60, /*useGenerated=*/ true);
const fetchedMetrics = parseMetrics(rawMetrics);
const metricsManager = getMetricsManager();
const addedNewMetrics = metricsManager.mergeInMetrics(fetchedMetrics);
Expand Down
14 changes: 13 additions & 1 deletion ui/src/components/VdbeView.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,16 @@ import {
sortTablesToHoist,
} from "../highlight";

function formatLatencySeconds(latencySeconds) {
const precision = 1;
if (latencySeconds < 1.0) {
// Use milliseconds.
const latencyMs = latencySeconds * 1000;
return `${latencyMs.toFixed(precision)} ms`;
}
return `${latencySeconds.toFixed(precision)} s`;
}

function VdbeView({
name,
freshness,
Expand All @@ -28,7 +38,9 @@ function VdbeView({
<div class="vdbe-view-props">
<ul>
<li>🌿: {freshness}</li>
{peak_latency_s && <li>⏱️: Query Latency ≤ {peak_latency_s} s</li>}
{peak_latency_s && (
<li>⏱️: Query Latency ≤ {formatLatencySeconds(peak_latency_s)}</li>
)}
<li>🗣: {dialect}</li>
</ul>
</div>
Expand Down
13 changes: 11 additions & 2 deletions ui/src/components/styles/Header.css
Original file line number Diff line number Diff line change
Expand Up @@ -32,16 +32,25 @@
.header-logo-img {
margin-top: 10px;
margin-right: 15px;
margin-left: 15px;
}

.header-logo-img img {
width: 55px;
height: 55px;
border-radius: 50%;
border: 2px solid #dae4eb;
}

.header-logo-txt {
font-size: 2.5em;
font-weight: 500;
font-size: 2.2em;
font-weight: 400;
}

.header-status {
display: flex;
align-items: center;
margin-right: 15px;
}

.header-status-text {
Expand Down

0 comments on commit f4e6f7b

Please sign in to comment.