Retry committing locked files on error - #2211
Conversation
There was a problem hiding this comment.
This is cross-platform code, buddy, you can't throw a Sleep in here. Could you please wrap this around #ifdef GIT_WIN32 tags, since this is not an issue on Unix systems?
There was a problem hiding this comment.
Also you may want to write this logic as part of p_rename itself (in posix/win32) so it affects all other parts of the code that rename files.
When a file is open for reading (without shared-delete permission), and then a different thread/process called p_rename, that would fail, even if the file was only open for reading for a few milliseconds. This change lets p_rename wait up to 50ms for the file to be closed by the reader. Applies only to win32. This is especially important for git_filebuf_commit, because writes should not fail if the file is read simultaneously. Fixes libgit2#2207
|
Thanks for your comments! I moved the code into |
There was a problem hiding this comment.
The error name ERROR_ACCESS_DENIED seems to indicate that we're simply not allowed to write to this file, no matter how much we retry. Googling seems to indicate that it is in fact a permissions error.
There was a problem hiding this comment.
ERROR_ACCESS_DENIED is in fact the error I get in the case described above. I don't really understand what's going on, maybe the anti virus software protects the files while it's scanning them. Anyhow - this PR fixes the problem.
There was a problem hiding this comment.
ERROR_ACCESS_DENIED is what NT returns for all kinds of stuff - could be temporary, could be an actual permissions problem, you shouldn't read into it
|
I think it's a good idea, for sure. Windows operates in this disappointing place where files are implicitly locked and if not, then they change in the middle of you reading them. This sort of technique is a requirement for many scenarios. Out of curiosity, how was the 50ms figure arrived at? I want a sanity-check from @phkelley as well, when he has a moment, since he knows better than I about all things Win32. |
It's the first number I picked. As I wrote above, I saw up to three Access Denied errors in a row, which equals to 15-20 ms. 50ms gives a safety margin. But I don't know about other systems. |
Legit. My gut says that we might want to wait a little longer. This is a common pattern that we use, let me see if I can find some of our numbers. Some historic data might be interesting since some of them probably predate SSDs and other fast type hardware. |
|
This seems like a good idea to me. I wonder if we should add a |
|
BTW, sorry, I just reread the patch and realize this is currently doing 10 tries at 5ms each. |
|
I agree that we should make the retry time configurable, so that users can balance performance vs. reliability. But I think exposing two options, one for time and one for step count is too complicated. What really matters is the total maximum wait time. This should be divided into reasonable time steps to enhance performance. And we need to provide a reasonable default maximum wait time. @ethomson Did you find out anything? |
|
This function (
(I would prefer to not retry errors from I wrote an implementation of this mechanism for clar at one point. It was an important part of increasing our test reliability on Win32. (The tests would fail almost 100% of the time before this on XP, for example.) You can find it at: https://github.com/vmg/clar/blob/master/clar/fs.h The key functions to look at are I remember at one point rewriting |
|
If I understand your proposal, it would lead to a situation where we would delete a file before putting the new one in place. This would go against a pretty basic assumption we make. Namely that a rename will atomically replace the target file. Otherwise, we end up in a situation, where we've e.g. deleted HEAD but not put in its replacement yet, leading to some time (albeit short) where we've made the repository invalid; or made a branch disappear. |
Maybe I got it wrong, but isn't that exactly what we're doing now? |
|
I don't want to end this discussion, but I think we should merge this PR as it is. It seems like it is a definite improvement to the existing behavior of the library. Obviously there are further improvements to configurability or stable behavior that can be achieved, and the discussion can continue here even after a merge and any outcomes can be addressed in a separate PR. Unless I hear someone saying a loud NO, I'm going to merge this later today. |
Retry committing locked files on error
|
Gonna apply a couple style changes manually. |
Retry committing locked files on error
When a config file is open for reading (without shared-delete permission), and then a different thread/process called git_filebuf_commit, that would fail, even if the file was only open for reading for a few milliseconds. This change lets git_filebuf_commit wait up to 50ms for the file to be closed by the reader.
Fixes #2207
In my environment, a service locks newly created files regularily. I set up a test case to continouously init new repositories, and with 4000 inits, I got 160 AccessDenied errors. Most of the times, it works on the
rename_try, the maximum I saw were 3 errors in a row, so it succeded in the fourth try.What do you think of this solution? It should not affect performance because the delay only occurs when the operation would fail anyway.