Add retry when Directory.Move (#9313)

This commit is contained in:
William Li 2018-05-22 09:55:10 -07:00 committed by GitHub
parent 6411d7b2e7
commit ca8a109d1c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 38 additions and 5 deletions

View file

@ -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;
}
}
}
}
} }
} }

View file

@ -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));
} }
}); });
} }

View file

@ -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);

View file

@ -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));
} }
}); });
} }