Skip to content

Commit

Permalink
rename to relation graph
Browse files Browse the repository at this point in the history
  • Loading branch information
kwannoel committed Sep 19, 2024
1 parent abb2a72 commit a6c04ec
Show file tree
Hide file tree
Showing 4 changed files with 94 additions and 96 deletions.
2 changes: 1 addition & 1 deletion dashboard/components/Layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ function Layout({ children }: { children: React.ReactNode }) {
<NavTitle>Streaming</NavTitle>
<NavButton href="/dependency_graph/">Dependency Graph</NavButton>
<NavButton href="/fragment_graph/">Fragment Graph</NavButton>
<NavButton href="/ddl_graph/">Ddl Graph</NavButton>
<NavButton href="/relation_graph/">Relation Graph</NavButton>
</Section>
<Section>
<NavTitle>Batch</NavTitle>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,86 +4,86 @@ import * as d3 from "d3"
import { cloneDeep } from "lodash"
import { Fragment, useCallback, useEffect, useRef } from "react"
import {
DdlBox,
RelationBox,
Edge,
Enter,
Position,
generateDdlEdges,
generateRelationBackPressureEdges,
layoutItem,
} from "../lib/layout"

const nodeRadius = 12
const ddlLayoutX = nodeRadius * 8
const ddlLayoutY = nodeRadius * 8
const ddlNameX = nodeRadius * 4
const ddlNameY = nodeRadius * 7
const ddlMarginX = nodeRadius * 2
const ddlMarginY = nodeRadius * 2

export default function DdlGraph({
ddlDependency,
const relationLayoutX = nodeRadius * 8
const relationLayoutY = nodeRadius * 8
const relationNameX = nodeRadius * 4
const relationNameY = nodeRadius * 7
const relationMarginX = nodeRadius * 2
const relationMarginY = nodeRadius * 2

export default function RelationGraph({
relationDependency,
backPressures,
}: {
ddlDependency: DdlBox[] // Ddl adjacency list, metadata
relationDependency: RelationBox[] // Relation adjacency list, metadata
backPressures?: Map<string, number> // relationId-relationId->back_pressure_rate
}) {
const svgRef = useRef<SVGSVGElement>(null)

const ddlDependencyDagCallback = useCallback(() => {
const ddlDependencyDag = cloneDeep(ddlDependency)
const relationDependencyDagCallback = useCallback(() => {
const relationDependencyDag = cloneDeep(relationDependency)

const layoutDdlResult = new Map<string, any>()
const includedDdlIds = new Set<string>()
for (const ddlBox of ddlDependencyDag) {
let ddlId = ddlBox.id
layoutDdlResult.set(ddlId, {
ddlName: ddlBox.ddlName,
schemaName: ddlBox.schemaName,
const layoutRelationResult = new Map<string, any>()
const includedRelationIds = new Set<string>()
for (const relationBox of relationDependencyDag) {
let relationId = relationBox.id
layoutRelationResult.set(relationId, {
relationName: relationBox.relationName,
schemaName: relationBox.schemaName,
})
includedDdlIds.add(ddlId)
includedRelationIds.add(relationId)
}

const ddlLayout = layoutItem(
ddlDependencyDag.map(({ width: _1, height: _2, id, ...data }) => {
return { width: ddlLayoutX, height: ddlLayoutY, id, ...data }
const relationLayout = layoutItem(
relationDependencyDag.map(({ width: _1, height: _2, id, ...data }) => {
return { width: relationLayoutX, height: relationLayoutY, id, ...data }
}),
ddlMarginX,
ddlMarginY
relationMarginX,
relationMarginY
)

let svgWidth = 0
let svgHeight = 0
ddlLayout.forEach(({ x, y }) => {
svgHeight = Math.max(svgHeight, y + ddlLayoutX)
svgWidth = Math.max(svgWidth, x + ddlLayoutY)
relationLayout.forEach(({ x, y }) => {
svgHeight = Math.max(svgHeight, y + relationLayoutX)
svgWidth = Math.max(svgWidth, x + relationLayoutY)
})
const edges = generateDdlEdges(ddlLayout)
const edges = generateRelationBackPressureEdges(relationLayout)

return {
layoutResult: ddlLayout,
layoutResult: relationLayout,
svgWidth,
svgHeight,
edges,
}
}, [ddlDependency])
}, [relationDependency])

const {
svgWidth,
svgHeight,
edges: ddlEdgeLayout,
layoutResult: ddlLayout,
} = ddlDependencyDagCallback()
edges: relationEdgeLayout,
layoutResult: relationLayout,
} = relationDependencyDagCallback()

useEffect(() => {
if (ddlLayout) {
if (relationLayout) {
const svgNode = svgRef.current
const svgSelection = d3.select(svgNode)

// Ddls
const applyDdl = (gSel: DdlSelection) => {
// Relations
const applyRelation = (gSel: RelationSelection) => {
gSel.attr("transform", ({ x, y }) => `translate(${x}, ${y})`)

// Render ddl name
// Render relation name
{
let text = gSel.select<SVGTextElement>(".text-frag-id")
if (text.empty()) {
Expand All @@ -92,16 +92,16 @@ export default function DdlGraph({

text
.attr("fill", "black")
.text(({ ddlName, schemaName }) => `${schemaName}.${ddlName}`)
.text(({ relationName, schemaName }) => `${schemaName}.${relationName}`)
.attr("font-family", "inherit")
.attr("text-anchor", "middle")
.attr("dx", ddlNameX)
.attr("dy", ddlNameY)
.attr("dx", relationNameX)
.attr("dy", relationNameY)
.attr("fill", "black")
.attr("font-size", 12)
}

// Render ddl node
// Render relation node
{
let circle = gSel.select<SVGCircleElement>("circle")
if (circle.empty()) {
Expand All @@ -114,33 +114,33 @@ export default function DdlGraph({
})

circle
.attr("cx", ddlLayoutX / 2)
.attr("cy", ddlLayoutY / 2)
.attr("cx", relationLayoutX / 2)
.attr("cy", relationLayoutY / 2)
.attr("fill", "white")
.attr("stroke-width", 1)
.attr("stroke", theme.colors.gray[500])
}
}

const createDdl = (sel: Enter<DdlSelection>) =>
sel.append("g").attr("class", "ddl").call(applyDdl)
const createRelation = (sel: Enter<RelationSelection>) =>
sel.append("g").attr("class", "relation").call(applyRelation)

const ddlSelection = svgSelection
.select<SVGGElement>(".ddls")
.selectAll<SVGGElement, null>(".ddl")
.data(ddlLayout)
type DdlSelection = typeof ddlSelection
const relationSelection = svgSelection
.select<SVGGElement>(".relations")
.selectAll<SVGGElement, null>(".relation")
.data(relationLayout)
type RelationSelection = typeof relationSelection

ddlSelection.enter().call(createDdl)
relationSelection.enter().call(createRelation)
// TODO(kwannoel): Is this even needed? I commented it out.
// ddlSelection.call(applyDdl)
ddlSelection.exit().remove()
// relationSelection.call(applyRelation)
relationSelection.exit().remove()

// Ddl Edges
// Relation Edges
const edgeSelection = svgSelection
.select<SVGGElement>(".ddl-edges")
.selectAll<SVGGElement, null>(".ddl-edge")
.data(ddlEdgeLayout)
.select<SVGGElement>(".relation-edges")
.selectAll<SVGGElement, null>(".relation-edge")
.data(relationEdgeLayout)
type EdgeSelection = typeof edgeSelection

const curveStyle = d3.curveMonotoneX
Expand Down Expand Up @@ -208,19 +208,19 @@ export default function DdlGraph({
return gSel
}
const createEdge = (sel: Enter<EdgeSelection>) =>
sel.append("g").attr("class", "ddl-edge").call(applyEdge)
sel.append("g").attr("class", "relation-edge").call(applyEdge)

edgeSelection.enter().call(createEdge)
edgeSelection.call(applyEdge)
edgeSelection.exit().remove()
}
}, [ddlLayout, ddlEdgeLayout, backPressures])
}, [relationLayout, relationEdgeLayout, backPressures])

return (
<Fragment>
<svg ref={svgRef} width={`${svgWidth}px`} height={`${svgHeight}px`}>
<g className="ddl-edges" />
<g className="ddls" />
<g className="relation-edges" />
<g className="relations" />
</svg>
</Fragment>
)
Expand Down
28 changes: 14 additions & 14 deletions dashboard/lib/layout.ts
Original file line number Diff line number Diff line change
Expand Up @@ -293,8 +293,8 @@ export type FragmentBox = LayoutItemBase & {
fragment: TableFragments_Fragment
}

export type DdlBox = LayoutItemBase & {
ddlName: string
export type RelationBox = LayoutItemBase & {
relationName: string
schemaName: string
}

Expand All @@ -310,7 +310,7 @@ export interface Position {

export type FragmentBoxPosition = FragmentBox & Position
export type RelationPointPosition = RelationPoint & Position
export type DdlBoxPosition = DdlBox & Position
export type RelationBoxPosition = RelationBox & Position

export interface Edge {
points: Array<Position>
Expand Down Expand Up @@ -517,27 +517,27 @@ export function generateFragmentEdges(
return links
}

export function generateDdlEdges(layoutMap: DdlBoxPosition[]): Edge[] {
export function generateRelationBackPressureEdges(layoutMap: RelationBoxPosition[]): Edge[] {
const links = []
const ddlMap = new Map<string, DdlBoxPosition>()
const relationMap = new Map<string, RelationBoxPosition>()
for (const x of layoutMap) {
ddlMap.set(x.id, x)
relationMap.set(x.id, x)
}
for (const ddl of layoutMap) {
for (const parentId of ddl.parentIds) {
const parentDdl = ddlMap.get(parentId)!
for (const relation of layoutMap) {
for (const parentId of relation.parentIds) {
const parentRelation = relationMap.get(parentId)!
links.push({
points: [
{
x: ddl.x + ddl.width / 2,
y: ddl.y + ddl.height / 2,
x: relation.x + relation.width / 2,
y: relation.y + relation.height / 2,
},
{
x: parentDdl.x + parentDdl.width / 2,
y: parentDdl.y + parentDdl.height / 2,
x: parentRelation.x + parentRelation.width / 2,
y: parentRelation.y + parentRelation.height / 2,
},
],
source: ddl.id,
source: relation.id,
target: parentId,
})
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ import {
import _ from "lodash"
import Head from "next/head"
import { Fragment, useCallback, useEffect, useMemo, useState } from "react"
import DdlGraph from "../components/DdlGraph"
import RelationGraph from "../components/RelationGraph"
import Title from "../components/Title"
import useErrorToast from "../hook/useErrorToast"
import useFetch from "../lib/api/fetch"
Expand All @@ -44,19 +44,19 @@ import {
getSchemas,
getStreamingJobs, getRelationDependencies,
} from "../lib/api/streaming"
import { DdlBox } from "../lib/layout"
import { RelationBox } from "../lib/layout"
import { BackPressureInfo } from "../proto/gen/monitor_service"

// Refresh interval (ms) for back pressure stats
const INTERVAL_MS = 5000

function buildDdlDependencyAsEdges(relations: StreamingJob[], relationDeps: Map<number, number[]>): DdlBox[] {
function buildRelationDependencyAsEdges(relations: StreamingJob[], relationDeps: Map<number, number[]>): RelationBox[] {
// Filter out non-streaming relations, e.g. source, views.
let relationIds = new Set<number>()
for (const relation of relations) {
relationIds.add(relation.id)
}
const nodes: DdlBox[] = []
const nodes: RelationBox[] = []
for (const relation of relations) {
let parentIds = relationDeps.get(relation.id)
nodes.push({
Expand All @@ -69,7 +69,7 @@ function buildDdlDependencyAsEdges(relations: StreamingJob[], relationDeps: Map<
.filter((x) => relationIds.has(x))
.map((x) => x.toString())
: [],
ddlName: relation.name,
relationName: relation.name,
schemaName: relation.schemaName ? relation.schemaName : "",
})
}
Expand Down Expand Up @@ -107,7 +107,7 @@ export default function Streaming() {
)
}

const ddlDependencyCallback = useCallback(() => {
const relationDependencyCallback = useCallback(() => {
if (relationList) {
if (relationDeps) {
if (schemas) {
Expand All @@ -117,16 +117,14 @@ export default function Streaming() {
)?.name
return { ...relation, schemaName }
})
const ddlDep = buildDdlDependencyAsEdges(relationListWithSchemaName, relationDeps)
return {
ddlDep,
}
const relationDep = buildRelationDependencyAsEdges(relationListWithSchemaName, relationDeps)
return relationDep
}
}
}
}, [relationList, relationDeps, schemas])

const ddlDependency = ddlDependencyCallback()?.ddlDep
const relationDependency = relationDependencyCallback()

const [backPressureDataSource, setBackPressureDataSource] =
useState<BackPressureDataSource>("Embedded")
Expand Down Expand Up @@ -241,7 +239,7 @@ export default function Streaming() {

const retVal = (
<Flex p={3} height="calc(100vh - 20px)" flexDirection="column">
<Title>Ddl Graph</Title>
<Title>Relation Graph</Title>
<Flex flexDirection="row" height="full" width="full">
<VStack
mr={3}
Expand Down Expand Up @@ -281,10 +279,10 @@ export default function Streaming() {
overflowX="scroll"
overflowY="scroll"
>
<Text fontWeight="semibold">Ddl Graph</Text>
{ddlDependency && (
<DdlGraph
ddlDependency={ddlDependency}
<Text fontWeight="semibold">Relation Graph</Text>
{relationDependency && (
<RelationGraph
relationDependency={relationDependency}
backPressures={backPressures}
/>
)}
Expand All @@ -296,7 +294,7 @@ export default function Streaming() {
return (
<Fragment>
<Head>
<title>Ddl Graph</title>
<title>Relation Graph</title>
</Head>
{retVal}
</Fragment>
Expand Down

0 comments on commit a6c04ec

Please sign in to comment.