Add retry when Directory.Move (#9313)
This commit is contained in:
parent
6411d7b2e7
commit
ca8a109d1c
4 changed files with 38 additions and 5 deletions
|
@ -3,6 +3,7 @@
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace Microsoft.DotNet.Cli.Utils
|
namespace Microsoft.DotNet.Cli.Utils
|
||||||
|
@ -47,5 +48,35 @@ namespace Microsoft.DotNet.Cli.Utils
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -113,7 +113,7 @@ namespace Microsoft.DotNet.ShellShim
|
||||||
foreach (var file in GetShimFiles(commandName).Where(f => _fileSystem.File.Exists(f.Value)))
|
foreach (var file in GetShimFiles(commandName).Where(f => _fileSystem.File.Exists(f.Value)))
|
||||||
{
|
{
|
||||||
var tempPath = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName());
|
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;
|
files[file.Value] = tempPath;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -137,7 +137,7 @@ namespace Microsoft.DotNet.ShellShim
|
||||||
rollback: () => {
|
rollback: () => {
|
||||||
foreach (var kvp in files)
|
foreach (var kvp in files)
|
||||||
{
|
{
|
||||||
_fileSystem.File.Move(kvp.Value, kvp.Key);
|
FileAccessRetrier.RetryOnMoveAccessFailure(() => _fileSystem.File.Move(kvp.Value, kvp.Key));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@ using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Xml.Linq;
|
using System.Xml.Linq;
|
||||||
using Microsoft.DotNet.Cli;
|
using Microsoft.DotNet.Cli;
|
||||||
|
using Microsoft.DotNet.Cli.Utils;
|
||||||
using Microsoft.DotNet.Configurer;
|
using Microsoft.DotNet.Configurer;
|
||||||
using Microsoft.DotNet.Tools;
|
using Microsoft.DotNet.Tools;
|
||||||
using Microsoft.Extensions.EnvironmentAbstractions;
|
using Microsoft.Extensions.EnvironmentAbstractions;
|
||||||
|
@ -82,7 +83,7 @@ namespace Microsoft.DotNet.ToolPackage
|
||||||
}
|
}
|
||||||
|
|
||||||
Directory.CreateDirectory(packageRootDirectory.Value);
|
Directory.CreateDirectory(packageRootDirectory.Value);
|
||||||
Directory.Move(stageDirectory.Value, packageDirectory.Value);
|
FileAccessRetrier.RetryOnMoveAccessFailure(() => Directory.Move(stageDirectory.Value, packageDirectory.Value));
|
||||||
rollbackDirectory = packageDirectory.Value;
|
rollbackDirectory = packageDirectory.Value;
|
||||||
|
|
||||||
return new ToolPackageInstance(_store, packageId, version, packageDirectory);
|
return new ToolPackageInstance(_store, packageId, version, packageDirectory);
|
||||||
|
|
|
@ -8,6 +8,7 @@ using Microsoft.Extensions.EnvironmentAbstractions;
|
||||||
using NuGet.ProjectModel;
|
using NuGet.ProjectModel;
|
||||||
using NuGet.Versioning;
|
using NuGet.Versioning;
|
||||||
using Microsoft.DotNet.Cli.Utils;
|
using Microsoft.DotNet.Cli.Utils;
|
||||||
|
using System.Threading;
|
||||||
|
|
||||||
namespace Microsoft.DotNet.ToolPackage
|
namespace Microsoft.DotNet.ToolPackage
|
||||||
{
|
{
|
||||||
|
@ -79,7 +80,7 @@ namespace Microsoft.DotNet.ToolPackage
|
||||||
// Use the staging directory for uninstall
|
// Use the staging directory for uninstall
|
||||||
// This prevents cross-device moves when temp is mounted to a different device
|
// This prevents cross-device moves when temp is mounted to a different device
|
||||||
var tempPath = _store.GetRandomStagingDirectory().Value;
|
var tempPath = _store.GetRandomStagingDirectory().Value;
|
||||||
Directory.Move(PackageDirectory.Value, tempPath);
|
FileAccessRetrier.RetryOnMoveAccessFailure(() => Directory.Move(PackageDirectory.Value, tempPath));
|
||||||
tempPackageDirectory = tempPath;
|
tempPackageDirectory = tempPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -111,7 +112,7 @@ namespace Microsoft.DotNet.ToolPackage
|
||||||
if (tempPackageDirectory != null)
|
if (tempPackageDirectory != null)
|
||||||
{
|
{
|
||||||
Directory.CreateDirectory(rootDirectory.Value);
|
Directory.CreateDirectory(rootDirectory.Value);
|
||||||
Directory.Move(tempPackageDirectory, PackageDirectory.Value);
|
FileAccessRetrier.RetryOnMoveAccessFailure(() => Directory.Move(tempPackageDirectory, PackageDirectory.Value));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue