-
Notifications
You must be signed in to change notification settings - Fork 2.6k
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
Fix append failure issue under remote directories #2753 #3646
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a great start!
I would like to ask for a few improvements:
- could you have a look at the existing commit messages, e.g. 9d0a094? Then try to imitate the style:
- start with a very brief description that explains what this patch is all about (take c2369bd for inspiration)
- then start the body of the commit message by describing the actual problem that is solved by this patch
- continue by discussing the various alternatives you considered to solve this problem
- explain why the approach taken by this patch was chosen
- then, and only then, reference the ticket that is fixed by this patch
- this definitely needs a test case, if we can add one without requiring a "real" remote share. As I had described, we already use a trick in
t/t5580-unc-paths.sh
to test Git access to remote shares by using the so-called administrative share\\localhost\C$
which simply accesses theC:
drive and is available in our CI builds.- if you are unsure how to write that test case, first have a look at https://github.com/git-for-windows/git/wiki/Running-Git's-regression-tests#running-individual-tests to run
t/t5580-unc-paths.sh
in your local checkout - once you ran this successfully, study the code, see for example how we test cloning from a remote share by using the
$UNCPATH
variable which simply contains the UNC version of the current directory's path - you will most likely want to add your test case at the very end of the test script, starting with
test_expect_success
and then continuing with a description of what is being tested, then the actual code to run for the test - to run your test, use the
--run=9
option (with whatever number your test case will have, use--run=0
to find out, this will skip all tests but print out their labels and their numbers) - you will want to make extra sure that the test case fails unless you modify
compat/mingw.c
: after committing all your (in-flux) changes, temporarily revert the respective part by runninggit checkout HEAD^ -- compat/mingw.c
, then building withmake
, then running the test (and when the test failed as expected, do not forget to undo the temporary revert viagit checkout HEAD -- compat/mingw.c
!)
- if you are unsure how to write that test case, first have a look at https://github.com/git-for-windows/git/wiki/Running-Git's-regression-tests#running-individual-tests to run
compat/mingw.c
Outdated
* slashes to backslashes. This is essential to get GetDriveTypeW() | ||
* correctly handle some UNC "\\server\share\..." paths. | ||
*/ | ||
if (!GetFullPathNameW(wpath, MAX_LONG_PATH, wfullpath, NULL)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a pretty costly call. It would be better to use something like convert_slashes()
.
This comment was marked as off-topic.
This comment was marked as off-topic.
Sorry, something went wrong.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a pretty costly call. It would be better to use something like
convert_slashes()
.
yeah, that is true, but GetDriveTypeW
needs full path as its input.
Currently, I use GetDriveType
to check if a file path is local or not and I failed to find a solid better solution, do you have any suggestion?
by the way, has_dos_drive_prefix
should not work, for file may locate in a mapped network drive, such as drive "Z" mapped to a network folder.
compat/mingw.c
Outdated
@@ -759,7 +801,7 @@ int mingw_open (const char *filename, int oflags, ...) | |||
return -1; | |||
} | |||
|
|||
if ((oflags & O_APPEND) && !is_local_named_pipe_path(filename)) | |||
if ((oflags & O_APPEND) && is_local_disk_file(filename)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Previously, this condition triggered when appending to anything but a local named pipe. Now, this is restricted to local disk files? That sounds a bit overzealous.
It would probably make more sense to trigger the new (expensive!) code path only if the open_fn()
call further down in this function failed (essentially: try running with mingw_open_append()
first, and re-try using _wopen()
only if it failed, and only if GetLastError()
has the expected value, which you can easily find out by printing it when the function call fails in your scenario, and then only if that GetDriveTypeW()
indicates a remote path).
Of course, an alternative would be to simply ask has_dos_drive_prefix()
as an indicator for a local file:
if ((oflags & O_APPEND) && !is_local_named_pipe_path(filename) && has_dos_drive_prefix(filename))
That should be good-enough in your use case, and fix the issue reliably without having to go through expensive Win32 API calls.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
After re-checking git commit(d641097) and MSDN doc(https://docs.microsoft.com/en-us/windows/win32/fileio/file-access-rights-constants), mingw_open_append
is introduced for atomatic append, it uses FILE_APPEND_DATA
only flag to achieve this, and according to the MSDN doc, it should only work for local files:
I totally agree with you on call mingw_open_append()
first, then re-try _wopen()
only if it failed. but I failed to do this based on my test, mingw_open_append
will still succeed on a UNC path with FILE_APPEND_DATA
, but it will fail in later write
calls. here is my test code, please help to check:
https://gist.github.com/sunzhuoshi/3b3a82e23f0b0cdaf750c7755b843aee
by the way, I map driver "Z" in code to a network folder.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
mingw_open_append
will still succeed on a UNC path withFILE_APPEND_DATA
, but it will fail in laterwrite
calls.
What is the error?
Can you reproduce the same error when using the "administrative share" \\localhost\c$
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
thank you for your feedback.
GetLastError()
after write
returns: ERROR_INVALID_PARAMETER : The parameter is incorrect.
and I failed to reproduce it when using \\localhost\c$
, it creates and writes file successfully.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
GetLastError()
afterwrite
returns:ERROR_INVALID_PARAMETER : The parameter is incorrect.
Okay. Unfortunately, this is not really helpful.
The problem I see here is the adverse effects of this PR for the common case: while is_local_named_pipe_path()
only looks at the string and is therefore very fast, the new is_local_disk_file()
function calls not only GetFullPathNameW()
but also GetDriveTypeW()
, i.e. two I/O operations, read: comparatively expensive functions.
Granted, this is "only" when we're opening a file with the intention to append to it. But still, it is a complication, and judging by the number of bug reports we received, the fix is actually not necessary for all network shares, therefore the workaround is a bit overzealous.
How about doing something different and going for a config option instead? Something like this:
static int append_atomically = -1;
[...]
if (append_atomically < 0 &&
git_config_get_bool("windows.appendatomically", &append_atomically))
append_atomically = 1; /* default to `true` */
if (append_atomically &&
(oflags & O_APPEND) && !is_local_named_pipe_path(filename))
open_fn = mingw_open_append;
[...]
We could then detect the ERROR_INVALID_PARAMETER
condition and suggest to disable atomic appending via the config option.
That would get us mostly to the best of both worlds: best performance for the common case, and a way out of the problematic scenario via an opt-in config setting.
What do you think?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree with you. I'll update it in one or two weeks. Sorry for busy these days.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(invalid)
compat/mingw.c
Outdated
* slashes to backslashes. This is essential to get GetDriveTypeW() | ||
* correctly handle some UNC "\\server\share\..." paths. | ||
*/ | ||
if (!GetFullPathNameW(wpath, MAX_LONG_PATH, wfullpath, NULL)) |
This comment was marked as off-topic.
This comment was marked as off-topic.
Sorry, something went wrong.
d6a6f29
to
97496bb
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Very nice!
I would like to ask for just a few favors:
- could you squash the two commits into a single one? (In the Git project, we frown upon introducing a change only to revert it within the same PR/patch series. I would recommend using an interactive rebase, changing the second commit's
pick
to asquash
.) - could you wrap the commit message to <= 76 columns per line?
- the
git_config_get_bool()
function returns 0 if it succeeded, we should setappend_atomically
only when it failed. Something likeif (append_atomically < 0 && (!the_repository || git_config_get_bool(...))) append_atomically = 1;
, I think. - we need to document this. To this end, we need to introduce
Documentation/config/windows.txt
and include it inDocumentation/config.txt
. SeeDocumentation/config/safe.txt
for an example to imitate (in particular the syntax, so that the manual page renders correctly).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Did you still want to add handling for the ERROR_INVALID_PARAMETER
condition (suggesting to set windows.appendAtomically
) as I suggested here?
Documentation/config/windows.txt
Outdated
@@ -0,0 +1,4 @@ | |||
windows.appendatomically:: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please use appendAtomically
in the documentation, it is easier to read.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
sorry, I missed it, let me try.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry for the delay!
In addition to the suggested change, could I ask you to sign off with your real name, i.e. those beautiful characters instead of a Latinized form?
compat/mingw.c
Outdated
errno = EINVAL; | ||
/* | ||
* default atomatic append causes such error on network file system, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"atomatic" -> "automatic"
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It should be "atomic", right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what do you mean by my real name? my Chinese name? or just "Sun Zhuoshi"?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I meant the Chinese name ;-) I just really like seeing those beautiful Chinese characters.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It should be "atomic", right?
Whoops, yes, you're correct, my bad!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK, but you still pointed out my mistake: "atomatic" -> "atomic". Sharp eyes!
No problem, next time, I'll try to sign off with my Chinese name.
compat/mingw.c
Outdated
* in such case, it should be turned off via config. | ||
*/ | ||
fprintf(stderr, "Invalid write operation detected, " | ||
"you may try to set config windows.appendAtomically to 0.\n"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could we:
- use
warning()
here? - guard this behind a check that we're looking at a remote filesystem (does
GetFileType(h)
returnFILE_TYPE_REMOTE
in that case)?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good idea! I'll try to update it.
08692d4
to
4514cc0
Compare
Atomic append on windows is only supported on local disk files, and it may cause errors in other situations, e.g. network file system. If that is the case, this config option should be used to turn atomic append off. Co-Authored-By: Johannes Schindelin <johannes.schindelin@gmx.de> Signed-off-by: 孙卓识 <sunzhuoshi@gmail.com> Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
@sunzhuoshi I hope you don't mind, I just force-pushed another change on top and plan on merging it as soon as the PR build passed. Could you have a quick look? |
OK, no problem. |
It passed my local test, pretty code update! |
Awesome. Thank you for contributing, @sunzhuoshi ! |
I learned a lot from you, thank you! |
Fix append failure issue under remote directories #2753
Fix append failure issue under remote directories #2753
Fix append failure issue under remote directories #2753
Fix append failure issue under remote directories #2753
Cloning to network shares failed on some network file systems, which was [fixed](git-for-windows/git#3646). Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Fix append failure issue under remote directories #2753
Fix append failure issue under remote directories #2753
Fix append failure issue under remote directories #2753
Fix append failure issue under remote directories #2753
Fix append failure issue under remote directories git-for-windows#2753
Fix append failure issue under remote directories #2753
Fix append failure issue under remote directories #2753
Fix append failure issue under remote directories #2753
Fix append failure issue under remote directories #2753
Fix append failure issue under remote directories #2753
Fix append failure issue under remote directories #2753
Fix append failure issue under remote directories #2753
Fix append failure issue under remote directories #2753
Fix append failure issue under remote directories #2753
Fix append failure issue under remote directories #2753
Fix append failure issue under remote directories #2753
Fix append failure issue under remote directories #2753
Fix append failure issue under remote directories #2753
Fix append failure issue under remote directories #2753
Fix append failure issue under remote directories #2753
Fix append failure issue under remote directories #2753
Fix append failure issue under remote directories #2753
Fix append failure issue under remote directories #2753
Fix append failure issue under remote directories #2753
Signed-off-by: sunzhuoshi sunzhuoshi@gmail.com