From de72bb1cf4ede1588fcbcc5d0af6539ce85f6597 Mon Sep 17 00:00:00 2001 From: Vadim Ogievetsky Date: Wed, 23 Sep 2020 18:40:38 -0700 Subject: [PATCH 1/5] init compaction status --- .../views/datasource-view/datasource-view.tsx | 52 ++++++++++++++++++- 1 file changed, 51 insertions(+), 1 deletion(-) diff --git a/web-console/src/views/datasource-view/datasource-view.tsx b/web-console/src/views/datasource-view/datasource-view.tsx index 20a38e73aeed..5e72eac2d06f 100644 --- a/web-console/src/views/datasource-view/datasource-view.tsx +++ b/web-console/src/views/datasource-view/datasource-view.tsx @@ -78,6 +78,7 @@ const tableColumns: Record = { 'Avg. row size', 'Replicated size', 'Compaction', + 'Compaction status', 'Retention', ACTION_COLUMN_LABEL, ], @@ -88,6 +89,7 @@ const tableColumns: Record = { 'Total data size', 'Segment size', 'Compaction', + 'Compaction status', 'Retention', ACTION_COLUMN_LABEL, ], @@ -131,9 +133,25 @@ function twoLines(line1: string, line2: string) { ); } +interface CompactionStatus { + dataSource: string; + scheduleStatus: string; + bytesAwaitingCompaction: number; + bytesCompacted: number; + bytesSkipped: number; + segmentCountAwaitingCompaction: number; + segmentCountCompacted: number; + segmentCountSkipped: number; + intervalCountAwaitingCompaction: number; + intervalCountCompacted: number; + intervalCountSkipped: number; +} + interface Datasource { datasource: string; rules: Rule[]; + compaction: Record; + compactionStatus: CompactionStatus; [key: string]: any; } @@ -335,12 +353,19 @@ GROUP BY 1`; (c: any) => c.dataSource, ); + const compactionStatusesResp = await axios.get('/druid/coordinator/v1/compaction/status'); + const compactionStatuses = lookupBy( + compactionStatusesResp.data.latestStatus || [], + (c: any) => c.dataSource, + ); + const allDatasources = (datasources as any).concat( unused.map(d => ({ datasource: d, unused: true })), ); - allDatasources.forEach((ds: any) => { + allDatasources.forEach((ds: Datasource) => { ds.rules = rules[ds.datasource] || []; ds.compaction = compaction[ds.datasource]; + ds.compactionStatus = compactionStatuses[ds.datasource]; }); return { @@ -1030,6 +1055,31 @@ GROUP BY 1`; ); }, }, + { + Header: twoLines('Compaction', 'status'), + show: + capabilities.hasCoordinatorAccess() && hiddenColumns.exists('Compaction status'), + id: 'compactionStatus', + accessor: row => Boolean(row.compactionStatus), + filterable: false, + Cell: row => { + const compactionStatus: CompactionStatus = row.original.compactionStatus; + let text: string; + if (compactionStatus) { + const progress = + (compactionStatus.bytesCompacted / + (compactionStatus.bytesAwaitingCompaction + + compactionStatus.bytesCompacted)) * + 100; + text = `${compactionStatus.scheduleStatus} (${progress.toFixed( + 2, + )}%) [${formatBytes(compactionStatus.bytesAwaitingCompaction)}]`; + } else { + text = 'Not enabled'; + } + return text; + }, + }, { Header: 'Retention', show: capabilities.hasCoordinatorAccess() && hiddenColumns.exists('Retention'), From 55cfcb14dbc0ebde040dd5507257de1babb33d85 Mon Sep 17 00:00:00 2001 From: Vadim Ogievetsky Date: Fri, 25 Sep 2020 08:00:13 -0700 Subject: [PATCH 2/5] % compacted --- .../components/more-button/more-button.tsx | 23 ++- .../compaction-dialog/compaction-dialog.tsx | 2 - web-console/src/utils/general.tsx | 4 + .../views/datasource-view/datasource-view.tsx | 141 +++++++++++++----- 4 files changed, 127 insertions(+), 43 deletions(-) diff --git a/web-console/src/components/more-button/more-button.tsx b/web-console/src/components/more-button/more-button.tsx index 7a161b7e4977..4bcef07225f9 100644 --- a/web-console/src/components/more-button/more-button.tsx +++ b/web-console/src/components/more-button/more-button.tsx @@ -18,14 +18,19 @@ import { Button, Menu, Popover, Position } from '@blueprintjs/core'; import { IconNames } from '@blueprintjs/icons'; -import React from 'react'; +import React, { useState } from 'react'; + +type OpenState = 'open' | 'alt-open'; export interface MoreButtonProps { - children: React.ReactNode; + children: React.ReactNode | React.ReactNode[]; + altExtra?: React.ReactNode; } export const MoreButton = React.memo(function MoreButton(props: MoreButtonProps) { - const { children } = props; + const { children, altExtra } = props; + + const [openState, setOpenState] = useState(); let childCount = 0; // Sadly React.Children.count does not ignore nulls correctly @@ -36,8 +41,18 @@ export const MoreButton = React.memo(function MoreButton(props: MoreButtonProps) return ( {children}} + isOpen={Boolean(openState)} + content={ + + {children} + {openState === 'alt-open' && altExtra} + + } position={Position.BOTTOM_LEFT} + onInteraction={(nextOpenState, e: any) => { + if (!e) return; // For some reason this function is always called twice once with e and once without + setOpenState(nextOpenState ? (e.altKey ? 'alt-open' : 'open') : undefined); + }} >