Skip to content

Commit 0d6bd9d

Browse files
Ensure we pass unique binlog paths to each BuildHost (#78599)
Otherwise if we launch multiple processes, they might step atop each other and cause locking issues.
2 parents 015a854 + 12369bc commit 0d6bd9d

File tree

9 files changed

+47
-29
lines changed

9 files changed

+47
-29
lines changed

SpellingExclusions.dic

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
1-
stackalloc
1+
stackalloc
22
awaitable
3-
Refactorings
4-
Infos
5-
cref
6-
binlog
7-
Namer
3+
Refactorings
4+
Infos
5+
cref
6+
binlog

src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/HostWorkspace/BinlogNamer.cs renamed to src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/HostWorkspace/BinLogPathProvider.cs

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,15 @@
44

55
using System.Composition;
66
using Microsoft.CodeAnalysis.Host.Mef;
7+
using Microsoft.CodeAnalysis.MSBuild;
78
using Microsoft.CodeAnalysis.Options;
89
using Microsoft.Extensions.Logging;
910
using Microsoft.VisualStudio.Composition;
1011

1112
namespace Microsoft.CodeAnalysis.LanguageServer.HostWorkspace;
1213

13-
[Export(typeof(BinlogNamer)), Shared]
14-
internal sealed class BinlogNamer
14+
[Export(typeof(IBinLogPathProvider)), Shared]
15+
internal sealed class BinLogPathProvider : IBinLogPathProvider
1516
{
1617
/// <summary>
1718
/// The suffix to use for the binary log name; incremented each time we have a new build. Should be incremented with <see cref="Interlocked.Increment(ref int)"/>.
@@ -28,13 +29,13 @@ internal sealed class BinlogNamer
2829

2930
[ImportingConstructor]
3031
[Obsolete(MefConstruction.ImportingConstructorMessage, error: true)]
31-
public BinlogNamer(IGlobalOptionService globalOptionService, ILoggerFactory loggerFactory)
32+
public BinLogPathProvider(IGlobalOptionService globalOptionService, ILoggerFactory loggerFactory)
3233
{
3334
_globalOptionService = globalOptionService;
34-
_logger = loggerFactory.CreateLogger<BinlogNamer>();
35+
_logger = loggerFactory.CreateLogger<BinLogPathProvider>();
3536
}
3637

37-
internal string? GetMSBuildBinaryLogPath()
38+
public string? GetNewLogPath()
3839
{
3940
if (_globalOptionService.GetOption(LanguageServerProjectSystemOptionsStorage.BinaryLogPath) is not string binaryLogDirectory)
4041
return null;

src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/HostWorkspace/FileBasedProgramsProjectSystem.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ public FileBasedProgramsProjectSystem(
4141
IAsynchronousOperationListenerProvider listenerProvider,
4242
ProjectLoadTelemetryReporter projectLoadTelemetry,
4343
ServerConfigurationFactory serverConfigurationFactory,
44-
BinlogNamer binlogNamer)
44+
IBinLogPathProvider binLogPathProvider)
4545
: base(
4646
workspaceFactory.FileBasedProgramsProjectFactory,
4747
workspaceFactory.TargetFrameworkManager,
@@ -52,7 +52,7 @@ public FileBasedProgramsProjectSystem(
5252
listenerProvider,
5353
projectLoadTelemetry,
5454
serverConfigurationFactory,
55-
binlogNamer)
55+
binLogPathProvider)
5656
{
5757
_lspServices = lspServices;
5858
_logger = loggerFactory.CreateLogger<FileBasedProgramsProjectSystem>();

src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/HostWorkspace/FileBasedProgramsWorkspaceProviderFactory.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
using Microsoft.CodeAnalysis.LanguageServer.Handler;
99
using Microsoft.CodeAnalysis.LanguageServer.HostWorkspace.ProjectTelemetry;
1010
using Microsoft.CodeAnalysis.MetadataAsSource;
11+
using Microsoft.CodeAnalysis.MSBuild;
1112
using Microsoft.CodeAnalysis.Options;
1213
using Microsoft.CodeAnalysis.ProjectSystem;
1314
using Microsoft.CodeAnalysis.Shared.TestHooks;
@@ -33,10 +34,10 @@ internal sealed class FileBasedProgramsWorkspaceProviderFactory(
3334
IAsynchronousOperationListenerProvider listenerProvider,
3435
ProjectLoadTelemetryReporter projectLoadTelemetry,
3536
ServerConfigurationFactory serverConfigurationFactory,
36-
BinlogNamer binlogNamer) : ILspMiscellaneousFilesWorkspaceProviderFactory
37+
IBinLogPathProvider binLogPathProvider) : ILspMiscellaneousFilesWorkspaceProviderFactory
3738
{
3839
public ILspMiscellaneousFilesWorkspaceProvider CreateLspMiscellaneousFilesWorkspaceProvider(ILspServices lspServices, HostServices hostServices)
3940
{
40-
return new FileBasedProgramsProjectSystem(lspServices, metadataAsSourceFileService, workspaceFactory, fileChangeWatcher, globalOptionService, loggerFactory, listenerProvider, projectLoadTelemetry, serverConfigurationFactory, binlogNamer);
41+
return new FileBasedProgramsProjectSystem(lspServices, metadataAsSourceFileService, workspaceFactory, fileChangeWatcher, globalOptionService, loggerFactory, listenerProvider, projectLoadTelemetry, serverConfigurationFactory, binLogPathProvider);
4142
}
4243
}

src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/HostWorkspace/LanguageServerProjectLoader.cs

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ internal abstract class LanguageServerProjectLoader
4343
protected readonly ILoggerFactory LoggerFactory;
4444
private readonly ILogger _logger;
4545
private readonly ProjectLoadTelemetryReporter _projectLoadTelemetryReporter;
46-
private readonly BinlogNamer _binlogNamer;
46+
private readonly IBinLogPathProvider _binLogPathProvider;
4747
protected readonly ImmutableDictionary<string, string> AdditionalProperties;
4848

4949
/// <summary>
@@ -98,7 +98,7 @@ protected LanguageServerProjectLoader(
9898
IAsynchronousOperationListenerProvider listenerProvider,
9999
ProjectLoadTelemetryReporter projectLoadTelemetry,
100100
ServerConfigurationFactory serverConfigurationFactory,
101-
BinlogNamer binlogNamer)
101+
IBinLogPathProvider binLogPathProvider)
102102
{
103103
ProjectFactory = projectFactory;
104104
_targetFrameworkManager = targetFrameworkManager;
@@ -108,7 +108,7 @@ protected LanguageServerProjectLoader(
108108
LoggerFactory = loggerFactory;
109109
_logger = loggerFactory.CreateLogger(nameof(LanguageServerProjectLoader));
110110
_projectLoadTelemetryReporter = projectLoadTelemetry;
111-
_binlogNamer = binlogNamer;
111+
_binLogPathProvider = binLogPathProvider;
112112
var workspace = projectFactory.Workspace;
113113
var razorDesignTimePath = serverConfigurationFactory.ServerConfiguration?.RazorDesignTimePath;
114114

@@ -145,9 +145,7 @@ private async ValueTask ReloadProjectsAsync(ImmutableSegmentedList<ProjectToLoad
145145

146146
// TODO: support configuration switching
147147

148-
var binaryLogPath = _binlogNamer.GetMSBuildBinaryLogPath();
149-
150-
await using var buildHostProcessManager = new BuildHostProcessManager(globalMSBuildProperties: AdditionalProperties, binaryLogPath: binaryLogPath, loggerFactory: LoggerFactory);
148+
await using var buildHostProcessManager = new BuildHostProcessManager(globalMSBuildProperties: AdditionalProperties, binaryLogPathProvider: _binLogPathProvider, loggerFactory: LoggerFactory);
151149
var toastErrorReporter = new ToastErrorReporter();
152150

153151
try

src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/HostWorkspace/LanguageServerProjectSystem.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ public LanguageServerProjectSystem(
3434
IAsynchronousOperationListenerProvider listenerProvider,
3535
ProjectLoadTelemetryReporter projectLoadTelemetry,
3636
ServerConfigurationFactory serverConfigurationFactory,
37-
BinlogNamer binlogNamer)
37+
IBinLogPathProvider binLogPathProvider)
3838
: base(
3939
workspaceFactory.HostProjectFactory,
4040
workspaceFactory.TargetFrameworkManager,
@@ -45,7 +45,7 @@ public LanguageServerProjectSystem(
4545
listenerProvider,
4646
projectLoadTelemetry,
4747
serverConfigurationFactory,
48-
binlogNamer)
48+
binLogPathProvider)
4949
{
5050
_logger = loggerFactory.CreateLogger(nameof(LanguageServerProjectSystem));
5151
var workspace = ProjectFactory.Workspace;

src/Workspaces/MSBuild/Core/MSBuild/BuildHostProcessManager.cs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -25,15 +25,15 @@ internal sealed class BuildHostProcessManager : IAsyncDisposable
2525
private readonly ImmutableDictionary<string, string> _globalMSBuildProperties;
2626
private readonly ILoggerFactory? _loggerFactory;
2727
private readonly ILogger? _logger;
28-
private readonly string? _binaryLogPath;
28+
private readonly IBinLogPathProvider? _binaryLogPathProvider;
2929

3030
private readonly SemaphoreSlim _gate = new(initialCount: 1);
3131
private readonly Dictionary<BuildHostProcessKind, BuildHostProcess> _processes = [];
3232

33-
public BuildHostProcessManager(ImmutableDictionary<string, string>? globalMSBuildProperties = null, string? binaryLogPath = null, ILoggerFactory? loggerFactory = null)
33+
public BuildHostProcessManager(ImmutableDictionary<string, string>? globalMSBuildProperties = null, IBinLogPathProvider? binaryLogPathProvider = null, ILoggerFactory? loggerFactory = null)
3434
{
3535
_globalMSBuildProperties = globalMSBuildProperties ?? ImmutableDictionary<string, string>.Empty;
36-
_binaryLogPath = binaryLogPath;
36+
_binaryLogPathProvider = binaryLogPathProvider;
3737
_loggerFactory = loggerFactory;
3838
_logger = loggerFactory?.CreateLogger<BuildHostProcessManager>();
3939
}
@@ -244,10 +244,10 @@ private void AppendBuildHostCommandLineArgumentsConfigureProcess(ProcessStartInf
244244
AddArgument(processStartInfo, globalMSBuildProperty.Key + '=' + globalMSBuildProperty.Value);
245245
}
246246

247-
if (_binaryLogPath is not null)
247+
if (_binaryLogPathProvider?.GetNewLogPath() is string binaryLogPath)
248248
{
249249
AddArgument(processStartInfo, "--binlog");
250-
AddArgument(processStartInfo, _binaryLogPath);
250+
AddArgument(processStartInfo, binaryLogPath);
251251
}
252252

253253
AddArgument(processStartInfo, "--locale");
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
// See the LICENSE file in the project root for more information.
4+
5+
namespace Microsoft.CodeAnalysis.MSBuild;
6+
7+
internal interface IBinLogPathProvider
8+
{
9+
/// <summary>
10+
/// Returns a new log path. Each call will return a new name, so that way we don't have collisions if multiple processes are writing to different logs.
11+
/// </summary>
12+
/// <returns>A new path, or null if no logging is currently wanted. An instance is allowed to switch between return null and returning non-null if
13+
/// the user changes configuration.</returns>
14+
string? GetNewLogPath();
15+
}

src/Workspaces/MSBuild/Test/BuildHostProcessManagerTests.cs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
using System.Collections.Generic;
66
using System.Collections.Immutable;
7+
using Moq;
78
using Roslyn.Test.Utilities;
89
using Xunit;
910

@@ -65,7 +66,10 @@ internal void ProcessStartInfo_PassesBinLogPath(BuildHostProcessKind buildHostKi
6566
{
6667
const string BinaryLogPath = "test.binlog";
6768

68-
var processStartInfo = new BuildHostProcessManager(binaryLogPath: BinaryLogPath)
69+
var binLogPathProviderMock = new Mock<IBinLogPathProvider>(MockBehavior.Strict);
70+
binLogPathProviderMock.Setup(m => m.GetNewLogPath()).Returns(BinaryLogPath);
71+
72+
var processStartInfo = new BuildHostProcessManager(binaryLogPathProvider: binLogPathProviderMock.Object)
6973
.CreateBuildHostStartInfo(buildHostKind, pipeName: "");
7074

7175
#if NET

0 commit comments

Comments
 (0)