From 6e007e6e68f432882efffc26789eac7fb538dbf0 Mon Sep 17 00:00:00 2001 From: Alan Ren Date: Thu, 15 Sep 2022 09:56:23 -0700 Subject: [PATCH] preload database when database node is expanded (#1690) --- .../ObjectExplorer/ObjectExplorerService.cs | 23 +++++++++++++++++++ .../SqlContext/SqlToolsSettingsValues.cs | 7 ++++++ .../SqlContext/TableDesignerSettings.cs | 18 +++++++++++++++ .../TableDesigner/TableDesignerService.cs | 12 ++++++++++ 4 files changed, 60 insertions(+) create mode 100644 src/Microsoft.SqlTools.ServiceLayer/SqlContext/TableDesignerSettings.cs diff --git a/src/Microsoft.SqlTools.ServiceLayer/ObjectExplorer/ObjectExplorerService.cs b/src/Microsoft.SqlTools.ServiceLayer/ObjectExplorer/ObjectExplorerService.cs index a99a19897e..72cee10811 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/ObjectExplorer/ObjectExplorerService.cs +++ b/src/Microsoft.SqlTools.ServiceLayer/ObjectExplorer/ObjectExplorerService.cs @@ -12,6 +12,7 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; +using Microsoft.Data.Tools.Sql.DesignServices.TableDesigner; using Microsoft.SqlServer.Management.Common; using Microsoft.SqlTools.Extensibility; using Microsoft.SqlTools.Hosting; @@ -23,6 +24,7 @@ using Microsoft.SqlTools.ServiceLayer.ObjectExplorer.Nodes; using Microsoft.SqlTools.ServiceLayer.ObjectExplorer.SmoModel; using Microsoft.SqlTools.ServiceLayer.SqlContext; +using Microsoft.SqlTools.ServiceLayer.TableDesigner; using Microsoft.SqlTools.ServiceLayer.Utility; using Microsoft.SqlTools.ServiceLayer.Workspace; using Microsoft.SqlTools.Utility; @@ -381,6 +383,27 @@ internal ExpandResponse QueueExpandNodeRequest(ObjectExplorerSession session, st TreeNode node = session.Root.FindNodeByPath(nodePath); ExpandResponse response = null; + // Performance Optimization for table designer to load the database model earlier based on user configuration. + if (node.NodeTypeId == NodeTypes.Database && TableDesignerService.Instance.Settings.PreloadDatabaseModel) + { + // The operation below are not blocking, but just in case, wrapping it with a task run to make sure it has no impact on the node expansion time. + var _ = Task.Run(() => + { + try + { + var builder = ConnectionService.CreateConnectionStringBuilder(session.ConnectionInfo.ConnectionDetails); + builder.InitialCatalog = node.NodeValue; + builder.ApplicationName = TableDesignerService.TableDesignerApplicationName; + var azureToken = session.ConnectionInfo.ConnectionDetails.AzureAccountToken; + TableDesignerCacheManager.StartDatabaseModelInitialization(builder.ToString(), azureToken); + } + catch (Exception ex) + { + Logger.Write(TraceEventType.Warning, $"Failed to start database initialization for table designer: {ex.Message}"); + } + }); + } + // This node was likely returned from a different node provider. Ignore expansion and return an empty array // since we don't need to add any nodes under this section of the tree. if (node == null) diff --git a/src/Microsoft.SqlTools.ServiceLayer/SqlContext/SqlToolsSettingsValues.cs b/src/Microsoft.SqlTools.ServiceLayer/SqlContext/SqlToolsSettingsValues.cs index ce92841fe0..d505b92ff0 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/SqlContext/SqlToolsSettingsValues.cs +++ b/src/Microsoft.SqlTools.ServiceLayer/SqlContext/SqlToolsSettingsValues.cs @@ -22,6 +22,7 @@ public SqlToolsSettingsValues(bool createDefaults = true) IntelliSense = new IntelliSenseSettings(); QueryExecutionSettings = new QueryExecutionSettings(); Format = new FormatterSettings(); + TableDesigner = new TableDesignerSettings(); } } @@ -48,5 +49,11 @@ public SqlToolsSettingsValues(bool createDefaults = true) /// [JsonProperty("objectExplorer")] public ObjectExplorerSettings ObjectExplorer { get; set; } + + /// + /// Gets or sets the table designer settings + /// + [JsonProperty("tableDesigner")] + public TableDesignerSettings TableDesigner { get; set; } } } diff --git a/src/Microsoft.SqlTools.ServiceLayer/SqlContext/TableDesignerSettings.cs b/src/Microsoft.SqlTools.ServiceLayer/SqlContext/TableDesignerSettings.cs new file mode 100644 index 0000000000..b252843feb --- /dev/null +++ b/src/Microsoft.SqlTools.ServiceLayer/SqlContext/TableDesignerSettings.cs @@ -0,0 +1,18 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +namespace Microsoft.SqlTools.ServiceLayer.SqlContext +{ + /// + /// Contract for receiving table designer settings as part of workspace settings + /// + public class TableDesignerSettings + { + /// + /// Whether the database model should be preloaded to make the initial launch quicker. + /// + public bool PreloadDatabaseModel { get; set; } = false; + } +} diff --git a/src/Microsoft.SqlTools.ServiceLayer/TableDesigner/TableDesignerService.cs b/src/Microsoft.SqlTools.ServiceLayer/TableDesigner/TableDesignerService.cs index 8ee9b1efc6..776401395f 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/TableDesigner/TableDesignerService.cs +++ b/src/Microsoft.SqlTools.ServiceLayer/TableDesigner/TableDesignerService.cs @@ -14,6 +14,7 @@ using Microsoft.SqlTools.ServiceLayer.TableDesigner.Contracts; using Dac = Microsoft.Data.Tools.Sql.DesignServices.TableDesigner; using STSHost = Microsoft.SqlTools.ServiceLayer.Hosting.ServiceHost; +using Microsoft.SqlTools.ServiceLayer.SqlContext; namespace Microsoft.SqlTools.ServiceLayer.TableDesigner { @@ -32,6 +33,8 @@ public TableDesignerService() { } + public TableDesignerSettings Settings { get; private set; } = new TableDesignerSettings(); + /// /// Gets the singleton instance object /// @@ -61,7 +64,16 @@ public void InitializeService(ServiceHost serviceHost) this.ServiceHost.SetRequestHandler(GenerateScriptRequest.Type, HandleGenerateScriptRequest); this.ServiceHost.SetRequestHandler(GeneratePreviewReportRequest.Type, HandleGeneratePreviewReportRequest); this.ServiceHost.SetRequestHandler(DisposeTableDesignerRequest.Type, HandleDisposeTableDesignerRequest); + Workspace.WorkspaceService.Instance.RegisterConfigChangeCallback(UpdateSettings); + + } + + internal Task UpdateSettings(SqlToolsSettings newSettings, SqlToolsSettings oldSettings, EventContext eventContext) + { + Settings.PreloadDatabaseModel = newSettings.MssqlTools.TableDesigner.PreloadDatabaseModel; + return Task.FromResult(0); } + private Task HandleRequest(RequestContext requestContext, Func action) { // The request handling will take some time to return, we need to use a separate task to run the request handler so that it won't block the main thread.