Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve Directory.Move and DirectoryInfo.MoveTo #63675

Merged
merged 7 commits into from
Feb 8, 2022

Conversation

adamsitnik
Copy link
Member

@adamsitnik adamsitnik commented Jan 12, 2022

Fixes #63287

Explanation: Directory.Move already contained the bug fix (dotnet/corefx#40570), so I've just moved this logic to FileSystem.MoveDirectory and now both Directory.Move and DirectoryInfo.MoveTo are using the same code.

Update: I've found few places for improvements and reduced the number of sys-calls and got allocations to zero.

Explanation:

  • on Windows, there is no need to perform checks for file/dictionary existence, the sys-call that we use takes care of that.
  • on Unix, the rename sys-call overwrites destination if it exists. To keep old .NET Framework behavior that is inherited from Windows, we perform a check for file/dictionary existence before calling rename. But we don't need to do that for source, as rename is just going to fail if it does not exist. Moreover, there is no need to perform two sys-calls to check whether destination exists (one to check if directory exists, another to check if file exists). We can perform a single sys-call (stat) which just fails if given path does not exist.

Linux before:

Method Mean Error StdDev Median Min Max Allocated
MoveFolders 11.10 us 0.442 us 0.510 us 10.83 us 10.61 us 12.06 us 144 B
MoveFiles 11.30 us 0.364 us 0.405 us 11.38 us 10.70 us 12.01 us 144 B

Linux after:

Method Mean Error StdDev Median Min Max Allocated
MoveFolders 7.569 us 0.0945 us 0.0838 us 7.591 us 7.397 us 7.717 us -
MoveFiles 7.021 us 0.2085 us 0.2402 us 6.985 us 6.700 us 7.524 us -

Windows before:

Method Mean Error StdDev Median Min Max Allocated
MoveFolders 536.9 us 3.14 us 2.79 us 536.5 us 533.4 us 542.8 us 273 B
MoveFiles 481.0 us 9.20 us 8.60 us 480.4 us 468.9 us 492.9 us 273 B

Windows after:

Method Mean Error StdDev Median Min Max Allocated
MoveFolders 506.8 us 2.26 us 2.01 us 506.4 us 504.0 us 511.1 us 0 B
MoveFiles 422.7 us 4.71 us 4.17 us 424.1 us 415.6 us 427.3 us 0 B

Source code: dotnet/performance#2208

@adamsitnik adamsitnik added this to the 7.0.0 milestone Jan 12, 2022
@ghost ghost assigned adamsitnik Jan 12, 2022
@ghost
Copy link

ghost commented Jan 12, 2022

Tagging subscribers to this area: @dotnet/area-system-io
See info in area-owners.md if you want to be subscribed.

Issue Details

Fixes #63287

Explanation: Directory.Move already contained the bug fix (dotnet/corefx#40570), so I've just moved this logic to FileSystem.MoveDirectory and now both Directory.Move and DirectoryInfo.MoveTo are using the same code.

Author: adamsitnik
Assignees: -
Labels:

area-System.IO

Milestone: 7.0.0

@adamsitnik adamsitnik changed the title Unify Directory.Move and DirectoryInfo.MoveTo logic Improve Directory.Move and DirectoryInfo.MoveTo Jan 12, 2022
@adamsitnik adamsitnik added the tenet-performance Performance related issue label Jan 12, 2022
so we need to handle it before rename is called
ref MemoryMarshal.GetReference(converterOldPath.ConvertAndTerminateString(oldPath)),
ref MemoryMarshal.GetReference(converterNewPath.ConvertAndTerminateString(newPath)));
converterNewPath.Dispose();
converterOldPath.Dispose();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do you use explicit Dispose calls (instead of using-Statements)?

@adamsitnik adamsitnik requested a review from tmds January 26, 2022 10:52
@adamsitnik
Copy link
Member Author

@tmds could you please take a look at the Unix part?

@adamsitnik adamsitnik merged commit b256be8 into dotnet:main Feb 8, 2022
@adamsitnik adamsitnik deleted the issue63287 branch February 8, 2022 09:10
}

if (FileExists(destFullPath))
if (!sameDirectoryDifferentCase) // This check is to allow renaming of directories
Copy link
Member

@tmds tmds Feb 9, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because file systems are case sensitive I don't understand why we need a specific check for sameDirectoryDifferentCase?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is something that already existed and to be honest I have not questioned that before you have asked the question. It seems that @wfurt agrees with you (#65059 (comment)):

The MoveDirectory_FailToMoveLowerCaseDirectoryWhenUpperCaseDirectoryExists is technically wrong on Unix IMHO.
The case sensitivity is determined by given filesystem not by the OS itself.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My guess is that this may be there to surface better exceptions. We could defer to actual IO but that may give different behaviors on different platforms. And Some OSes and file systems do care about case and some don't.

@tmds
Copy link
Member

tmds commented Feb 9, 2022

@tmds could you please take a look at the Unix part?

@adamsitnik apologies, I forgot about your request. I have one question.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
area-System.IO tenet-performance Performance related issue
Projects
None yet
5 participants