-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Conversation
dfafcd6
to
751ec0d
Compare
The following can repo the root cause using System;
using System.IO;
using System.Threading;
namespace console1
{
class Program
{
static void Main(string[] args)
{
for (int i = 1; i < 1000000; i++)
{
Console.WriteLine(i);
Directory.Move(@"C:\work\test1\folder", @"C:\work\test2\folder");
Directory.Move(@"C:\work\test2\folder", @"C:\work\test1\folder");
}
}
}
}
result
|
/// </summary> | ||
internal static void RetryOnMoveAccessFailure(Action action) | ||
{ | ||
const int ERROR_HRESULT_ACCESS_DENIED = unchecked((int)0x80070005); |
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
/// <summary> | ||
/// Run Directory.Move and File.Move in Windows has a chance to get IOException with HResult 0x80070005. But this error is transient. | ||
/// </summary> | ||
internal static void RetryOnMoveAccessFailure(Action action) |
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
@@ -47,5 +48,34 @@ public static class FileAccessRetrier | |||
} | |||
} | |||
} | |||
|
|||
/// <summary> | |||
/// Run Directory.Move and File.Move in Windows has a chance to get IOException with HResult 0x80070005. But this error is transient. |
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
catch (IOException e) when (e.HResult == ERROR_HRESULT_ACCESS_DENIED) | ||
{ | ||
Thread.Sleep(nextWaitTime); | ||
nextWaitTime *= 10; |
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
internal static void RetryOnMoveAccessFailure(Action action) | ||
{ | ||
const int ERROR_HRESULT_ACCESS_DENIED = unchecked((int)0x80070005); | ||
int nextWaitTime = 1000; |
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
catch (IOException e) when (e.HResult == ERROR_HRESULT_ACCESS_DENIED) | ||
{ | ||
Thread.Sleep(nextWaitTime); | ||
nextWaitTime *= 2; |
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
@@ -47,5 +48,35 @@ public static class FileAccessRetrier | |||
} | |||
} | |||
} | |||
|
|||
/// <summary> | |||
/// Run Directory.Move and File.Move in Windows has a chance to get IOException with |
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
We decide to not fix in 2.1.300 and set it to known issue. Re targeting to 2.1.4xx |
@livarcocc need your approval for check in 2.1.4xx |
* master: (31 commits) Updating signing project to use new intermediate directory (int). Update runtimeconfig.json doc for 2.1 (dotnet#9382) Shortening the path to the intermediate folder by renaming it to int. fix typo (dotnet#9364) Updating asp.net to 2.2.0 as well. Updating the build and tests to work with the 2.2.0 runtime. Simplified combining dictionaries in Telemetry Fixing 'Channel' and 'BranchName': "release/2.1.4xx" to "master" (dotnet#9362) Fix extraction of folders (dotnet#9335) Update Sha256Hasher.cs Fix relative path tool path (dotnet#9330) Insert updated SDK from 2.1.4xx branch MSBuild 15.8.60 Fix crash when user home directory cannot be determined. Make `CliFolderPathCalculator` a static class. Don't add the ReleaseSuffix to the branding on the CLI when DropSuffix is set to true. Add retry when Directory.Move (dotnet#9313) Override new SdkResult public properties Add reference to Microsoft.Build.NuGetSdkResolver Disable crossgen for MSBuild inline-task refs ... README.md build/BranchInfo.props build/BundledTemplates.props build/DependencyVersions.props build/Version.props src/redist/redist.csproj test/EndToEnd/GivenAspNetAppsResolveImplicitVersions.cs tools/CrossGen.Dependencies/CrossGen.Dependencies.csproj
…e_master_cli * 'master' of /Users/livarcocc/Documents/git/cli: (1063 commits) Updating signing project to use new intermediate directory (int). Update runtimeconfig.json doc for 2.1 (dotnet#9382) Shortening the path to the intermediate folder by renaming it to int. fix typo (dotnet#9364) Updating asp.net to 2.2.0 as well. Updating the build and tests to work with the 2.2.0 runtime. Simplified combining dictionaries in Telemetry Fixing 'Channel' and 'BranchName': "release/2.1.4xx" to "master" (dotnet#9362) Fix extraction of folders (dotnet#9335) Update Sha256Hasher.cs Fix relative path tool path (dotnet#9330) Insert updated SDK from 2.1.4xx branch MSBuild 15.8.60 Fix crash when user home directory cannot be determined. Make `CliFolderPathCalculator` a static class. Don't add the ReleaseSuffix to the branding on the CLI when DropSuffix is set to true. Add retry when Directory.Move (dotnet#9313) Override new SdkResult public properties Add reference to Microsoft.Build.NuGetSdkResolver Disable crossgen for MSBuild inline-task refs ...
https://github.com/dotnet/cli/issues/9289
#9313
N/A
When running uninstall and then install on Windows. Due to global tools use Directory.Move underneath, there is a chance the indexer or the antivirus collided (had a handle still open on the prior name). And the installation/uninstalling will fail with access denied error.
This impact the producers most. During producer’s test, it is likely they will uninstall and install their tools several times. And the frequency of seeing this error varies machine by machine.
No
Low risk. Try action on failure. And Directory.Move, File.Move is atomic. Once it fails it can be retired.
No
manual test
Windows
dotnet.dll, Microsoft.DotNet.Cli.Utils.dll
Why check 0x80070005 on IOException
This error is the exact error thrown. It is just an IOException. The only way to detect that is by HResult.
Why don’t use the function above -- RetryOnFileAccessFailure?
RetryOnFileAccessFailure is async. And also in this case, it is awaiting a void. There is some gotcha around it. Since it is so close to release, I choose the safer way. And RetryOnFileAccessFailure ‘s exception is not specific. UnauthorizedAccessException is likely a real error for user to handle for –-tool-path.
Tested with 100 times tight loop. No error