020406eaa5
This commit introduces the infrastructure for the core.fsync configuration knob. The repository components we want to sync are identified by flags so that we can turn on or off syncing for specific components. If core.fsyncObjectFiles is set and the core.fsync configuration also includes FSYNC_COMPONENT_LOOSE_OBJECT, we will fsync any loose objects. This picks the strictest data integrity behavior if core.fsync and core.fsyncObjectFiles are set to conflicting values. This change introduces the currently unused fsync_component helper, which will be used by a later patch that adds fsyncing to the refs backend. Actual configuration and documentation of the fsync components list are in other patches in the series to separate review of the underlying mechanism from the policy of how it's configured. Helped-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Neeraj Singh <neerajsi@microsoft.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
111 lines
2.3 KiB
C
111 lines
2.3 KiB
C
#include "cache.h"
|
|
#include "config.h"
|
|
#include "run-command.h"
|
|
|
|
/*
|
|
* Some cases use stdio, but want to flush after the write
|
|
* to get error handling (and to get better interactive
|
|
* behaviour - not buffering excessively).
|
|
*
|
|
* Of course, if the flush happened within the write itself,
|
|
* we've already lost the error code, and cannot report it any
|
|
* more. So we just ignore that case instead (and hope we get
|
|
* the right error code on the flush).
|
|
*
|
|
* If the file handle is stdout, and stdout is a file, then skip the
|
|
* flush entirely since it's not needed.
|
|
*/
|
|
void maybe_flush_or_die(FILE *f, const char *desc)
|
|
{
|
|
static int skip_stdout_flush = -1;
|
|
struct stat st;
|
|
char *cp;
|
|
|
|
if (f == stdout) {
|
|
if (skip_stdout_flush < 0) {
|
|
cp = getenv("GIT_FLUSH");
|
|
if (cp)
|
|
skip_stdout_flush = (atoi(cp) == 0);
|
|
else if ((fstat(fileno(stdout), &st) == 0) &&
|
|
S_ISREG(st.st_mode))
|
|
skip_stdout_flush = 1;
|
|
else
|
|
skip_stdout_flush = 0;
|
|
}
|
|
if (skip_stdout_flush && !ferror(f))
|
|
return;
|
|
}
|
|
if (fflush(f)) {
|
|
check_pipe(errno);
|
|
die_errno("write failure on '%s'", desc);
|
|
}
|
|
}
|
|
|
|
void fprintf_or_die(FILE *f, const char *fmt, ...)
|
|
{
|
|
va_list ap;
|
|
int ret;
|
|
|
|
va_start(ap, fmt);
|
|
ret = vfprintf(f, fmt, ap);
|
|
va_end(ap);
|
|
|
|
if (ret < 0) {
|
|
check_pipe(errno);
|
|
die_errno("write error");
|
|
}
|
|
}
|
|
|
|
static int maybe_fsync(int fd)
|
|
{
|
|
if (use_fsync < 0)
|
|
use_fsync = git_env_bool("GIT_TEST_FSYNC", 1);
|
|
if (!use_fsync)
|
|
return 0;
|
|
|
|
if (fsync_method == FSYNC_METHOD_WRITEOUT_ONLY &&
|
|
git_fsync(fd, FSYNC_WRITEOUT_ONLY) >= 0)
|
|
return 0;
|
|
|
|
return git_fsync(fd, FSYNC_HARDWARE_FLUSH);
|
|
}
|
|
|
|
void fsync_or_die(int fd, const char *msg)
|
|
{
|
|
if (maybe_fsync(fd) < 0)
|
|
die_errno("fsync error on '%s'", msg);
|
|
}
|
|
|
|
int fsync_component(enum fsync_component component, int fd)
|
|
{
|
|
if (fsync_components & component)
|
|
return maybe_fsync(fd);
|
|
return 0;
|
|
}
|
|
|
|
void fsync_component_or_die(enum fsync_component component, int fd, const char *msg)
|
|
{
|
|
if (fsync_components & component)
|
|
fsync_or_die(fd, msg);
|
|
}
|
|
|
|
void write_or_die(int fd, const void *buf, size_t count)
|
|
{
|
|
if (write_in_full(fd, buf, count) < 0) {
|
|
check_pipe(errno);
|
|
die_errno("write error");
|
|
}
|
|
}
|
|
|
|
void fwrite_or_die(FILE *f, const void *buf, size_t count)
|
|
{
|
|
if (fwrite(buf, 1, count, f) != count)
|
|
die_errno("fwrite error");
|
|
}
|
|
|
|
void fflush_or_die(FILE *f)
|
|
{
|
|
if (fflush(f))
|
|
die_errno("fflush error");
|
|
}
|