Add processors tab (#23634)

Co-authored-by: Cory Rivera <corivera@microsoft.com>
This commit is contained in:
Barbara Valdez
2023-08-21 10:52:55 -07:00
committed by GitHub
parent fb2f8492d5
commit 60bff01240
5 changed files with 161 additions and 5 deletions

View File

@@ -30,6 +30,7 @@ export const AlterDatabaseRoleDocUrl = 'https://learn.microsoft.com/sql/t-sql/st
export const CreateDatabaseDocUrl = 'https://learn.microsoft.com/sql/t-sql/statements/create-database-transact-sql';
export const ViewGeneralServerPropertiesDocUrl = 'https://learn.microsoft.com/sql/t-sql/functions/serverproperty-transact-sql';
export const ViewMemoryServerPropertiesDocUrl = 'https://learn.microsoft.com/sql/database-engine/configure-windows/server-properties-memory-page';
export const ViewProcessorsServerPropertiesDocUrl = 'https://learn.microsoft.com/sql/database-engine/configure-windows/server-properties-processors-page';
export const DetachDatabaseDocUrl = 'https://go.microsoft.com/fwlink/?linkid=2240322';
export const DatabaseGeneralPropertiesDocUrl = 'https://learn.microsoft.com/sql/relational-databases/databases/database-properties-general-page';
export const DatabaseOptionsPropertiesDocUrl = 'https://learn.microsoft.com/sql/relational-databases/databases/database-properties-options-page'

View File

@@ -495,6 +495,22 @@ export interface AzureEditionDetails {
editionOptions: OptionsCollection;
}
export interface ProcessorAffinity {
processorId: string;
affinity: boolean;
ioAffinity: boolean;
}
export interface NumaNode {
numaNodeId: string
processors: ProcessorAffinity[]
}
export enum AffinityType {
ProcessorAffinity = 1,
IOAffinity = 2,
}
export interface Server extends ObjectManagement.SqlObject {
hardwareGeneration: string;
language: string;
@@ -515,6 +531,9 @@ export interface Server extends ObjectManagement.SqlObject {
storageSpaceUsageInMB: number;
minServerMemory: NumericServerProperty;
maxServerMemory: NumericServerProperty;
autoProcessorAffinityMaskForAll: boolean;
autoProcessorAffinityIOMaskForAll: boolean;
numaNodes: NumaNode[];
}
export interface NumericServerProperty {

View File

@@ -277,7 +277,15 @@ export const StorageSpaceUsageInMBText = localize('objectManagement.storageSpace
export const VersionText = localize('objectManagement.versionText', "Version");
export const minServerMemoryText = localize('objectManagement.minServerMemoryText', "Minimum Server Memory (MB)");
export const maxServerMemoryText = localize('objectManagement.maxServerMemoryText', "Maximum Server Memory (MB)");
export const serverMemoryMaxLowerThanMinInputError: string = localize('objectManagement.serverMemoryMaxLowerThanMinInputError', "Maximum server memory cannot be lower than minimum server memory")
export const autoSetProcessorAffinityMaskForAllText = localize('objectManagement.autoSetProcessorAffinityMaskForAll', "Automatically set processor affinity mask for all processors");
export const autoSetProcessorAffinityIOMaskForAllText = localize('objectManagement.autoSetProcessorAffinityIOMaskForAll', "Automatically set I/O affinity mask for all processors");
export const processorColumnText = localize('objectManagement.processorColumn', "Processor");
export const processorAffinityColumnText = localize('objectManagement.processorAffinityColumn', "Processor Affinity");
export const processorIOAffinityColumnText = localize('objectManagement.processorIOAffinityColumn', "I/O Affinity");
export const processorLabel = localize('objectManagement.processorLabel', "Processor Affinity Table");
export const serverMemoryMaxLowerThanMinInputError: string = localize('objectManagement.serverMemoryMaxLowerThanMinInputError', "Maximum server memory cannot be lower than minimum server memory");
export const serverNumaNodeLabel = (value: string) => localize('objectManagement.serverNumaNodeLabel', "Numa Node {0}", value);
export const serverCPULabel = (value: string) => localize('objectManagement.serverCPULabel', "CPU {0}", value);
//Database properties Dialog
export const LastDatabaseBackupText = localize('objectManagement.lastDatabaseBackup', "Last Database Backup");

View File

@@ -4,10 +4,11 @@
*--------------------------------------------------------------------------------------------*/
import * as azdata from 'azdata';
import { ObjectManagementDialogBase, ObjectManagementDialogOptions } from './objectManagementDialogBase';
import { DefaultColumnCheckboxWidth } from '../../ui/dialogBase';
import { IObjectManagementService } from 'mssql';
import * as localizedConstants from '../localizedConstants';
import { ViewGeneralServerPropertiesDocUrl, ViewMemoryServerPropertiesDocUrl } from '../constants';
import { Server, ServerViewInfo } from '../interfaces';
import { ViewGeneralServerPropertiesDocUrl, ViewMemoryServerPropertiesDocUrl, ViewProcessorsServerPropertiesDocUrl } from '../constants';
import { Server, ServerViewInfo, NumaNode, AffinityType } from '../interfaces';
export class ServerPropertiesDialog extends ObjectManagementDialogBase<Server, ServerViewInfo> {
private generalTab: azdata.Tab;
@@ -40,6 +41,11 @@ export class ServerPropertiesDialog extends ObjectManagementDialogBase<Server, S
private maxServerMemoryInput: azdata.InputBoxComponent;
private engineEdition: azdata.DatabaseEngineEdition;
private processorsTab: azdata.Tab;
private readonly processorsTabId: string = 'processorsId';
private processorsSection: azdata.GroupContainer;
private autoSetProcessorAffinityMaskForAllCheckbox: azdata.CheckBoxComponent;
private autoSetProcessorIOAffinityMaskForAllCheckbox: azdata.CheckBoxComponent;
private activeTabId: string;
constructor(objectManagementService: IObjectManagementService, options: ObjectManagementDialogOptions) {
@@ -55,6 +61,8 @@ export class ServerPropertiesDialog extends ObjectManagementDialogBase<Server, S
break;
case this.memoryTabId:
helpUrl = ViewMemoryServerPropertiesDocUrl;
case this.processorsTabId:
helpUrl = ViewProcessorsServerPropertiesDocUrl;
default:
break;
}
@@ -71,7 +79,8 @@ export class ServerPropertiesDialog extends ObjectManagementDialogBase<Server, S
this.engineEdition = serverInfo.engineEditionId;
this.initializeGeneralSection();
this.initializeMemorySection();
const serverPropertiesTabGroup = { title: '', tabs: [this.generalTab, this.memoryTab] };
this.initializeProcessorsSection();
const serverPropertiesTabGroup = { title: '', tabs: [this.generalTab, this.memoryTab, this.processorsTab] };
const serverPropertiesTabbedPannel = this.modelView.modelBuilder.tabbedPanel()
.withTabs([serverPropertiesTabGroup])
.withProps({
@@ -269,6 +278,7 @@ export class ServerPropertiesDialog extends ObjectManagementDialogBase<Server, S
enabled: isEnabled,
max: this.objectInfo.minServerMemory.maximumValue,
min: this.objectInfo.minServerMemory.minimumValue,
value: this.objectInfo.minServerMemory.value.toString(),
required: true
};
this.minServerMemoryInput = this.createInputBox(async (newValue) => {
@@ -282,6 +292,7 @@ export class ServerPropertiesDialog extends ObjectManagementDialogBase<Server, S
enabled: isEnabled,
max: this.objectInfo.maxServerMemory.maximumValue,
min: this.objectInfo.maxServerMemory.minimumValue,
value: this.objectInfo.maxServerMemory.value.toString(),
required: true
};
this.maxServerMemoryInput = this.createInputBox(async (newValue) => {
@@ -304,4 +315,120 @@ export class ServerPropertiesDialog extends ObjectManagementDialogBase<Server, S
}
return errors;
}
private initializeProcessorsSection(): void {
const isEnabled = this.engineEdition !== azdata.DatabaseEngineEdition.SqlManagedInstance;
let nodes: NumaNode[] = this.objectInfo.numaNodes;
let nodeTableList: azdata.TableComponent[] = [];
let tableGroups: azdata.GroupContainer[] = [];
for (let node of nodes) {
let table = this.createProcessorTable(node);
nodeTableList.push(table);
tableGroups.push(this.createGroup(localizedConstants.serverNumaNodeLabel(node.numaNodeId), [table], true));
}
this.autoSetProcessorAffinityMaskForAllCheckbox = this.createCheckbox(localizedConstants.autoSetProcessorAffinityMaskForAllText, async (newValue) => {
this.objectInfo.autoProcessorAffinityMaskForAll = newValue;
for (let table of nodeTableList) {
let newData = table.data;
for (let i = 0; i < newData.length; i++) {
if (newValue) {
// if affinity mask for all is checked, then uncheck the individual processors
newData[i][AffinityType.ProcessorAffinity] = false;
}
}
await this.setTableData(table, newData);
}
}, this.objectInfo.autoProcessorAffinityMaskForAll, isEnabled);
this.autoSetProcessorIOAffinityMaskForAllCheckbox = this.createCheckbox(localizedConstants.autoSetProcessorAffinityIOMaskForAllText, async (newValue) => {
this.objectInfo.autoProcessorAffinityIOMaskForAll = newValue;
for (let table of nodeTableList) {
let newData = table.data;
for (let i = 0; i < newData.length; i++) {
if (newValue) {
// if IO affinity mask for all is checked, then uncheck the individual processors
newData[i][AffinityType.IOAffinity] = false;
}
}
await this.setTableData(table, newData);
this.resetNumaNodes();
}
}, this.objectInfo.autoProcessorAffinityIOMaskForAll, isEnabled);
this.processorsSection = this.createGroup('', [
this.autoSetProcessorAffinityMaskForAllCheckbox,
this.autoSetProcessorIOAffinityMaskForAllCheckbox,
], false);
this.processorsSection.addItems(tableGroups);
this.processorsTab = this.createTab(this.processorsTabId, localizedConstants.ProcessorsText, this.processorsSection);
}
private createProcessorTable(numaNode: NumaNode): azdata.TableComponent {
const cssClass = 'no-borders';
let tableData = numaNode.processors.map(row => [localizedConstants.serverCPULabel(row.processorId), row.affinity, row.ioAffinity]);
let processorTable = this.createTable(localizedConstants.processorLabel,
[
<azdata.TableColumn>{
name: localizedConstants.processorColumnText,
value: localizedConstants.processorColumnText,
type: azdata.ColumnType.text,
cssClass: cssClass,
headerCssClass: cssClass,
},
<azdata.TableColumn>{
name: localizedConstants.processorAffinityColumnText,
value: localizedConstants.processorAffinityColumnText,
type: azdata.ColumnType.checkBox,
width: DefaultColumnCheckboxWidth,
action: azdata.ActionOnCellCheckboxCheck.customAction,
cssClass: cssClass,
headerCssClass: cssClass,
},
<azdata.TableColumn>{
name: localizedConstants.processorIOAffinityColumnText,
value: localizedConstants.processorIOAffinityColumnText,
type: azdata.ColumnType.checkBox,
width: DefaultColumnCheckboxWidth,
action: azdata.ActionOnCellCheckboxCheck.customAction,
cssClass: cssClass,
headerCssClass: cssClass,
}
], tableData);
this.disposables.push(processorTable.onCellAction(async (row) => {
if (processorTable.selectedRows.length > 0) {
const result = processorTable.data;
let checkboxState = <azdata.ICheckboxCellActionEventArgs>row;
let columnToAdjust = checkboxState.column === AffinityType.ProcessorAffinity ? AffinityType.IOAffinity : AffinityType.ProcessorAffinity;
if (result[checkboxState.row][columnToAdjust]) {
result[checkboxState.row][columnToAdjust] = !checkboxState.checked;
processorTable.updateCells = result[checkboxState.row];
}
// uncheck the set all processors checkbox
if (checkboxState.column === AffinityType.ProcessorAffinity) {
this.autoSetProcessorAffinityMaskForAllCheckbox.checked = false;
this.objectInfo.autoProcessorAffinityMaskForAll = false;
this.objectInfo.numaNodes[+numaNode.numaNodeId].processors[checkboxState.row].affinity = checkboxState.checked;
this.objectInfo.numaNodes[+numaNode.numaNodeId].processors[checkboxState.row].ioAffinity = false;
}
if (checkboxState.column === AffinityType.IOAffinity) {
this.autoSetProcessorIOAffinityMaskForAllCheckbox.checked = false;
this.objectInfo.autoProcessorAffinityIOMaskForAll = false;
this.objectInfo.numaNodes[+numaNode.numaNodeId].processors[checkboxState.row].ioAffinity = checkboxState.checked;
this.objectInfo.numaNodes[+numaNode.numaNodeId].processors[checkboxState.row].affinity = false;
}
this.onFormFieldChange();
}
}));
return processorTable;
}
private resetNumaNodes(): void {
for (let node of this.objectInfo.numaNodes) {
for (let cpu of node.processors) {
cpu.ioAffinity = false;
}
}
}
}

View File

@@ -10,6 +10,7 @@ import * as uiLoc from '../ui/localizedConstants';
export const DefaultLabelWidth = 150;
export const DefaultInputWidth = 300;
export const DefaultColumnCheckboxWidth = 150;
export const DefaultTableWidth = DefaultInputWidth + DefaultLabelWidth;
export const DefaultMaxTableRowCount = 10;
export const DefaultMinTableRowCount = 1;
@@ -255,7 +256,7 @@ export abstract class DialogBase<DialogResult> {
});
}
protected createTable(ariaLabel: string, columns: string[], data: any[][], maxRowCount: number = DefaultMaxTableRowCount): azdata.TableComponent {
protected createTable(ariaLabel: string, columns: string[] | azdata.TableColumn[], data: any[][], maxRowCount: number = DefaultMaxTableRowCount): azdata.TableComponent {
const table = this.modelView.modelBuilder.table().withProps(
{
ariaLabel: ariaLabel,