git/list[1] front-page[2] threads[3] people[4] search[5] about
 

Re: [PATCH] mingw: enable atomic O_APPEND

From
Junio C Hamano <gitster@pobox.com>
Date
Aug 13, 2018, 20:20 UTC
Message-ID
<xmqqr2j23tnb.fsf@gitster-ct.c.googlers.com>
In-Reply-To
<bc9132ab-3030-07e3-03d1-d2ddae6a1b45@kdbg.org>
Johannes Sixt <j6t@kdbg.org> writes:
Show 24 quoted lines
> The Windows CRT implements O_APPEND "manually": on write() calls, the
> file pointer is set to EOF before the data is written. Clearly, this is
> not atomic. And in fact, this is the root cause of failures observed in
> t5552-skipping-fetch-negotiator.sh and t5503-tagfollow.sh, where
> different processes write to the same trace file simultanously; it also
> occurred in t5400-send-pack.sh, but there it was worked around in
> 71406ed4d6 ("t5400: avoid concurrent writes into a trace file",
> 2017-05-18).
>
> Fortunately, Windows does support atomic O_APPEND semantics using the
> file access mode FILE_APPEND_DATA. Provide an implementation that does.
>
> This implementation is minimal in such a way that it only implements
> the open modes that are actually used in the Git code base. Emulation
> for other modes can be added as necessary later. To become aware of
> the necessity early, the unusal error ENOSYS is reported if an
> unsupported mode is encountered.
>
> Diagnosed-by: Johannes Schindelin <Johannes.Schindelin@gmx.de>
> Helped-by: Jeff Hostetler <git@jeffhostetler.com>
> Signed-off-by: Johannes Sixt <j6t@kdbg.org>
> ---
>  compat/mingw.c | 41 +++++++++++++++++++++++++++++++++++++++--
>  1 file changed, 39 insertions(+), 2 deletions(-)
Nice.

I wonder how much more expensive using this implementation is compared with the original "race susceptible" open(), when raciness is known not to be an issue (e.g. there is higher level lock that protects the appending).

If it turns out to be quite more costly, I do not think we'd mind introducing a thin wrapper

#ifndef race_safe_append_open #ifndef race_safe_append_open(fn) open(fn, O_WRONLY|O_APPEND|O_CREAT, 0666) #endif

in git-compat-util.h after it includes "compat/mingw.h" and replace the call to open(... O_APPEND ...) in trace.c::get_trace_fd() with a call to that wrapper. That way, other codepaths that use O_APPEND (namely, reflog and todo-list writers) can avoid the additional cost, if any.

Some may find it beneficial from code readability POV because that approach marks the codepath that needs to have non-racy fd more explicitly.

I am assuming that in this case other users of O_APPEND are not performance critical, so hopefully the following is only theoretical and not necessary.

 git-compat-util.h | 5 +++++
 trace.c           | 2 +-
 2 files changed, 6 insertions(+), 1 deletion(-)
diff --git a/git-compat-util.h b/git-compat-util.h
index 9a64998b24..a981c50800 100644
--- a/git-compat-util.h
+++ b/git-compat-util.h
@@ -218,6 +218,11 @@
 #else
 #include <stdint.h>
 #endif
+
+#ifndef race_safe_append_open
+#define race_safe_append_open(fn) open(fn, O_WRONLY|O_APPEND|O_CREAT, 0666)
+#endif
+
 #ifdef NO_INTPTR_T
 /*
  * On I16LP32, ILP32 and LP64 "long" is the save bet, however
diff --git a/trace.c b/trace.c
index fc623e91fd..bef9cee1da 100644
--- a/trace.c
+++ b/trace.c
@@ -47,7 +47,7 @@ static int get_trace_fd(struct trace_key *key)
 	else if (strlen(trace) == 1 && isdigit(*trace))
 		key->fd = atoi(trace);
 	else if (is_absolute_path(trace)) {
-		int fd = open(trace, O_WRONLY | O_APPEND | O_CREAT, 0666);
+		int fd = race_safe_append_open(trace);
 		if (fd == -1) {
 			warning("could not open '%s' for tracing: %s",
 				trace, strerror(errno));
Previous: Johannes SixtNext: Johannes Sixt
Message 26 of 43 in “t5552: fix flakiness by introducing proper locking for GIT_TRACE”
  1. 0/4 t5552: fix flakiness by introducing proper locking for GIT_TRACEJohannes Schindelin via GitGitGadget, Aug 9, 2018
  2. 1/4 Introduce a function to lock/unlock file descriptors when appendingJohannes Schindelin via GitGitGadget, Aug 9, 2018
  3. Junio C HamanoAug 9, 2018
  4. Johannes SchindelinAug 10, 2018
  5. 2/4 mingw: implement lock_or_unlock_fd_for_appending()Johannes Schindelin via GitGitGadget, Aug 9, 2018
  6. 3/4 trace: lock the trace file to avoid racy trace_write() callsJohannes Schindelin via GitGitGadget, Aug 9, 2018
  7. 4/4 trace: verify that locking worksJohannes Schindelin via GitGitGadget, Aug 9, 2018
  8. Jeff KingAug 9, 2018
  9. Junio C HamanoAug 9, 2018
  10. Junio C HamanoAug 9, 2018
  11. Jeff KingAug 9, 2018
  12. Jeff KingAug 10, 2018
  13. Junio C HamanoAug 10, 2018
  14. Junio C HamanoAug 10, 2018
  15. Johannes SchindelinAug 10, 2018
  16. Jeff KingAug 10, 2018
  17. Junio C HamanoAug 10, 2018
  18. Johannes SchindelinAug 10, 2018
  19. Johannes SixtAug 10, 2018
  20. Jeff HostetlerAug 10, 2018
  21. Jeff HostetlerAug 10, 2018
  22. Johannes SixtAug 10, 2018
  23. Junio C HamanoAug 10, 2018
  24. Jeff KingAug 10, 2018
  25. mingw: enable atomic O_APPENDJohannes Sixt, Aug 13, 2018
  26. Junio C HamanoAug 13, 2018
  27. Johannes SixtAug 13, 2018
  28. Ævar Arnfjörð BjarmasonAug 13, 2018
  29. Junio C HamanoAug 13, 2018
  30. Jeff KingAug 13, 2018
  31. Ævar Arnfjörð BjarmasonAug 14, 2018
  32. Jeff KingAug 14, 2018
  33. Johannes SixtAug 14, 2018
  34. Jeff KingAug 14, 2018
  35. Jeff HostetlerAug 14, 2018
  36. Junio C HamanoAug 14, 2018
  37. 0/4 t5552: fix flakiness by introducing proper locking for GIT_TRACEJohannes Schindelin via GitGitGadget, Aug 10, 2018
  38. 1/4 Introduce a function to lock/unlock file descriptors when appendingJohannes Schindelin via GitGitGadget, Aug 10, 2018
  39. Junio C HamanoAug 10, 2018
  40. Johannes SchindelinAug 10, 2018
  41. 2/4 mingw: implement lock_or_unlock_fd_for_appending()Johannes Schindelin via GitGitGadget, Aug 10, 2018
  42. 3/4 trace: lock the trace file to avoid racy trace_write() callsJohannes Schindelin via GitGitGadget, Aug 10, 2018
  43. 4/4 trace: verify that locking worksJohannes Schindelin via GitGitGadget, Aug 10, 2018

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.