Don't fflush(stdout) when it's not helpful
This patch arose from a discussion started by Jim Meyering's patch whose intention was to provide better diagnostics for failed writes. Linus proposed a better way to do things, which also had the added benefit that adding a fflush() to git-log-* operations and incremental git-blame operations could improve interactive respose time feel, at the cost of making things a bit slower when we aren't piping the output to a downstream program. This patch skips the fflush() calls when stdout is a regular file, or if the environment variable GIT_FLUSH is set to "0". This latter can speed up a command such as: GIT_FLUSH=0 strace -c -f -e write time git-rev-list HEAD | wc -l a tiny amount. Signed-off-by: "Theodore Ts'o" <tytso@mit.edu> Acked-by: Linus Torvalds <torvalds@linux-foundation.org> Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
parent
ee36856d8c
commit
06f59e9f5d
@ -396,6 +396,16 @@ other
|
|||||||
'GIT_PAGER'::
|
'GIT_PAGER'::
|
||||||
This environment variable overrides `$PAGER`.
|
This environment variable overrides `$PAGER`.
|
||||||
|
|
||||||
|
'GIT_FLUSH'::
|
||||||
|
If this environment variable is set to "1", then commands such
|
||||||
|
as git-blame (in incremental mode), git-rev-list, git-log,
|
||||||
|
git-whatchanged, etc., will force a flush of the output stream
|
||||||
|
after each commit-oriented record have been flushed. If this
|
||||||
|
variable is set to "0", the output of these commands will be done
|
||||||
|
using completely buffered I/O. If this environment variable is
|
||||||
|
not set, git will choose buffered or record-oriented flushing
|
||||||
|
based on whether stdout appears to be redirected to a file or not.
|
||||||
|
|
||||||
'GIT_TRACE'::
|
'GIT_TRACE'::
|
||||||
If this variable is set to "1", "2" or "true" (comparison
|
If this variable is set to "1", "2" or "true" (comparison
|
||||||
is case insensitive), git will print `trace:` messages on
|
is case insensitive), git will print `trace:` messages on
|
||||||
|
@ -1459,6 +1459,7 @@ static void found_guilty_entry(struct blame_entry *ent)
|
|||||||
printf("boundary\n");
|
printf("boundary\n");
|
||||||
}
|
}
|
||||||
write_filename_info(suspect->path);
|
write_filename_info(suspect->path);
|
||||||
|
maybe_flush_or_die(stdout, "stdout");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -100,7 +100,7 @@ static void show_commit(struct commit *commit)
|
|||||||
printf("%s%c", buf, hdr_termination);
|
printf("%s%c", buf, hdr_termination);
|
||||||
free(buf);
|
free(buf);
|
||||||
}
|
}
|
||||||
fflush(stdout);
|
maybe_flush_or_die(stdout, "stdout");
|
||||||
if (commit->parents) {
|
if (commit->parents) {
|
||||||
free_commit_list(commit->parents);
|
free_commit_list(commit->parents);
|
||||||
commit->parents = NULL;
|
commit->parents = NULL;
|
||||||
|
2
cache.h
2
cache.h
@ -532,6 +532,8 @@ extern char git_default_name[MAX_GITNAME];
|
|||||||
extern const char *git_commit_encoding;
|
extern const char *git_commit_encoding;
|
||||||
extern const char *git_log_output_encoding;
|
extern const char *git_log_output_encoding;
|
||||||
|
|
||||||
|
/* IO helper functions */
|
||||||
|
extern void maybe_flush_or_die(FILE *, const char *);
|
||||||
extern int copy_fd(int ifd, int ofd);
|
extern int copy_fd(int ifd, int ofd);
|
||||||
extern int read_in_full(int fd, void *buf, size_t count);
|
extern int read_in_full(int fd, void *buf, size_t count);
|
||||||
extern int write_in_full(int fd, const void *buf, size_t count);
|
extern int write_in_full(int fd, const void *buf, size_t count);
|
||||||
|
@ -408,5 +408,6 @@ int log_tree_commit(struct rev_info *opt, struct commit *commit)
|
|||||||
shown = 1;
|
shown = 1;
|
||||||
}
|
}
|
||||||
opt->loginfo = NULL;
|
opt->loginfo = NULL;
|
||||||
|
maybe_flush_or_die(stdout, "stdout");
|
||||||
return shown;
|
return shown;
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,45 @@
|
|||||||
#include "cache.h"
|
#include "cache.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)) {
|
||||||
|
if (errno == EPIPE)
|
||||||
|
exit(0);
|
||||||
|
die("write failure on %s: %s", desc, strerror(errno));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int read_in_full(int fd, void *buf, size_t count)
|
int read_in_full(int fd, void *buf, size_t count)
|
||||||
{
|
{
|
||||||
char *p = buf;
|
char *p = buf;
|
||||||
|
Loading…
Reference in New Issue
Block a user