Skip to content

Commit

Permalink
feat: init optimizer trace (#1187)
Browse files Browse the repository at this point in the history
* feat: init optimizer trace

* update: logical optimizer

* tweak: optimizer trace layout

* fix: index

* update: icon

* update: deps

* tweak: some styles

* udpate: step interface

* tweak: logical optimization step

* tweak: final

* tweak: unselected candidates style

* update: unselected candates style

* deps: use d3-graphviz

* chore: remove webpack chunk name comment

* tweak: error boundary

* chore: clear some deps

* tweak: action info tooltip
  • Loading branch information
shhdgit authored Mar 10, 2022
1 parent 8abc480 commit f8c59bc
Show file tree
Hide file tree
Showing 13 changed files with 656 additions and 1 deletion.
2 changes: 2 additions & 0 deletions ui/dashboardApp/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ import AppContinuousProfiling from '@lib/apps/ContinuousProfiling/index.meta'
import AppQueryEditor from '@lib/apps/QueryEditor/index.meta'
import AppConfiguration from '@lib/apps/Configuration/index.meta'
import AppDebugAPI from '@lib/apps/DebugAPI/index.meta'
import AppOptimizerTrace from '@lib/apps/OptimizerTrace/index.meta'
import { handleSSOCallback, isSSOCallback } from '@lib/utils/authSSO'
import { mustLoadAppInfo, reloadWhoAmI, NgmState } from '@lib/utils/store'
// import __APP_NAME__ from '@lib/apps/__APP_NAME__/index.meta'
Expand Down Expand Up @@ -133,6 +134,7 @@ async function webPageStart() {
.register(AppQueryEditor)
.register(AppConfiguration)
.register(AppDebugAPI)
.register(AppOptimizerTrace)
// .register(__APP_NAME__)
// NOTE: Don't remove above comment line, it is a placeholder for code generator

Expand Down
74 changes: 74 additions & 0 deletions ui/lib/apps/OptimizerTrace/components/LogicalOperatorTree.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import React, { useEffect, useRef } from 'react'
import { graphviz } from 'd3-graphviz'

import styles from './OperatorTree.module.less'

interface LogicalOperatorTreeProps {
data: LogicalOperatorNode[]
labels?: any
className?: string
}

export interface LogicalOperatorNode {
id: number
children: number[] // children id
type: string
cost: number
selected: boolean
property: string
info: string
}

export default function LogicalOperatorTree({
data,
labels = {},
className,
}: LogicalOperatorTreeProps) {
const containerRef = useRef<HTMLDivElement>(null)

useEffect(() => {
const containerEl = containerRef.current
if (!containerEl) {
return
}

const define = data
.map(
(n) =>
`${n.id} ${createLabels({
label: `${n.type}_${n.id}`,
color: labels.color || '',
tooltip: `info: ${n.info}`,
})};\n`
)
.join('')
const link = data
.map((n) =>
(n.children || [])
.map((c) => `${n.id} -> ${c} ${createLabels(labels)};\n`)
.join('')
)
.join('')

graphviz(containerEl).renderDot(
`digraph {
node [shape=ellipse fontsize=8 fontname="Verdana"];
${define}\n${link}\n}`
)
}, [containerRef, data, labels])

return (
<div
ref={containerRef}
className={`${styles.operator_tree} ${className || ''}`}
></div>
)
}

export function createLabels(labels: { [props: string]: string } = {}): string {
const ls = Object.entries(labels).filter(([k, v]) => !!v)
if (!ls.length) {
return ''
}
return `[${ls.map(([k, v]) => `${k}="${v}"`).join(' ')}]`
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
.operator_tree {
height: 300px;
width: 200px;

svg {
height: 100%;
width: 100%;
}
}
67 changes: 67 additions & 0 deletions ui/lib/apps/OptimizerTrace/components/PhysicalOperatorTree.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import React, { useEffect, useRef } from 'react'
import { graphviz } from 'd3-graphviz'

import styles from './OperatorTree.module.less'
import { LogicalOperatorNode, createLabels } from './LogicalOperatorTree'

export interface PhysicalOperatorNode extends LogicalOperatorNode {
parentNode: null | PhysicalOperatorNode
childrenNodes: PhysicalOperatorNode[]
mapping: string
}

interface PhysicalOperatorTreeProps {
data: PhysicalOperatorNode
className?: string
}

export default function PhysicalOperatorTree({
data,
className,
}: PhysicalOperatorTreeProps) {
const containerRef = useRef<HTMLDivElement>(null)

useEffect(() => {
const containerEl = containerRef.current
if (!containerEl) {
return
}

const allDatas = [data, ...(data.childrenNodes || [])]
const define = allDatas
.map(
(n) =>
`${n.id} ${createLabels({
label: `${n.type}_${n.id}\ncost: ${n.cost.toFixed(4)}`,
color: n.selected ? 'blue' : '',
tooltip: `info: ${n.info}`,
})};\n`
)
.join('')
const link = allDatas
.map((n) =>
(n.children || [])
.map(
(c) =>
`${n.id} -- ${c} ${createLabels({
color: n.selected ? 'blue' : '',
})};\n`
)
.join('')
)
.join('')

graphviz(containerEl).renderDot(
`graph {
node [shape=ellipse fontsize=8 fontname="Verdana"];
${define}\n${link}\n}`
)
}, [containerRef, data])

return (
<div
ref={containerRef}
className={`${styles.operator_tree} ${className || ''}`}
></div>
)
}
8 changes: 8 additions & 0 deletions ui/lib/apps/OptimizerTrace/index.meta.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import translations from './translations'

export default {
id: 'optimizer_trace',
routerPrefix: '/optimizer_trace',
translations,
reactRoot: () => import('.'),
}
37 changes: 37 additions & 0 deletions ui/lib/apps/OptimizerTrace/index.module.less
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
.container {
overflow: auto;
}
.operator_tree {
flex-shrink: 0;
}

.logical_optimize {
display: flex;
align-items: center;
}

.arrow {
margin: 0 10px;
}

.physical_operator_tree_container {
display: flex;
align-items: center;
}

.unselected_candidates {
border: dashed 1px #ccc;
margin-left: 10px;
padding: 5px;
}

.steps {
width: 200px;
}

.step_info {
max-height: 90px;
width: 200px;
overflow: hidden;
text-overflow: ellipsis;
}
Loading

0 comments on commit f8c59bc

Please sign in to comment.