Skip to content
This repository has been archived by the owner on Apr 20, 2023. It is now read-only.

Port 2.1.3xx add retry when directory.move #9402

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 31 additions & 0 deletions src/Microsoft.DotNet.Cli.Utils/FileAccessRetryer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

using System;
using System.IO;
using System.Threading;
using System.Threading.Tasks;

namespace Microsoft.DotNet.Cli.Utils
Expand Down Expand Up @@ -47,5 +48,35 @@ public static class FileAccessRetrier
}
}
}

/// <summary>
/// Run Directory.Move and File.Move in Windows has a chance to get IOException with
/// HResult 0x80070005 due to Indexer. But this error is transient.
/// </summary>
internal static void RetryOnMoveAccessFailure(Action action)
{
const int ERROR_HRESULT_ACCESS_DENIED = unchecked((int)0x80070005);
int nextWaitTime = 10;
int remainRetry = 10;

while (true)
{
try
{
action();
break;
}
catch (IOException e) when (e.HResult == ERROR_HRESULT_ACCESS_DENIED)
{
Thread.Sleep(nextWaitTime);
nextWaitTime *= 2;
remainRetry--;
if (remainRetry == 0)
{
throw;
}
}
}
}
}
}
4 changes: 2 additions & 2 deletions src/dotnet/ShellShim/ShellShimRepository.cs
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ public void RemoveShim(string commandName)
foreach (var file in GetShimFiles(commandName).Where(f => _fileSystem.File.Exists(f.Value)))
{
var tempPath = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName());
_fileSystem.File.Move(file.Value, tempPath);
FileAccessRetrier.RetryOnMoveAccessFailure(() => _fileSystem.File.Move(file.Value, tempPath));
files[file.Value] = tempPath;
}
}
Expand All @@ -137,7 +137,7 @@ public void RemoveShim(string commandName)
rollback: () => {
foreach (var kvp in files)
{
_fileSystem.File.Move(kvp.Value, kvp.Key);
FileAccessRetrier.RetryOnMoveAccessFailure(() => _fileSystem.File.Move(kvp.Value, kvp.Key));
}
});
}
Expand Down
3 changes: 2 additions & 1 deletion src/dotnet/ToolPackage/ToolPackageInstaller.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using System.Linq;
using System.Xml.Linq;
using Microsoft.DotNet.Cli;
using Microsoft.DotNet.Cli.Utils;
using Microsoft.DotNet.Configurer;
using Microsoft.DotNet.Tools;
using Microsoft.Extensions.EnvironmentAbstractions;
Expand Down Expand Up @@ -82,7 +83,7 @@ public IToolPackage InstallPackage(PackageId packageId,
}

Directory.CreateDirectory(packageRootDirectory.Value);
Directory.Move(stageDirectory.Value, packageDirectory.Value);
FileAccessRetrier.RetryOnMoveAccessFailure(() => Directory.Move(stageDirectory.Value, packageDirectory.Value));
rollbackDirectory = packageDirectory.Value;

return new ToolPackageInstance(_store, packageId, version, packageDirectory);
Expand Down
5 changes: 3 additions & 2 deletions src/dotnet/ToolPackage/ToolPackageInstance.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
using NuGet.ProjectModel;
using NuGet.Versioning;
using Microsoft.DotNet.Cli.Utils;
using System.Threading;

namespace Microsoft.DotNet.ToolPackage
{
Expand Down Expand Up @@ -79,7 +80,7 @@ public void Uninstall()
// Use the staging directory for uninstall
// This prevents cross-device moves when temp is mounted to a different device
var tempPath = _store.GetRandomStagingDirectory().Value;
Directory.Move(PackageDirectory.Value, tempPath);
FileAccessRetrier.RetryOnMoveAccessFailure(() => Directory.Move(PackageDirectory.Value, tempPath));
tempPackageDirectory = tempPath;
}

Expand Down Expand Up @@ -111,7 +112,7 @@ public void Uninstall()
if (tempPackageDirectory != null)
{
Directory.CreateDirectory(rootDirectory.Value);
Directory.Move(tempPackageDirectory, PackageDirectory.Value);
FileAccessRetrier.RetryOnMoveAccessFailure(() => Directory.Move(tempPackageDirectory, PackageDirectory.Value));
}
});
}
Expand Down