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
don't Fail if trying to mkdir when the dir already exists #699
Conversation
Evan Martin » ninja #668 SUCCESS |
Can you explain in some more detail how this can happen (e.g. sample (Running several ninjas at once is fairly strongly not supported; the only guarantee we make is that running two ninjas at once won't crash and won't corrupt build state.) |
I don't have a minimised testcase yet (I have a large set of local gyp files added to chromium's build system, and this only reproduces intermittently), but I think the situation that I'm encountering is:
If (2) starts then (1) finishes, (2) can fail. Since ninja's built-in directory tree creation looks like it is trying to do the equivalent of mkdir -p, I think it should be made to cope with this situation. But of course I'm also trying to fix this in my gyp files by adding dependencies to prevent this overlap. |
Having a reduced repro would be good. |
To simulate a loaded system / slow fs, I added a sleep(1) immediately before the MakeDir call in DiskInterface::MakeDirs. Then if you produce a ninja file from the contrived gyp file below, and run ninja on the top target with multiple jobs, it's quite easy to trigger "ninja: error: mkdir(../../staging): File exists". Technically, this isn't a bug in ninja: it's really a problem of incompletely specified dependencies. But seeing as it's so easy to handle this and that it's already handled in NinjaMain::EnsureBuildDirExists, I think it's worth handling here too. { |
Any updates on this? |
@nico: ping would you prefer this to work in the same way that NinjaMain::EnsureBuildDirExists checks for EEXIST? |
Sorry for not looking earlier. I don't mind too much passing over EEXIST. I can't think of any scenarios where it'd be harmful. If it's true that Ninja always wants to skip on EEXIST, I think it'd be good to rename the relevant functions to make their intent clearer. Perhaps MakeDirs should be renamed MakeContainingDirs (since it expects a path to a file and creates all the parents), which then calls a MakeDirs that does the mkdir -p equivalent, and then the various callers could use that. It'd let the call from EnsureBuildDirExist also be clearer (in that it wouldn't need to construct a fake path within the directory). (I think Nico is probably the right person to finally eval this in any case.) |
I can't think of problems with this patch either, but I think trying to work well with bad build files (which is what this is about, if I understand the above correctly) shouldn't be a goal. I'm afraid that merging this will beget similar patches. (Not necessarily from the same author.) |
The plausible use case I can think of is if you have something like:
If these two rules interleave at exactly the wrong times, then Ninja can race the header-generator in creating the directory. Is it always the case that Ninja must know the paths to all generated files? I think there are legitimate cases where it won't, but I'm not positive... |
A possible scenario that I think it would be reasonable for ninja to support: you have a tool that generates output that is not easy to predict exactly beforehand (eg doxygen, but I'm not sure if it creates many directories) and a ninja rule that outputs a file somewhere into the same tree. A purist could rightly say that you should simply add intermediate rules to create the shared directory paths, plus some dependencies to get the ordering right. But since this is so easy to fix in the ninja source, I think it's worth doing there. |
Please reconsider merging this. Ninja's manual claims "Output directories are always implicitly created before running the command that relies on them." as an advantage/feature. This is not true if it can be foiled by an external tool that might create the same directories at the "wrong" time, necessitating somewhat redundant mkdir targets to sync things. I believe it makes more sense to do this robustly than it is to add a lengthy explanation of when things might go wrong in some parallel scenarios. |
I suppose the patch is innocent enough. |
don't Fail if trying to mkdir when the dir already exists
When ninja tries to do the equivalent of "mkdir -p", it will fail if another process (or possibly another ninja task) creates one of the intermediate dirs in the meantime. This can be quite annoying, but it's fairly simple to catch.
NinjaMain::EnsureBuildDirExists doesn't fail in case of EEXIST (the check would be redundant if this patch is landed), but Builder::StartEdge does. Perhaps we should just check for EEXIST in Builder::StartEdge?