Skip to content

How atomic is renameFile? #109

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

Closed
Gabriella439 opened this issue Jul 19, 2020 · 3 comments
Closed

How atomic is renameFile? #109

Gabriella439 opened this issue Jul 19, 2020 · 3 comments
Labels
type: b-discussion This is a discussion with unclear objectives.

Comments

@Gabriella439
Copy link

Is System.Directory.renameFile supposed to safely handle two parallel renames that share the same destination?

The documentation says:

If the new object already exists, it is atomically replaced by the old object

... but it doesn't clarify what should happen if two concurrent processes rename two files to the same destination for the first time.

The context for this is: dhall-lang/dhall-haskell#1904

What we ran into is that we were using the atomic-write package and in the course of doing so ran into a situation where two parallel writes attempted to write to the same destination file at the same time. Under the hood, each write creates a temporary file and uses renameFile to move the temporarily file to the final destination. If they rename to the same destination in parallel we see a conflict on Windows. On Linux things work without problems.

@Rufflewind
Copy link
Member

Rufflewind commented Jul 20, 2020

This is a fairly nuanced issue on Windows: https://stackoverflow.com/q/167414

According to the Niall Douglas' explanation in "Racing the File System" at CppCon and Doug E. Cook's comment on MSDN forums, MoveFileEx uses multiple strategies to move (and replace) a file. The first strategy attempted is atomic, but if it fails it will fall back to copy-and-delete. So if it succeeds, then you know it worked. But if it fails, I don't know for sure whether the destination file might be corrupted. Other than permission denied errors, have you seen instances where the file is corrupted?

Docs

I think the documentation could be clarified by weakening the guarantees of this function on Windows, as the atomicity of this function seems unclear on that platform.

Alternative 1

"Racing the File System" notes that there is a more exotic, NTFS-specific alternative:

SetFileInformationByHandle(FILE_RENAME_INFO { ReplaceIfExists: TRUE })

However, I don't know if this might break other use cases, since users might be unintentionally relying on the fallback behavior when moving files from one volume to another, so this is unlikely to work as a general purpose replacement for rename.

To allow an open file to be replaced, the FILE_RENAME_FLAG_POSIX_SEMANTICS flag (Windows 10 V1607+) would also need to be added.

(This approach is not used in the standard libraries of other languages, e.g. both Python and Rust use the more conventional MoveFileEx approach.)

Alternative 2

There is an older API ReplaceFileW that has better guarantees and is more in line with what Dhall is trying to do. However, it is not suitable as a general purpose rename function because it expects the target file to already exist.

@Gabriella439
Copy link
Author

@Rufflewind: I think it's fine if the solution is to weaken the guarantee on Windows

@soulomoon
Copy link

soulomoon commented May 30, 2024

What is the status of this? HLS depend on it too.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type: b-discussion This is a discussion with unclear objectives.
Projects
None yet
Development

No branches or pull requests

3 participants