From: Jeff King <peff@peff.net>
To: "Ævar Arnfjörð Bjarmason" <avarab@gmail.com>
Cc: Johannes Sixt <j6t@kdbg.org>, Junio C Hamano <gitster@pobox.com>,
Johannes Schindelin <johannes.schindelin@gmx.de>,
git@vger.kernel.org, Jeff Hostetler <git@jeffhostetler.com>
Subject: Re: [PATCH] mingw: enable atomic O_APPEND
Date: Mon, 13 Aug 2018 18:37:01 -0400 [thread overview]
Message-ID: <20180813223701.GC16006@sigill.intra.peff.net> (raw)
In-Reply-To: <87eff2rmgt.fsf@evledraar.gmail.com>
On Mon, Aug 13, 2018 at 11:22:10PM +0200, Ævar Arnfjörð Bjarmason wrote:
> > O_APPEND is POSIX and means race-free append. If you mark some call
> > sites with O_APPEND, then that must be the ones that need race-free
> > append. Hence, you would have to go the other route: Mark those call
> > sites that do _not_ need race-free append with some custom
> > function/macro. (Or mark both with different helpers and avoid writing
> > down O_APPEND.)
>
> O_APPEND in POSIX is race-free only up to PIPE_MAX bytes written at a
> time, which is e.g. 2^12 by default on linux, after that all bets are
> off and the kernel is free to interleave different write calls.
This is a claim I've run across often, but I've never seen a good
citation for it.
Certainly atomic writes to _pipes_ are determined by PIPE_BUF (which
IIRC is not even a constant on Linux, but can be changed at run-time).
But is it relevant for regular-file writes?
Another gem I found while digging on this O_APPEND/FILE_APPEND_DATA
stuff the other day: somebody claimed that the max atomic-append size on
Linux is 4096 and 1024 on Windows. But their experimental script was
done in bash! So I suspect they were really just measuring the size of
stdio buffers.
Here's my attempt at a test setup. This C program forces two processes
to write simultaneously to the same file with O_APPEND:
-- >8 --
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <sys/types.h>
#include <fcntl.h>
#include <unistd.h>
static void doit(int size, const char *fn, char c)
{
int fd;
char *buf;
fd = open(fn, O_WRONLY|O_APPEND|O_CREAT, 0666);
if (fd < 0) {
perror("open");
return;
}
buf = malloc(size);
memset(buf, c, size);
while (1)
write(fd, buf, size);
}
int main(int argc, const char **argv)
{
int size = atoi(argv[1]);
if (fork())
doit(size, argv[2], '1');
else
doit(size, argv[2], '2');
return 0;
}
-- 8< --
and then this program checks that we saw atomic units of the correct
size:
-- >8 --
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
int main(int argc, const char **argv)
{
int size = atoi(argv[1]);
char *buf;
buf = malloc(size);
while (1) {
int i;
/* assume atomic reads, i.e., no signals */
int r = read(0, buf, size);
if (!r)
break;
for (i = 1; i < size; i++) {
if (buf[i] != buf[0]) {
fprintf(stderr, "overlap\n");
return 1;
}
}
}
return 0;
}
-- 8< --
And then you can do something like:
for size in 4097 8193 16385 32769 65537 131073 262145 524289 1048577; do
>out ;# clean up from last run
echo "Trying $size..."
timeout 5 ./write $size out
if ! ./check $size <out; then
echo "$size failed"
break
fi
done
On my Linux system, each of those seems to write several gigabytes
without overlapping. I did manage to hit some failing cases, but they
were never sheared writes, but rather cases where there was an
incomplete write at the end-of-file.
So obviously this is all a bit of a tangent. I'd be fine declaring that
trace output is generally small enough not to worry about this in the
first place. But those results show that it shouldn't matter even if
we're writing 1MB trace lines on Linux. I wouldn't be at all surprised
to see different results on other operating systems, though.
-Peff
next prev parent reply other threads:[~2018-08-13 22:37 UTC|newest]
Thread overview: 43+ messages / expand[flat|nested] mbox.gz Atom feed top
2018-08-09 17:35 [PATCH 0/4] t5552: fix flakiness by introducing proper locking for GIT_TRACE Johannes Schindelin via GitGitGadget
2018-08-09 17:35 ` [PATCH 1/4] Introduce a function to lock/unlock file descriptors when appending Johannes Schindelin via GitGitGadget
2018-08-09 19:01 ` Junio C Hamano
2018-08-10 18:32 ` Johannes Schindelin
2018-08-09 17:35 ` [PATCH 2/4] mingw: implement lock_or_unlock_fd_for_appending() Johannes Schindelin via GitGitGadget
2018-08-09 17:35 ` [PATCH 3/4] trace: lock the trace file to avoid racy trace_write() calls Johannes Schindelin via GitGitGadget
2018-08-09 17:35 ` [PATCH 4/4] trace: verify that locking works Johannes Schindelin via GitGitGadget
2018-08-09 19:47 ` [PATCH 0/4] t5552: fix flakiness by introducing proper locking for GIT_TRACE Jeff King
2018-08-09 20:49 ` Junio C Hamano
2018-08-09 21:08 ` Junio C Hamano
2018-08-09 21:32 ` Jeff King
2018-08-10 14:09 ` Jeff King
2018-08-10 15:58 ` Junio C Hamano
2018-08-10 15:58 ` Junio C Hamano
2018-08-10 16:43 ` Johannes Schindelin
2018-08-10 17:15 ` Jeff King
2018-08-10 18:40 ` Junio C Hamano
2018-08-10 19:34 ` Johannes Schindelin
2018-08-10 16:15 ` Johannes Sixt
2018-08-10 16:51 ` Jeff Hostetler
2018-08-10 16:57 ` Jeff Hostetler
2018-08-10 17:08 ` Johannes Sixt
2018-08-10 18:34 ` Junio C Hamano
2018-08-10 18:56 ` Jeff King
2018-08-13 19:02 ` [PATCH] mingw: enable atomic O_APPEND Johannes Sixt
2018-08-13 20:20 ` Junio C Hamano
2018-08-13 21:05 ` Johannes Sixt
2018-08-13 21:22 ` Ævar Arnfjörð Bjarmason
2018-08-13 21:55 ` Junio C Hamano
2018-08-13 22:37 ` Jeff King [this message]
2018-08-14 13:47 ` Ævar Arnfjörð Bjarmason
2018-08-14 14:53 ` Jeff King
2018-08-14 18:29 ` Johannes Sixt
2018-08-14 19:17 ` Jeff King
2018-08-14 13:01 ` Jeff Hostetler
2018-08-14 14:38 ` Junio C Hamano
2018-08-10 19:47 ` [PATCH v2 0/4] t5552: fix flakiness by introducing proper locking for GIT_TRACE Johannes Schindelin via GitGitGadget
2018-08-10 19:47 ` [PATCH v2 1/4] Introduce a function to lock/unlock file descriptors when appending Johannes Schindelin via GitGitGadget
2018-08-10 20:05 ` Junio C Hamano
2018-08-10 21:31 ` Johannes Schindelin
2018-08-10 19:47 ` [PATCH v2 2/4] mingw: implement lock_or_unlock_fd_for_appending() Johannes Schindelin via GitGitGadget
2018-08-10 19:47 ` [PATCH v2 3/4] trace: lock the trace file to avoid racy trace_write() calls Johannes Schindelin via GitGitGadget
2018-08-10 19:47 ` [PATCH v2 4/4] trace: verify that locking works Johannes Schindelin via GitGitGadget
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20180813223701.GC16006@sigill.intra.peff.net \
--to=peff@peff.net \
--cc=avarab@gmail.com \
--cc=git@jeffhostetler.com \
--cc=git@vger.kernel.org \
--cc=gitster@pobox.com \
--cc=j6t@kdbg.org \
--cc=johannes.schindelin@gmx.de \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).