Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
107210: jobs: enable downloading execution detail files r=maryliag a=adityamaru

In cockroachdb#106879 we added a table to the `Advanced Debugging`
tab of the job details page. This table lists out all
the execution detail files that are available for the
given job.

This change is a follow up to add download functionality
to each row in the table. The format of the downloaded
file is determined by the prefix of the filename.

A final change to allow users to generate execution details
will be added in the next follow up.

Informs: cockroachdb#105076
Release note: None

107760: spanconfigccl: fix tests under multitenancy r=yuzefovich a=rafiss

fixes cockroachdb#106818
fixes cockroachdb#106821
Release note: None

Co-authored-by: adityamaru <[email protected]>
Co-authored-by: Rafi Shamim <[email protected]>
  • Loading branch information
3 people committed Jul 28, 2023
3 parents 2d47570 + 566f3cb + ee028ba commit 167da65
Show file tree
Hide file tree
Showing 14 changed files with 191 additions and 66 deletions.
19 changes: 7 additions & 12 deletions pkg/ccl/spanconfigccl/spanconfigsplitterccl/datadriven_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,8 +67,7 @@ func TestDataDriven(t *testing.T) {
datadriven.Walk(t, datapathutils.TestDataPath(t), func(t *testing.T, path string) {
tc := testcluster.StartTestCluster(t, 1, base.TestClusterArgs{
ServerArgs: base.TestServerArgs{
// Fails with nil pointer dereference. Tracked with #76378 and #106818.
DefaultTestTenant: base.TestDoesNotWorkWithSecondaryTenantsButWeDontKnowWhyYet(106818),
DefaultTestTenant: base.TestControlsTenantsExplicitly,
Knobs: base.TestingKnobs{
SpanConfig: scKnobs,
},
Expand All @@ -79,15 +78,10 @@ func TestDataDriven(t *testing.T) {
spanConfigTestCluster := spanconfigtestcluster.NewHandle(t, tc, scKnobs)
defer spanConfigTestCluster.Cleanup()

var tenant *spanconfigtestcluster.Tenant
if strings.Contains(path, "tenant") {
tenantID := roachpb.MustMakeTenantID(10)
tenant = spanConfigTestCluster.InitializeTenant(ctx, tenantID)
spanConfigTestCluster.AllowSecondaryTenantToSetZoneConfigurations(t, tenantID)
spanConfigTestCluster.EnsureTenantCanSetZoneConfigurationsOrFatal(t, tenant)
} else {
tenant = spanConfigTestCluster.InitializeTenant(ctx, roachpb.SystemTenantID)
}
tenantID := roachpb.MustMakeTenantID(10)
tenant := spanConfigTestCluster.InitializeTenant(ctx, tenantID)
spanConfigTestCluster.AllowSecondaryTenantToSetZoneConfigurations(t, tenantID)
spanConfigTestCluster.EnsureTenantCanSetZoneConfigurationsOrFatal(t, tenant)

// TODO(irfansharif): Expose this through the test harness once we integrate
// it into the schema changer.
Expand Down Expand Up @@ -119,7 +113,8 @@ func TestDataDriven(t *testing.T) {
var dbName, tbName string
d.ScanArgs(t, "database", &dbName)
d.ScanArgs(t, "table", &tbName)
objID = tenant.LookupTableByName(ctx, dbName, tbName).GetID()
tbl := tenant.LookupTableByName(ctx, dbName, tbName)
objID = tbl.GetID()
default:
d.Fatalf(t, "insufficient/improper args (%v) provided to split", d.CmdArgs)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -287,7 +287,6 @@ func TestSQLWatcherMultiple(t *testing.T) {

tc := testcluster.StartTestCluster(t, 1, base.TestClusterArgs{
ServerArgs: base.TestServerArgs{
DefaultTestTenant: base.TestDoesNotWorkWithSecondaryTenantsButWeDontKnowWhyYet(106821),
Knobs: base.TestingKnobs{
SpanConfig: &spanconfig.TestingKnobs{
ManagerDisableJobCreation: true, // disable the automatic job creation.
Expand All @@ -305,7 +304,7 @@ func TestSQLWatcherMultiple(t *testing.T) {

noopCheckpointDuration := 100 * time.Millisecond
sqlWatcher := spanconfigsqlwatcher.New(
ts.Codec(),
ts.ApplicationLayer().Codec(),
ts.ClusterSettings(),
ts.RangeFeedFactory().(*rangefeed.Factory),
1<<20, /* 1 MB, bufferMemLimit */
Expand Down
19 changes: 18 additions & 1 deletion pkg/ui/workspaces/cluster-ui/src/api/jobProfilerApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,12 @@ export type ListJobProfilerExecutionDetailsRequest =
export type ListJobProfilerExecutionDetailsResponse =
cockroach.server.serverpb.ListJobProfilerExecutionDetailsResponse;

export const getExecutionDetails = (
export type GetJobProfilerExecutionDetailRequest =
cockroach.server.serverpb.GetJobProfilerExecutionDetailRequest;
export type GetJobProfilerExecutionDetailResponse =
cockroach.server.serverpb.GetJobProfilerExecutionDetailResponse;

export const listExecutionDetailFiles = (
req: ListJobProfilerExecutionDetailsRequest,
): Promise<cockroach.server.serverpb.ListJobProfilerExecutionDetailsResponse> => {
return fetchData(
Expand All @@ -27,3 +32,15 @@ export const getExecutionDetails = (
"30M",
);
};

export const getExecutionDetailFile = (
req: GetJobProfilerExecutionDetailRequest,
): Promise<cockroach.server.serverpb.GetJobProfilerExecutionDetailResponse> => {
return fetchData(
cockroach.server.serverpb.GetJobProfilerExecutionDetailResponse,
`/_status/job_profiler_execution_details/${req.job_id}/${req.filename}`,
null,
null,
"30M",
);
};
22 changes: 9 additions & 13 deletions pkg/ui/workspaces/cluster-ui/src/downloadFile/downloadFile.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,16 +15,13 @@ import React, {
useImperativeHandle,
} from "react";

type FileTypes = "text/plain" | "application/json";

export interface DownloadAsFileProps {
fileName?: string;
fileType?: FileTypes;
content?: string;
content?: Blob;
}

export interface DownloadFileRef {
download: (name: string, type: FileTypes, body: string) => void;
download: (name: string, body: Blob) => void;
}

/*
Expand Down Expand Up @@ -58,26 +55,25 @@ export interface DownloadFileRef {
// tslint:disable-next-line:variable-name
export const DownloadFile = forwardRef<DownloadFileRef, DownloadAsFileProps>(
(props, ref) => {
const { children, fileName, fileType, content } = props;
const { children, fileName, content } = props;
const anchorRef = useRef<HTMLAnchorElement>();

const bootstrapFile = (name: string, type: FileTypes, body: string) => {
const bootstrapFile = (name: string, body: Blob) => {
const anchorElement = anchorRef.current;
const file = new Blob([body], { type });
anchorElement.href = URL.createObjectURL(file);
anchorElement.href = URL.createObjectURL(body);
anchorElement.download = name;
};

useEffect(() => {
if (content === undefined) {
return;
}
bootstrapFile(fileName, fileType, content);
}, [fileName, fileType, content]);
bootstrapFile(fileName, content);
}, [fileName, content]);

useImperativeHandle(ref, () => ({
download: (name: string, type: FileTypes, body: string) => {
bootstrapFile(name, type, body);
download: (name: string, body: Blob) => {
bootstrapFile(name, body);
anchorRef.current.click();
},
}));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ import jobStyles from "src/jobs/jobs.module.scss";
import classNames from "classnames/bind";
import { Timestamp } from "../../timestamp";
import {
GetJobProfilerExecutionDetailRequest,
GetJobProfilerExecutionDetailResponse,
ListJobProfilerExecutionDetailsRequest,
ListJobProfilerExecutionDetailsResponse,
RequestState,
Expand All @@ -60,14 +62,17 @@ enum TabKeysEnum {

export interface JobDetailsStateProps {
jobRequest: RequestState<JobResponse>;
jobProfilerResponse: RequestState<ListJobProfilerExecutionDetailsResponse>;
jobProfilerExecutionDetailFilesResponse: RequestState<ListJobProfilerExecutionDetailsResponse>;
jobProfilerLastUpdated: moment.Moment;
jobProfilerDataIsValid: boolean;
onDownloadExecutionFileClicked: (
req: GetJobProfilerExecutionDetailRequest,
) => Promise<GetJobProfilerExecutionDetailResponse>;
}

export interface JobDetailsDispatchProps {
refreshJob: (req: JobRequest) => void;
refreshExecutionDetails: (
refreshExecutionDetailFiles: (
req: ListJobProfilerExecutionDetailsRequest,
) => void;
}
Expand Down Expand Up @@ -130,10 +135,15 @@ export class JobDetails extends React.Component<
return (
<JobProfilerView
jobID={id}
executionDetailsResponse={this.props.jobProfilerResponse}
refreshExecutionDetails={this.props.refreshExecutionDetails}
executionDetailFilesResponse={
this.props.jobProfilerExecutionDetailFilesResponse
}
refreshExecutionDetailFiles={this.props.refreshExecutionDetailFiles}
lastUpdated={this.props.jobProfilerLastUpdated}
isDataValid={this.props.jobProfilerDataIsValid}
onDownloadExecutionFileClicked={
this.props.onDownloadExecutionFileClicked
}
/>
);
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import { selectID } from "../../selectors";
import {
ListJobProfilerExecutionDetailsRequest,
createInitialState,
getExecutionDetailFile,
} from "src/api";
import {
initialState,
Expand All @@ -39,15 +40,17 @@ const mapStateToProps = (
const jobID = selectID(state, props);
return {
jobRequest: state.adminUI?.job?.cachedData[jobID] ?? emptyState,
jobProfilerResponse: state.adminUI?.executionDetails ?? initialState,
jobProfilerLastUpdated: state.adminUI?.executionDetails?.lastUpdated,
jobProfilerDataIsValid: state.adminUI?.executionDetails?.valid,
jobProfilerExecutionDetailFilesResponse:
state.adminUI?.executionDetailFiles ?? initialState,
jobProfilerLastUpdated: state.adminUI?.executionDetailFiles?.lastUpdated,
jobProfilerDataIsValid: state.adminUI?.executionDetailFiles?.valid,
onDownloadExecutionFileClicked: getExecutionDetailFile,
};
};

const mapDispatchToProps = (dispatch: Dispatch): JobDetailsDispatchProps => ({
refreshJob: (req: JobRequest) => jobActions.refresh(req),
refreshExecutionDetails: (req: ListJobProfilerExecutionDetailsRequest) =>
refreshExecutionDetailFiles: (req: ListJobProfilerExecutionDetailsRequest) =>
dispatch(jobProfilerActions.refresh(req)),
});

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,26 @@
@import "src/core/index.module";

.crl-job-profiler-view {
&__actions-column {
display: flex;
flex-direction: row;
flex-wrap: nowrap;
justify-content: flex-end;
}
}

.column-size-medium {
width: 230px;
}

.download-execution-detail-button {
white-space: nowrap;

>svg {
margin-right: $spacing-x-small;
}
}

.sorted-table {
width: 100%;
}
Loading

0 comments on commit 167da65

Please sign in to comment.