Uh oh!
There was an error while loading. Please reload this page.
Fix race condition in fs::create_dir_all - #39799
Conversation
rust-highfive
commented
Feb 14, 2017
Thanks for the pull request, and welcome! The Rust team is excited to review your changes, and you should hear from @aturon (or someone else) soon. If any changes to this PR are deemed necessary, please add them as extra commits. This ensures that the reviewer can see what has changed since they last reviewed the code. Due to the way GitHub handles out-of-date commits, this should also make it reasonably obvious what issues have or haven't been addressed. Large or tricky changes may require several passes of review and changes. Please see the contribution instructions for more information. |
dpc
commented
Feb 14, 2017
alexcrichton
commented
Feb 14, 2017
Thanks for the PR! Could this actually lift the implementation in the compiler which I believe tries to minimize syscalls in the "normal" case. Also yeah you can just add a test with a few threads hammering at creating directories and just make sure they don't fail. |
seppo0010
commented
Feb 14, 2017
There's still room for a race condition if the directory is created after |
dpc
commented
Feb 14, 2017
@alexcrichton How to "lift it"? Move from librustc to libstd and then use that new location instead in librustc code (or just call directly from the old librustc name)? @seppo0010 : I don't understand. If another thread called |
seppo0010
commented
Feb 14, 2017
@dpc sorry, my case is quite weird, let me write it down a more detailed version. Let's say I'm not saying it's a bug, but it might be unexpected, and I don't even know what may be better in that case. |
alexcrichton
commented
Feb 14, 2017
@dpc yeah we can just copy the code and then update the compiler to call libstd (as libstd would handle this race) |
There was a problem hiding this comment.
Can this import get moved up to the top of the file with the other imports?
alexcrichton
commented
Mar 7, 2017
ping @dpc, thoughts on updating this? |
dpc
commented
Mar 7, 2017
I agree with all feedback, and will get to it, probably on a weekend. If anyone would like you to pick it up, that's also fine with me. |
alexcrichton
commented
Mar 7, 2017
Thanks @dpc! |
bc9df80 to
9865187CompareOoops. Sorry. I wasn't able to compile anything on current Also, seems like |
| Err(e) => return Err(e), | ||
| } | ||
| match path.parent() { | ||
| Some(p) => try!(create_dir_all(p)), |
There was a problem hiding this comment.
Could this call self.create_dir_all to ensure reuse of configuration in self? (if we add it in the future)
alexcrichton
commented
Mar 12, 2017
Looking good to me, thanks! Could you also add a test for specifically this use case? |
dpc
commented
Mar 13, 2017
Done |
alexcrichton
commented
Mar 13, 2017
Looks good! I think Travis has a tidy error though (r=me otherwise) |
petrochenkov
commented
Mar 13, 2017
@dpc |
alexcrichton
commented
Mar 13, 2017
@petrochenkov@dpc oh not yet, we'll need to wait for a new release. That's compiled against the stage0 libstd which doesn't have this fix. |
alexcrichton
commented
Mar 13, 2017
@bors: r+ |
bors
commented
Mar 13, 2017
📌 Commit 4e2114f has been approved by |
bors
commented
Mar 13, 2017
⌛ Testing commit 4e2114f with merge e1be448... |
bors
commented
Mar 13, 2017
💔 Test failed - status-appveyor |
alexcrichton
commented
Mar 13, 2017
@bors: retry
|
bors
commented
Mar 13, 2017
⌛ Testing commit 4e2114f with merge 4d01a7d... |
Fix race condition in fs::create_dir_all The code would crash if the directory was created after create_dir_all checked whether the directory already existed. This was contrary to the documentation which claimed to create the directory if it doesn't exist, implying (but not stating) that there would not be a failure due to the directory existing.
frewsxcv
commented
Mar 18, 2017
This seems to fail on Windows: https://ci.appveyor.com/project/rust-lang/rust/build/1.0.2436/job/ph8mhjt83f837xdl @bors r- |
dpc
commented
Mar 19, 2017
I don't understand what happened, and I don't have Windows to debug. If one of the threads have failed, I would expect Could someone with Windows help? |
| #[test] | ||
| fn concurrent_recursive_mkdir() { | ||
| for _ in 0..50 { |
There was a problem hiding this comment.
I think the main problem here is this use of tmpdir(). It deletes the path it returns when it goes out of scope and because it's not assigned to a variable that's immediately. See here. Changing this to the following should fix that:
let tmpdir = tmpdir();letmut dir = tmpdir.join("a");| } | ||
| #[test] | ||
| fn concurrent_recursive_mkdir() { |
There was a problem hiding this comment.
Does this test really need to be run 50 times? It fails the first time for me on Windows.
There was a problem hiding this comment.
It's because it relies on there being a race condition between the threads, but race conditions don't occur very often. By doing the test multiple times, it is much more likely to hit the race condition.
| #[test] | ||
| fn concurrent_recursive_mkdir() { | ||
| for _ in 0..50 { | ||
| let mut dir = tmpdir().join("a"); |
There was a problem hiding this comment.
Looks like you reduced the number of times this test is run rather than the the length of the path 😉.
Increase lifetime of `tmpdir`, and really change the length of test path.
alexcrichton
commented
Mar 19, 2017
@bors: r+ |
bors
commented
Mar 19, 2017
📌 Commit 088696b has been approved by |
bors
commented
Mar 19, 2017
⌛ Testing commit 088696b with merge 6eb9960... |
Fix race condition in fs::create_dir_all The code would crash if the directory was created after create_dir_all checked whether the directory already existed. This was contrary to the documentation which claimed to create the directory if it doesn't exist, implying (but not stating) that there would not be a failure due to the directory existing.
bors
commented
Mar 19, 2017
☀️ Test successful - status-appveyor, status-travis |
emk
commented
Mar 22, 2017
@dpc Thank you for fixing one of my least favorite Rust annoyances! The path to merge was a bit rock, but it's greatly appreciated. |
dpc
commented
Mar 22, 2017
@emk You're welcome. I'm very happy about it myself. First, I got on contributor's list. Second, it was a torn for me too. :) |
This is a minor tweak to handle some problems which I've encountered
several times now. The only real excuse for this change is that it's
unobstrusive and has natural semantics.
This patch modifies --filename to support two use cases:
xsv partition --filename {}/cities.csv state . all-cities.csv
xsv partition --filename {}/monuments.csv state . all-monuments.csv
xsv partition --filename {}/parks.csv state . all-parks.csv
Above, we want to partition our records by state into separate
directories, but we have multiple kinds of data.
xsv partition --filename {}/$(uuidgen).csv . input1.csv
xsv partition --filename {}/$(uuidgen).csv . input2.csv
Above, we're running multiple (possibly parallel) copies of xsv and we
want to parition the data into multiple directories without a filename
clash.
There's one limitation to the implementation: We might theoretically hit
the `create_dir_all` race condition recently fixed by
rust-lang/rust#39799. I'm planning to supply a final patch which works
around this race condition in stable Rust.See rust-lang/rust#39799 for details.
rustdoc: Use `create_dir_all` to create output directory Currently rustdoc will fail if passed `-o foo/doc` if the `foo` directory doesn't exist. Also remove unneeded `mkdir` as `create_dir_all` can now handle concurrent invocations since #39799.
rustbuild: Replace create_dir_racy with create_dir_all `create_dir_all` has since been fixed (in #39799) so no need for `create_dir_racy`.
as std::fs::create_dir_all is now threadsafe rust-lang/rust#39799
The code would crash if the directory was created after create_dir_all
checked whether the directory already existed. This was contrary to
the documentation which claimed to create the directory if it doesn't
exist, implying (but not stating) that there would not be a failure
due to the directory existing.