Skip to content

Commit 4d59307

Browse files
authored
Defend against parallel access to package assets cache (#2159)
This can happen if certain targets are invoked in parallel on the same project having with global properties not differing sufficiently to provide each build with a unique intermediate directory. One case where this can happen is if there is a design-time build and real build happening in parallel. Another case occurs frequently in `dotnet store`. The latter may be a design flaw in `dotnet store` but the root cause hasn't been identified yet. This will at least prevent `dotnet store` from failing, but more investigation is needed to understand why `dotnet store` gets itself into this situation. Now, when we're unable to read or write the assets cache, we fall back to the same in-memory technique that is used when DisablePackageAssetsCache is set to true. We will also log a high importance message (not a warning because that can break builds with warning-as-error and this can happen outside the user's control). The intent of logging a message is to be able to get feedback if this is happening frequently. The risk the message is trying to mitigate is if we start falling back from the fast path in common cases and don't have any clues about that other than the perf hit.
1 parent 11ea81d commit 4d59307

16 files changed

+91
-8
lines changed

src/Tasks/Common/Resources/Strings.resx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -352,7 +352,10 @@
352352
{1} - Restored version of platform package
353353
{2} - Current version of platform package</comment>
354354
</data>
355+
<data name="UnableToUsePackageAssetsCache" xml:space="preserve">
356+
<value>Unable to use package assets cache due to I/O error. This can occur when the same project is built more than once in parallel. Performance may be degraded, but the build result will not be impacted.</value>
357+
</data>
355358
<data name="AssetsFileNotSet" xml:space="preserve">
356359
<value>The path to the project assets file was not set. Run a NuGet package restore to generate this file.</value>
357360
</data>
358-
</root>
361+
</root>

src/Tasks/Common/Resources/xlf/Strings.cs.xlf

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -394,6 +394,11 @@
394394
<target state="new">DotnetTool does not support target framework lower than netcoreapp2.1.</target>
395395
<note />
396396
</trans-unit>
397+
<trans-unit id="UnableToUsePackageAssetsCache">
398+
<source>Unable to use package assets cache due to I/O error. This can occur when the same project is built more than once in parallel. Performance may be degraded, but the build result will not be impacted.</source>
399+
<target state="new">Unable to use package assets cache due to I/O error. This can occur when the same project is built more than once in parallel. Performance may be degraded, but the build result will not be impacted.</target>
400+
<note />
401+
</trans-unit>
397402
</body>
398403
</file>
399404
</xliff>

src/Tasks/Common/Resources/xlf/Strings.de.xlf

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -394,6 +394,11 @@
394394
<target state="new">DotnetTool does not support target framework lower than netcoreapp2.1.</target>
395395
<note />
396396
</trans-unit>
397+
<trans-unit id="UnableToUsePackageAssetsCache">
398+
<source>Unable to use package assets cache due to I/O error. This can occur when the same project is built more than once in parallel. Performance may be degraded, but the build result will not be impacted.</source>
399+
<target state="new">Unable to use package assets cache due to I/O error. This can occur when the same project is built more than once in parallel. Performance may be degraded, but the build result will not be impacted.</target>
400+
<note />
401+
</trans-unit>
397402
</body>
398403
</file>
399404
</xliff>

src/Tasks/Common/Resources/xlf/Strings.es.xlf

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -394,6 +394,11 @@
394394
<target state="new">DotnetTool does not support target framework lower than netcoreapp2.1.</target>
395395
<note />
396396
</trans-unit>
397+
<trans-unit id="UnableToUsePackageAssetsCache">
398+
<source>Unable to use package assets cache due to I/O error. This can occur when the same project is built more than once in parallel. Performance may be degraded, but the build result will not be impacted.</source>
399+
<target state="new">Unable to use package assets cache due to I/O error. This can occur when the same project is built more than once in parallel. Performance may be degraded, but the build result will not be impacted.</target>
400+
<note />
401+
</trans-unit>
397402
</body>
398403
</file>
399404
</xliff>

src/Tasks/Common/Resources/xlf/Strings.fr.xlf

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -394,6 +394,11 @@
394394
<target state="new">DotnetTool does not support target framework lower than netcoreapp2.1.</target>
395395
<note />
396396
</trans-unit>
397+
<trans-unit id="UnableToUsePackageAssetsCache">
398+
<source>Unable to use package assets cache due to I/O error. This can occur when the same project is built more than once in parallel. Performance may be degraded, but the build result will not be impacted.</source>
399+
<target state="new">Unable to use package assets cache due to I/O error. This can occur when the same project is built more than once in parallel. Performance may be degraded, but the build result will not be impacted.</target>
400+
<note />
401+
</trans-unit>
397402
</body>
398403
</file>
399404
</xliff>

src/Tasks/Common/Resources/xlf/Strings.it.xlf

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -394,6 +394,11 @@
394394
<target state="new">DotnetTool does not support target framework lower than netcoreapp2.1.</target>
395395
<note />
396396
</trans-unit>
397+
<trans-unit id="UnableToUsePackageAssetsCache">
398+
<source>Unable to use package assets cache due to I/O error. This can occur when the same project is built more than once in parallel. Performance may be degraded, but the build result will not be impacted.</source>
399+
<target state="new">Unable to use package assets cache due to I/O error. This can occur when the same project is built more than once in parallel. Performance may be degraded, but the build result will not be impacted.</target>
400+
<note />
401+
</trans-unit>
397402
</body>
398403
</file>
399404
</xliff>

src/Tasks/Common/Resources/xlf/Strings.ja.xlf

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -394,6 +394,11 @@
394394
<target state="new">DotnetTool does not support target framework lower than netcoreapp2.1.</target>
395395
<note />
396396
</trans-unit>
397+
<trans-unit id="UnableToUsePackageAssetsCache">
398+
<source>Unable to use package assets cache due to I/O error. This can occur when the same project is built more than once in parallel. Performance may be degraded, but the build result will not be impacted.</source>
399+
<target state="new">Unable to use package assets cache due to I/O error. This can occur when the same project is built more than once in parallel. Performance may be degraded, but the build result will not be impacted.</target>
400+
<note />
401+
</trans-unit>
397402
</body>
398403
</file>
399404
</xliff>

src/Tasks/Common/Resources/xlf/Strings.ko.xlf

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -394,6 +394,11 @@
394394
<target state="new">DotnetTool does not support target framework lower than netcoreapp2.1.</target>
395395
<note />
396396
</trans-unit>
397+
<trans-unit id="UnableToUsePackageAssetsCache">
398+
<source>Unable to use package assets cache due to I/O error. This can occur when the same project is built more than once in parallel. Performance may be degraded, but the build result will not be impacted.</source>
399+
<target state="new">Unable to use package assets cache due to I/O error. This can occur when the same project is built more than once in parallel. Performance may be degraded, but the build result will not be impacted.</target>
400+
<note />
401+
</trans-unit>
397402
</body>
398403
</file>
399404
</xliff>

src/Tasks/Common/Resources/xlf/Strings.pl.xlf

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -394,6 +394,11 @@
394394
<target state="new">DotnetTool does not support target framework lower than netcoreapp2.1.</target>
395395
<note />
396396
</trans-unit>
397+
<trans-unit id="UnableToUsePackageAssetsCache">
398+
<source>Unable to use package assets cache due to I/O error. This can occur when the same project is built more than once in parallel. Performance may be degraded, but the build result will not be impacted.</source>
399+
<target state="new">Unable to use package assets cache due to I/O error. This can occur when the same project is built more than once in parallel. Performance may be degraded, but the build result will not be impacted.</target>
400+
<note />
401+
</trans-unit>
397402
</body>
398403
</file>
399404
</xliff>

src/Tasks/Common/Resources/xlf/Strings.pt-BR.xlf

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -394,6 +394,11 @@
394394
<target state="new">DotnetTool does not support target framework lower than netcoreapp2.1.</target>
395395
<note />
396396
</trans-unit>
397+
<trans-unit id="UnableToUsePackageAssetsCache">
398+
<source>Unable to use package assets cache due to I/O error. This can occur when the same project is built more than once in parallel. Performance may be degraded, but the build result will not be impacted.</source>
399+
<target state="new">Unable to use package assets cache due to I/O error. This can occur when the same project is built more than once in parallel. Performance may be degraded, but the build result will not be impacted.</target>
400+
<note />
401+
</trans-unit>
397402
</body>
398403
</file>
399404
</xliff>

src/Tasks/Common/Resources/xlf/Strings.ru.xlf

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -394,6 +394,11 @@
394394
<target state="new">DotnetTool does not support target framework lower than netcoreapp2.1.</target>
395395
<note />
396396
</trans-unit>
397+
<trans-unit id="UnableToUsePackageAssetsCache">
398+
<source>Unable to use package assets cache due to I/O error. This can occur when the same project is built more than once in parallel. Performance may be degraded, but the build result will not be impacted.</source>
399+
<target state="new">Unable to use package assets cache due to I/O error. This can occur when the same project is built more than once in parallel. Performance may be degraded, but the build result will not be impacted.</target>
400+
<note />
401+
</trans-unit>
397402
</body>
398403
</file>
399404
</xliff>

src/Tasks/Common/Resources/xlf/Strings.tr.xlf

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -394,6 +394,11 @@
394394
<target state="new">DotnetTool does not support target framework lower than netcoreapp2.1.</target>
395395
<note />
396396
</trans-unit>
397+
<trans-unit id="UnableToUsePackageAssetsCache">
398+
<source>Unable to use package assets cache due to I/O error. This can occur when the same project is built more than once in parallel. Performance may be degraded, but the build result will not be impacted.</source>
399+
<target state="new">Unable to use package assets cache due to I/O error. This can occur when the same project is built more than once in parallel. Performance may be degraded, but the build result will not be impacted.</target>
400+
<note />
401+
</trans-unit>
397402
</body>
398403
</file>
399404
</xliff>

src/Tasks/Common/Resources/xlf/Strings.zh-Hans.xlf

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -394,6 +394,11 @@
394394
<target state="new">DotnetTool does not support target framework lower than netcoreapp2.1.</target>
395395
<note />
396396
</trans-unit>
397+
<trans-unit id="UnableToUsePackageAssetsCache">
398+
<source>Unable to use package assets cache due to I/O error. This can occur when the same project is built more than once in parallel. Performance may be degraded, but the build result will not be impacted.</source>
399+
<target state="new">Unable to use package assets cache due to I/O error. This can occur when the same project is built more than once in parallel. Performance may be degraded, but the build result will not be impacted.</target>
400+
<note />
401+
</trans-unit>
397402
</body>
398403
</file>
399404
</xliff>

src/Tasks/Common/Resources/xlf/Strings.zh-Hant.xlf

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -394,6 +394,11 @@
394394
<target state="new">DotnetTool does not support target framework lower than netcoreapp2.1.</target>
395395
<note />
396396
</trans-unit>
397+
<trans-unit id="UnableToUsePackageAssetsCache">
398+
<source>Unable to use package assets cache due to I/O error. This can occur when the same project is built more than once in parallel. Performance may be degraded, but the build result will not be impacted.</source>
399+
<target state="new">Unable to use package assets cache due to I/O error. This can occur when the same project is built more than once in parallel. Performance may be degraded, but the build result will not be impacted.</target>
400+
<note />
401+
</trans-unit>
397402
</body>
398403
</file>
399404
</xliff>

src/Tasks/Microsoft.NET.Build.Tasks/ResolvePackageAssets.cs

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -348,21 +348,36 @@ public CacheReader(ResolvePackageAssets task)
348348
{
349349
byte[] settingsHash = task.HashSettings();
350350

351-
if (task.DisablePackageAssetsCache)
352-
{
353-
_reader = CreateReaderFromMemory(task, settingsHash);
351+
if (!task.DisablePackageAssetsCache)
352+
{
353+
// I/O errors can occur here if there are parallel calls to resolve package assets
354+
// for the same project configured with the same intermediate directory. This can
355+
// (for example) happen when design-time builds and real builds overlap.
356+
//
357+
// If there is an I/O error, then we fall back to the same in-memory approach below
358+
// as when DisablePackageAssetsCache is set to true.
359+
try
360+
{
361+
_reader = CreateReaderFromDisk(task, settingsHash);
362+
}
363+
catch (IOException) { }
364+
catch (UnauthorizedAccessException) { }
354365
}
355-
else
366+
367+
if (_reader == null)
356368
{
357-
_reader = CreateReaderFromDisk(task, settingsHash);
369+
_reader = CreateReaderFromMemory(task, settingsHash);
358370
}
359371

360372
ReadMetadataStringTable();
361373
}
362374

363375
private static BinaryReader CreateReaderFromMemory(ResolvePackageAssets task, byte[] settingsHash)
364376
{
365-
Debug.Assert(task.DisablePackageAssetsCache);
377+
if (!task.DisablePackageAssetsCache)
378+
{
379+
task.Log.LogMessage(MessageImportance.High, Strings.UnableToUsePackageAssetsCache);
380+
}
366381

367382
var stream = new MemoryStream();
368383
using (var writer = new CacheWriter(task, stream))

src/Tests/Microsoft.NET.Publish.Tests/GivenThatWeWantToStoreAProjectWithDependencies.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,7 @@ public void store_nativeonlyassets()
160160
storeDirectory.Should().OnlyHaveFiles(files_on_disk);
161161
}
162162

163-
[CoreMSBuildOnlyFact(Skip="https://github.com/dotnet/sdk/issues/2089")]
163+
[CoreMSBuildOnlyFact]
164164
public void compose_multifile()
165165
{
166166
TestAsset simpleDependenciesAsset = _testAssetsManager

0 commit comments

Comments
 (0)