From 16c7e323567023b08200ab35b2bfb2a5042385e0 Mon Sep 17 00:00:00 2001
From: Barbara Valdez <34872381+barbaravaldez@users.noreply.github.com>
Date: Mon, 21 Aug 2023 13:24:48 -0700
Subject: [PATCH] Add processors tab (#2166)
---
.../ObjectTypes/Server/ServerHandler.cs | 5 +-
.../ObjectTypes/Server/ServerInfo.cs | 17 +
.../ObjectTypes/Server/ServerProcessor.cs | 221 ++++++++++
.../ObjectTypes/Server/ServerPrototype.cs | 402 +++++++++++++++++-
.../ObjectManagement/ServerHandlerTests.cs | 59 ++-
5 files changed, 698 insertions(+), 6 deletions(-)
create mode 100644 src/Microsoft.SqlTools.ServiceLayer/ObjectManagement/ObjectTypes/Server/ServerProcessor.cs
diff --git a/src/Microsoft.SqlTools.ServiceLayer/ObjectManagement/ObjectTypes/Server/ServerHandler.cs b/src/Microsoft.SqlTools.ServiceLayer/ObjectManagement/ObjectTypes/Server/ServerHandler.cs
index dc691d25..55b4f153 100644
--- a/src/Microsoft.SqlTools.ServiceLayer/ObjectManagement/ObjectTypes/Server/ServerHandler.cs
+++ b/src/Microsoft.SqlTools.ServiceLayer/ObjectManagement/ObjectTypes/Server/ServerHandler.cs
@@ -63,7 +63,10 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectManagement
StorageSpaceUsageInMB = prototype.StorageSpaceUsageInMB,
Version = prototype.Version,
MinServerMemory = prototype.MinServerMemory,
- MaxServerMemory = prototype.MaxServerMemory
+ MaxServerMemory = prototype.MaxServerMemory,
+ AutoProcessorAffinityMaskForAll = prototype.AutoProcessorAffinityMaskForAll,
+ AutoProcessorAffinityIOMaskForAll = prototype.AutoProcessorAffinityIOMaskForAll,
+ NumaNodes = prototype.NumaNodes
};
}
return Task.FromResult(new InitializeViewResult { ViewInfo = this.serverViewInfo, Context = context });
diff --git a/src/Microsoft.SqlTools.ServiceLayer/ObjectManagement/ObjectTypes/Server/ServerInfo.cs b/src/Microsoft.SqlTools.ServiceLayer/ObjectManagement/ObjectTypes/Server/ServerInfo.cs
index a900fd7a..9d8cad7c 100644
--- a/src/Microsoft.SqlTools.ServiceLayer/ObjectManagement/ObjectTypes/Server/ServerInfo.cs
+++ b/src/Microsoft.SqlTools.ServiceLayer/ObjectManagement/ObjectTypes/Server/ServerInfo.cs
@@ -4,6 +4,8 @@
//
#nullable disable
+using System.Collections.Generic;
+
namespace Microsoft.SqlTools.ServiceLayer.ObjectManagement
{
///
@@ -30,6 +32,9 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectManagement
public string Version { get; set; }
public NumericServerProperty MaxServerMemory { get; set; }
public NumericServerProperty MinServerMemory { get; set; }
+ public bool AutoProcessorAffinityMaskForAll { get; set; }
+ public bool AutoProcessorAffinityIOMaskForAll { get; set; }
+ public List NumaNodes { get; set; }
}
public class NumericServerProperty
@@ -38,4 +43,16 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectManagement
public int MinimumValue { get; set; }
public int Value { get; set; }
}
+ public class NumaNode
+ {
+ public string NumaNodeId { get; set; }
+ public List Processors { get; set; }
+ }
+
+ public class ProcessorAffinity
+ {
+ public string ProcessorId { get; set; }
+ public bool Affinity { get; set; }
+ public bool IOAffinity { get; set; }
+ }
}
\ No newline at end of file
diff --git a/src/Microsoft.SqlTools.ServiceLayer/ObjectManagement/ObjectTypes/Server/ServerProcessor.cs b/src/Microsoft.SqlTools.ServiceLayer/ObjectManagement/ObjectTypes/Server/ServerProcessor.cs
new file mode 100644
index 00000000..08b05351
--- /dev/null
+++ b/src/Microsoft.SqlTools.ServiceLayer/ObjectManagement/ObjectTypes/Server/ServerProcessor.cs
@@ -0,0 +1,221 @@
+//
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+//
+
+using System;
+using System.Collections;
+using SMO = Microsoft.SqlServer.Management.Smo;
+
+namespace Microsoft.SqlTools.ServiceLayer.ObjectManagement.ObjectTypes.Server
+{
+ ///
+ /// Class to manage affinity for 64 processors in an independent manner for I/O as well as processors
+ ///
+ internal sealed class AffinityManager
+ {
+ public const int MAX64CPU = 64;
+ public const int MAX32CPU = 32;
+ public const int MAX_IO_CPU_SUPPORTED = 64;
+
+ public BitArray initialIOAffinityArray = new BitArray(64, false);
+
+ private static string[] configFields = new string[]
+ {
+ "Minimum",
+ "Maximum",
+ "Dynamic",
+ "ConfigValue",
+ "RunValue"
+ };
+ #region class Affinity representing data related to each affinity mask
+ ///
+ /// The Affinity structure represents one row of the sys.configuration table for
+ /// that particular affinity (affinity,affinty64 for processor or I/O).
+ /// It also stores the old value of the affinity for optimizing server query.
+ ///
+ private class Affinity
+ {
+ private int affinityMaskCfg = 0;
+ private int affinityMaskRun = 0;
+ ///
+ /// Affinity ConfigValue reflecting sys.configurations table
+ ///
+ public int AffinityMaskCfg { get { return affinityMaskCfg; } set { affinityMaskCfg = value; } }
+ ///
+ /// Affinity RunValue reflecting sys.configurations table
+ ///
+ public int AffinityMaskRun { get { return affinityMaskRun; } set { affinityMaskRun = value; } }
+
+ /// Reset the affinities to default values.
+ ///
+ public void Clear()
+ {
+ affinityMaskCfg = 0;
+ affinityMaskRun = 0;
+ }
+ };
+ #endregion
+
+ ///
+ /// Generates a mask for masking the N processors
+ ///
+ /// number of processors to mask
+ /// Mask for numProcessors
+ private int GetMaskAllProcessors(int numProcessors)
+ {
+ if (numProcessors < MAX32CPU)
+ {
+ try
+ {
+ return System.Convert.ToInt32(Math.Pow(2, numProcessors) - 1);
+ }
+ catch (System.OverflowException)
+ {
+ return int.MaxValue;
+ }
+ }
+ else
+ {
+ // Earlier code used int.MaxValue for return which was buggy
+ // since in 2's compliment notation -1 is the one with all bits
+ // set to 1. [anchals]
+ return (int)-1;
+ }
+ }
+
+ ///
+ /// Lets the caller know if only one CPU is selected. The processor number for the only set CPU is
+ /// passed in. The method is optimized this way otherwise it needs to count the number of 1's in the
+ /// affinity mask to see if only one CPU is selected.
+ ///
+ /// The CPU number for which affinity is to be set. Range: [0, 63]
+ /// true: this is the last CPU which has affinity bit set;
+ /// false: some other CPU than processorNumber is having affinity bit set.
+ public bool IsThisLastSelectedProcessor(int processorNumber)
+ {
+ if (processorNumber < MAX32CPU)
+ {
+ return (affinity.AffinityMaskCfg == (1 << processorNumber)) && (affinity64.AffinityMaskCfg == 0);
+ }
+ else
+ {
+ return (affinity64.AffinityMaskCfg == (1 << (processorNumber - MAX32CPU))) && (affinity.AffinityMaskCfg == 0);
+ }
+ }
+
+ ///
+ /// Get affinity masks for first 32 and next 32 processors (total 64 processors) if the
+ /// processor masks have been modified after being read from the server.
+ ///
+ /// returns the affinity for first 32 processors. null if not changed
+ /// return the affinity for CPUs 33-64. null if not changed.
+ public void GetAffinityMasksIfChanged(out int? affinityConfig, out int? affinity64Config)
+ {
+ affinityConfig = affinity64Config = null;
+ affinityConfig = affinity.AffinityMaskCfg;
+ affinity64Config = affinity64.AffinityMaskCfg;
+ }
+
+
+ ///
+ /// Checks if automatic affinity is chosen. Happens when mask for all 64 processors is reset/0.
+ /// Tells whether the CPU is in auto affinity mode or not. (i.e. all CPU mask bits are 0)
+ ///
+ /// true: use ConfigValue mask for test
+ /// false: use RunValue mask for test.
+ /// true: The Affinity mode is set to "auto".; false: The affinity mode is not auto.
+ public bool IsAutoAffinity(bool basedOnConfigValue)
+ {
+ return basedOnConfigValue ? (affinity.AffinityMaskCfg == 0 && affinity64.AffinityMaskCfg == 0)
+ : (affinity.AffinityMaskRun == 0 && affinity64.AffinityMaskRun == 0);
+
+ }
+
+ ///
+ /// Get the affinity for CPU processorNumber as enabled or disabled.
+ ///
+ /// The CPU number for which affinity is queried. Range: [0, 63]
+ /// true: affinity is enabled for the CPU; false: affinity disabled
+ /// /// Note: if the function returns false then the SQL Server might be in auto mode also,
+ /// as in auto mode all Processor Affinity Mask bits are 0.
+ ///
+ public bool GetAffinity(int processorNumber, bool showConfigValues)
+ {
+ int aux = 0, mask = 0;
+ if (processorNumber < MAX32CPU)
+ {
+ aux = showConfigValues ? affinity.AffinityMaskCfg : affinity.AffinityMaskRun;
+ mask = 1 << processorNumber;
+ }
+ else
+ {
+ aux = showConfigValues ? affinity64.AffinityMaskCfg : affinity64.AffinityMaskRun;
+ mask = 1 << (processorNumber - MAX32CPU);
+ }
+
+ return (aux & mask) != 0;
+ }
+
+ ///
+ /// Set the desired CPU's affinity.
+ ///
+ /// the CPU number for which affinity is set. Range: [0, 63] Must be valid.
+ ///
+ /// true: set affinity bit for the CPU; false: reset CPU bit for the particular processor.
+ /// Note: if false is passed then the SQL Server might be set in auto mode also,
+ /// as in auto mode all Processor Affinity Mask bits are 0.
+ ///
+ public void SetAffinity(int processorNumber, bool affinityEnabled)
+ {
+ int mask = 0;
+
+ if (processorNumber < MAX32CPU)
+ {
+ mask = 1 << processorNumber;
+ if (affinityEnabled)
+ {
+ affinity.AffinityMaskCfg |= mask;
+ }
+ else
+ {
+ affinity.AffinityMaskCfg &= ~mask;
+ }
+ }
+ else
+ {
+ mask = 1 << (processorNumber - MAX32CPU);
+ if (affinityEnabled)
+ {
+ affinity64.AffinityMaskCfg |= mask;
+ }
+ else
+ {
+ affinity64.AffinityMaskCfg &= ~mask;
+ }
+
+ }
+ }
+
+ public void InitializeAffinity(SMO.ConfigProperty affinity, SMO.ConfigProperty affinity64)
+ {
+ this.affinity.AffinityMaskCfg = affinity.ConfigValue;
+ this.affinity.AffinityMaskRun = affinity.RunValue;
+ this.affinity64.AffinityMaskCfg = affinity64.ConfigValue;
+ this.affinity64.AffinityMaskRun = affinity64.RunValue;
+ }
+
+ ///
+ /// Reset the affinities to default values.
+ ///
+ public void Clear()
+ {
+ initialIOAffinityArray = new BitArray(64, false);
+ affinity.Clear();
+ affinity64.Clear();
+ }
+
+ private Affinity affinity = new Affinity(); // affinity mask for first 32 processors
+ private Affinity affinity64 = new Affinity(); // affinity mask for next 32 (33-64) processors.
+ };
+}
diff --git a/src/Microsoft.SqlTools.ServiceLayer/ObjectManagement/ObjectTypes/Server/ServerPrototype.cs b/src/Microsoft.SqlTools.ServiceLayer/ObjectManagement/ObjectTypes/Server/ServerPrototype.cs
index 760401a7..9b588dbb 100644
--- a/src/Microsoft.SqlTools.ServiceLayer/ObjectManagement/ObjectTypes/Server/ServerPrototype.cs
+++ b/src/Microsoft.SqlTools.ServiceLayer/ObjectManagement/ObjectTypes/Server/ServerPrototype.cs
@@ -5,10 +5,15 @@
using System;
using Microsoft.SqlServer.Management.Smo;
+using SMO = Microsoft.SqlServer.Management.Smo;
using Microsoft.SqlTools.ServiceLayer.Management;
using Microsoft.SqlServer.Management.Common;
using Microsoft.SqlTools.ServiceLayer.ServerConfigurations;
using Microsoft.SqlTools.Utility;
+using System.Collections.Generic;
+using Microsoft.SqlTools.ServiceLayer.ObjectManagement.ObjectTypes.Server;
+using System.Linq;
+using System.Collections;
namespace Microsoft.SqlTools.ServiceLayer.ObjectManagement
{
@@ -287,6 +292,45 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectManagement
this.currentState.MinMemory = value;
}
+ }
+
+ public bool AutoProcessorAffinityMaskForAll
+ {
+ get
+ {
+ return this.currentState.AutoProcessorAffinityMaskForAll;
+ }
+ set
+ {
+ this.currentState.AutoProcessorAffinityMaskForAll = value;
+ }
+
+ }
+
+ public bool AutoProcessorAffinityIOMaskForAll
+ {
+ get
+ {
+ return this.currentState.AutoProcessorAffinityMaskForAll;
+ }
+ set
+ {
+ this.currentState.AutoProcessorAffinityMaskForAll = value;
+ }
+
+ }
+
+ public List NumaNodes
+ {
+ get
+ {
+ return this.currentState.NumaNodes;
+ }
+ set
+ {
+ this.currentState.NumaNodes = value;
+ }
+
}
#endregion
@@ -321,6 +365,37 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectManagement
{
Microsoft.SqlServer.Management.Smo.Server server = this.dataContainer.Server;
bool changesMade = false;
+ bool alterServerConfig = false;
+ bool sendCPUAffinityBeforeIO = false;
+ bool sendIOAffinityBeforeCPU = false;
+ bool sentCpuAffinity = false;
+
+ sendCPUAffinityBeforeIO = this.CheckCPUAffinityBeforeIO(server);
+ sendIOAffinityBeforeCPU = this.CheckIOAffinityBeforeCPU(server);
+ alterServerConfig = this.CheckIOAffinityTsqlGenerated(server);
+ if (!sendIOAffinityBeforeCPU)
+ {
+ SendDataForKJ(server);
+ sentCpuAffinity = true;
+ }
+
+ if (alterServerConfig)
+ {
+ try
+ {
+ server.Configuration.Alter((sendCPUAffinityBeforeIO && sendIOAffinityBeforeCPU));
+ }
+ finally
+ {
+ server.Configuration.Refresh();
+ }
+ }
+ if (!sentCpuAffinity)
+ {
+ SendDataForKJ(server);
+ }
+ this.currentState.AffinityManagerProcessorMask.Clear();
+ this.currentState.AffinityManagerIOMask.Clear();
changesMade = UpdateMemoryValues(this.dataContainer.Server);
@@ -349,6 +424,156 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectManagement
}
return changesMade;
}
+
+ private bool CheckCPUAffinityBeforeIO(SMO.Server smoServer)
+ {
+ for (int i = 0; i < this.NumaNodes.Count; i++)
+ {
+ SMO.NumaNode nNode = smoServer.AffinityInfo.NumaNodes[i];
+ for (int cpuCount = 0; cpuCount < this.NumaNodes[i].Processors.Count; cpuCount++)
+ {
+ SMO.Cpu cpu = nNode.Cpus[cpuCount];
+ if (cpu.GroupID == 0)
+ {
+ if (cpu.AffinityMask == this.NumaNodes[i].Processors[cpuCount].IOAffinity && cpu.AffinityMask)
+ {
+ //if Current IO affinity is equal to initial cpu.Affinity then script Cpu Affinity first
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+ }
+
+ private bool CheckIOAffinityBeforeCPU(SMO.Server smoServer)
+ {
+ for (int i = 0; i < this.NumaNodes.Count; i++)
+ {
+ SMO.NumaNode nNode = smoServer.AffinityInfo.NumaNodes[i];
+ for (int cpuCount = 0; cpuCount < this.NumaNodes[i].Processors.Count; cpuCount++)
+ {
+ SMO.Cpu cpu = nNode.Cpus[cpuCount];
+ if (cpu.GroupID == 0)
+ {
+ if (this.currentState.AffinityManagerIOMask.initialIOAffinityArray[cpu.ID] == this.NumaNodes[i].Processors[cpuCount].Affinity && this.currentState.AffinityManagerIOMask.initialIOAffinityArray[cpu.ID])
+ {
+ //if Current IO affinity is equal to initial cpu.Affinity then script Cpu Affinity first
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+ }
+ ///
+ /// This will send data for KJ specific things
+ /// Also Checks if Alter needs to be generated
+ ///
+ private void SendDataForKJ(SMO.Server smoServer)
+ {
+ BitArray finalCpuAffinity = new BitArray(64, false);
+ bool sendAffinityInfoAlter = false;
+
+ if (this.AutoProcessorAffinityMaskForAll)
+ {
+ if (smoServer.AffinityInfo.AffinityType != Microsoft.SqlServer.Management.Smo.AffinityType.Auto)
+ {
+ smoServer.AffinityInfo.AffinityType = Microsoft.SqlServer.Management.Smo.AffinityType.Auto;
+ sendAffinityInfoAlter = true;
+ }
+ }
+ else
+ {
+ if (smoServer.AffinityInfo.AffinityType != Microsoft.SqlServer.Management.Smo.AffinityType.Manual)
+ {
+ smoServer.AffinityInfo.AffinityType = Microsoft.SqlServer.Management.Smo.AffinityType.Manual;
+ sendAffinityInfoAlter = true;
+ }
+ }
+
+ for (int i = 0; i < this.NumaNodes.Count; i++)
+ {
+ SMO.NumaNode node = smoServer.AffinityInfo.NumaNodes[i];
+ for (int cpuCount = 0; cpuCount < this.NumaNodes[i].Processors.Count; cpuCount++)
+ {
+ SMO.Cpu cpu = node.Cpus[cpuCount];
+ if (this.NumaNodes[i].Processors[cpuCount].Affinity != cpu.AffinityMask)
+ {
+ sendAffinityInfoAlter = true;
+ if (!this.AutoProcessorAffinityMaskForAll)
+ {
+ cpu.AffinityMask = this.NumaNodes[i].Processors[cpuCount].Affinity;
+ }
+ }
+ }
+ }
+
+ if (sendAffinityInfoAlter)
+ {
+ try
+ {
+ smoServer.AffinityInfo.Alter();
+ smoServer.Configuration.Alter();
+ }
+ finally
+ {
+ smoServer.AffinityInfo.Refresh();
+ smoServer.Configuration.Refresh();
+ }
+ }
+
+ }
+
+ private bool CheckIOAffinityTsqlGenerated(SMO.Server smoServer)
+ {
+ bool sendAlter = false;
+ bool send64AffinityIOAlter = false;
+ BitArray finalCpuIOAffinity = new BitArray(64, false);
+ for (int i = 0; i < this.NumaNodes.Count; i++)
+ {
+ SMO.NumaNode nNode = smoServer.AffinityInfo.NumaNodes[i];
+ for (int cpuCount = 0; cpuCount < this.NumaNodes[i].Processors.Count; cpuCount++)
+ {
+ SMO.Cpu cpu = nNode.Cpus[cpuCount];
+ if (cpu.GroupID == 0)
+ {
+ finalCpuIOAffinity[cpu.ID] = this.NumaNodes[i].Processors[cpuCount].IOAffinity;
+ if (this.currentState.AffinityManagerIOMask.initialIOAffinityArray[cpu.ID] != finalCpuIOAffinity[cpu.ID])
+ {
+ if (cpu.ID < AffinityManager.MAX32CPU)
+ {
+ sendAlter = true;
+ }
+ else
+ {
+ send64AffinityIOAlter = true;
+ }
+ }
+ }
+ }
+ }
+
+ if (sendAlter || send64AffinityIOAlter)
+ {
+ int[] intArray = new int[2];
+ finalCpuIOAffinity.CopyTo(intArray, 0);
+ if (sendAlter)
+ {
+ smoServer.Configuration.AffinityIOMask.ConfigValue = intArray[0];
+ }
+ if (send64AffinityIOAlter)
+ {
+ smoServer.Configuration.Affinity64IOMask.ConfigValue = intArray[1];
+ }
+ //update current state initialIO after update
+ if (this.currentState.AffinityManagerIOMask.initialIOAffinityArray != finalCpuIOAffinity)
+ {
+ this.currentState.AffinityManagerIOMask.initialIOAffinityArray = finalCpuIOAffinity;
+ }
+ }
+ return (sendAlter || send64AffinityIOAlter);
+ }
#endregion
public void ApplyInfoToPrototype(ServerInfo serverInfo)
@@ -373,6 +598,9 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectManagement
this.StorageSpaceUsageInMB = (int)(serverInfo.StorageSpaceUsageInMB);
this.MaxServerMemory = serverInfo.MaxServerMemory;
this.MinServerMemory = serverInfo.MinServerMemory;
+ this.AutoProcessorAffinityMaskForAll = serverInfo.AutoProcessorAffinityMaskForAll;
+ this.AutoProcessorAffinityIOMaskForAll = serverInfo.AutoProcessorAffinityIOMaskForAll;
+ this.NumaNodes = serverInfo.NumaNodes.ToList();
}
///
@@ -403,19 +631,53 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectManagement
private string serviceTier = String.Empty;
private int reservedStorageSizeMB = 0;
private int storageSpaceUsageInMB = 0;
-
private NumericServerProperty minMemory;
private NumericServerProperty maxMemory;
+ private bool autoProcessorAffinityMaskForAll = false;
+ private bool autoProcessorAffinityIOMaskForAll = false;
+ private List numaNodes = new List();
+
private bool initialized = false;
private Server server;
private CDataContainer context;
private ServerConfigService configService;
+ private AffinityManager affinityManagerIOMask;
+ private AffinityManager affinityManagerProcessorMask;
+
private bool isYukonOrLater = false;
+ private bool isSqlServer64Bit;
+ private bool isIOAffinitySupported = false;
ConfigProperty serverMaxMemoryProperty;
ConfigProperty serverMinMemoryProperty;
#endregion
+ public AffinityManager AffinityManagerIOMask
+ {
+ get
+ {
+ return this.affinityManagerIOMask;
+ }
+
+ set
+ {
+ this.affinityManagerIOMask = value;
+ }
+ }
+
+ public AffinityManager AffinityManagerProcessorMask
+ {
+ get
+ {
+ return this.affinityManagerProcessorMask;
+ }
+
+ set
+ {
+ this.affinityManagerProcessorMask = value;
+ }
+ }
+
#region Properties
// General properties
@@ -835,11 +1097,11 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectManagement
set
{
if (this.initialized)
- {
+ {
Logger.Error(SR.PropertyNotInitialized("MinMemory"));
}
- this.minMemory = value;
+ this.minMemory = value;
}
}
@@ -866,6 +1128,75 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectManagement
}
}
+ public bool AutoProcessorAffinityMaskForAll
+ {
+ get
+ {
+ if (!this.initialized)
+ {
+ LoadData();
+ }
+
+ return this.autoProcessorAffinityMaskForAll;
+ }
+
+ set
+ {
+ if (this.initialized)
+ {
+ Logger.Error(SR.PropertyNotInitialized("AutoProcessorAffinityMaskForAll"));
+ }
+
+ this.autoProcessorAffinityMaskForAll = value;
+ }
+ }
+
+ public bool AutoProcessorAffinityIOMaskForAll
+ {
+ get
+ {
+ if (!this.initialized)
+ {
+ LoadData();
+ }
+
+ return this.autoProcessorAffinityIOMaskForAll;
+ }
+
+ set
+ {
+ if (this.initialized)
+ {
+ Logger.Error(SR.PropertyNotInitialized("AutoProcessorAffinityIOMaskForAll"));
+ }
+
+ this.autoProcessorAffinityIOMaskForAll = value;
+ }
+ }
+
+ public List NumaNodes
+ {
+ get
+ {
+ if (!this.initialized)
+ {
+ LoadData();
+ }
+
+ return this.numaNodes;
+ }
+
+ set
+ {
+ if (this.initialized)
+ {
+ Logger.Error(SR.PropertyNotInitialized("NumaNodes"));
+ }
+
+ this.numaNodes = value;
+ }
+ }
+
public Microsoft.SqlServer.Management.Smo.Server Server
{
@@ -904,10 +1235,15 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectManagement
this.context = context;
this.configService = service;
this.isYukonOrLater = (this.server.Information.Version.Major >= 9);
+ this.isSqlServer64Bit = (this.server.Edition.Contains("(64 - bit)"));
+ this.affinityManagerIOMask = new AffinityManager();
+ this.affinityManagerProcessorMask = new AffinityManager();
this.serverMaxMemoryProperty = this.configService.GetServerSmoConfig(server, this.configService.MaxServerMemoryPropertyNumber);
this.serverMinMemoryProperty = this.configService.GetServerSmoConfig(server, this.configService.MinServerMemoryPropertyNumber);
this.minMemory = new NumericServerProperty();
this.maxMemory = new NumericServerProperty();
+ this.NumaNodes = new List();
+
LoadData();
}
@@ -939,6 +1275,9 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectManagement
result.version = this.version;
result.maxMemory = this.maxMemory;
result.minMemory = this.minMemory;
+ result.autoProcessorAffinityMaskForAll = this.autoProcessorAffinityMaskForAll;
+ result.autoProcessorAffinityIOMaskForAll = this.autoProcessorAffinityIOMaskForAll;
+ result.numaNodes = this.numaNodes;
result.server = this.server;
return result;
}
@@ -965,6 +1304,19 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectManagement
this.serviceTier = server.ServiceTier;
this.storageSpaceUsageInMB = server.UsedStorageSizeMB;
LoadMemoryProperties();
+ try
+ {
+ this.affinityManagerIOMask.InitializeAffinity(this.server.Configuration.AffinityIOMask, this.server.Configuration.Affinity64IOMask);
+ this.isIOAffinitySupported = true;
+ }
+ catch
+ {
+ this.isIOAffinitySupported = false;
+ }
+ this.affinityManagerProcessorMask.InitializeAffinity(this.server.Configuration.AffinityMask, this.server.Configuration.Affinity64Mask);
+
+ this.numaNodes = GetNumaNodes();
+ GetAutoProcessorsAffinity();
}
private void LoadMemoryProperties()
@@ -977,6 +1329,50 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectManagement
this.minMemory.MaximumValue = serverMinMemoryProperty.Maximum;
this.minMemory.MinimumValue = serverMinMemoryProperty.Minimum;
}
+
+ ///
+ /// Get affinity masks for first 32 and next 32 processors (total 64 processors) if the
+ /// processor masks have been modified after being read from the server.
+ ///
+ /// returns the affinity for first 32 processors. null if not changed
+ /// return the affinity for CPUs 33-64. null if not changed.
+ private List GetNumaNodes()
+ {
+ List results = new List();
+ foreach (SMO.NumaNode node in this.server.AffinityInfo.NumaNodes)
+ {
+ var processors = new List();
+ foreach (SMO.Cpu cpu in node.Cpus)
+ {
+ if (cpu.GroupID == 0)
+ {
+ var affinityIO = this.AffinityManagerIOMask.GetAffinity(cpu.ID, true);
+ if (!cpu.AffinityMask && this.isIOAffinitySupported && affinityIO) // if it's false then check if io affinity is checked
+ {
+ this.AffinityManagerIOMask.initialIOAffinityArray[cpu.ID] = true;
+ }
+
+ // get affinityIO info if group id is 0
+ processors.Add(new ProcessorAffinity() { ProcessorId = cpu.ID.ToString(), Affinity = cpu.AffinityMask, IOAffinity = affinityIO });
+ }
+ }
+ var result = new NumaNode() { NumaNodeId = node.ID.ToString(), Processors = processors };
+ results.Add(result);
+ }
+ return results;
+ }
+
+ private void GetAutoProcessorsAffinity()
+ {
+ if (this.server.AffinityInfo.AffinityType == Microsoft.SqlServer.Management.Smo.AffinityType.Auto)
+ {
+ this.autoProcessorAffinityMaskForAll = this.autoProcessorAffinityIOMaskForAll = true;
+ }
+ else
+ {
+ this.autoProcessorAffinityMaskForAll = this.autoProcessorAffinityIOMaskForAll = false;
+ }
+ }
}
}
}
diff --git a/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/ObjectManagement/ServerHandlerTests.cs b/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/ObjectManagement/ServerHandlerTests.cs
index 1684fe12..d8033276 100644
--- a/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/ObjectManagement/ServerHandlerTests.cs
+++ b/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/ObjectManagement/ServerHandlerTests.cs
@@ -87,9 +87,13 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.ObjectManagement
MaxServerMemory = result.MaxServerMemory
};
+ // original memory settings
+ var originalMinMemory = result.MinServerMemory.Value;
+ var originalMaxMemory = result.MaxServerMemory.Value;
+
// Change memory settings
- serverInfo.MinServerMemory.Value = 10;
- serverInfo.MaxServerMemory.Value = 500;
+ serverInfo.MinServerMemory.Value = serverInfo.MinServerMemory.MinimumValue;
+ serverInfo.MaxServerMemory.Value = serverInfo.MaxServerMemory.MaximumValue;
Assert.That(result.MinServerMemory.Value, Is.Not.EqualTo(serverInfo.MinServerMemory.Value), "Server property should not be equal after update");
Assert.That(result.MaxServerMemory.Value, Is.Not.EqualTo(serverInfo.MaxServerMemory.Value), "Server property should not be equal after update");
@@ -100,6 +104,57 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.ObjectManagement
Assert.That(result, Is.Not.Null);
Assert.That(result.MinServerMemory.Value, Is.EqualTo(serverInfo.MinServerMemory.Value), "Server property should be equal after update");
Assert.That(result.MaxServerMemory.Value, Is.EqualTo(serverInfo.MaxServerMemory.Value), "Server property should be equal after update");
+
+ // Reset to original values
+ serverInfo.MinServerMemory.Value = originalMinMemory;
+ serverInfo.MaxServerMemory.Value = originalMaxMemory;
+ await ObjectManagementTestUtils.SaveObject(requestParams, serverInfo);
+ }
+ }
+
+ ///
+ /// Test Processors for Sql Server
+ ///
+ [Test]
+ public async Task GetProcessorsProperties()
+ {
+ var connectionResult = await LiveConnectionHelper.InitLiveConnectionInfoAsync("master", serverType: TestServerType.OnPrem);
+ using (SqlConnection sqlConn = ConnectionService.OpenSqlConnection(connectionResult.ConnectionInfo))
+ {
+ var server = new Server(new ServerConnection(sqlConn));
+ var serverHandler = new ServerHandler(ConnectionService.Instance);
+
+ var requestParams = ObjectManagementTestUtils.GetInitializeViewRequestParams(connectionResult.ConnectionInfo.OwnerUri, "master", true, SqlObjectType.Server, "", "");
+ var result = (ServerInfo)(await serverHandler.InitializeObjectView(requestParams)).ViewInfo.ObjectInfo;
+ ServerInfo serverInfo = new ServerInfo()
+ {
+ Name = result.Name,
+ HardwareGeneration = result.HardwareGeneration,
+ Language = result.Language,
+ MemoryInMB = result.MemoryInMB,
+ OperatingSystem = result.OperatingSystem,
+ Platform = result.Platform,
+ Processors = result.Processors,
+ IsClustered = result.IsClustered,
+ IsHadrEnabled = result.IsHadrEnabled,
+ IsPolyBaseInstalled = result.IsPolyBaseInstalled,
+ IsXTPSupported = result.IsXTPSupported,
+ Product = result.Product,
+ ReservedStorageSizeMB = result.ReservedStorageSizeMB,
+ RootDirectory = result.RootDirectory,
+ ServerCollation = result.ServerCollation,
+ ServiceTier = result.ServiceTier,
+ StorageSpaceUsageInMB = result.StorageSpaceUsageInMB,
+ Version = result.Version,
+ MinServerMemory = result.MinServerMemory,
+ MaxServerMemory = result.MaxServerMemory,
+ AutoProcessorAffinityMaskForAll = result.AutoProcessorAffinityMaskForAll,
+ AutoProcessorAffinityIOMaskForAll = result.AutoProcessorAffinityIOMaskForAll
+ };
+
+ Assert.That(result, Is.Not.Null);
+ Assert.That(result.AutoProcessorAffinityIOMaskForAll,Is.True, "Auto affinity should be default");
+ Assert.That(result.AutoProcessorAffinityMaskForAll, Is.True, "Auto affinity should be default");
}
}
}