summary | shortlog | log | commit | commitdiff | tree
raw | patch | inline | side by side (parent: ee36856)
raw | patch | inline | side by side (parent: ee36856)
author | Theodore Ts'o <tytso@mit.edu> | |
Fri, 29 Jun 2007 17:40:46 +0000 (13:40 -0400) | ||
committer | Junio C Hamano <gitster@pobox.com> | |
Sun, 1 Jul 2007 03:16:12 +0000 (20:16 -0700) |
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>
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>
Documentation/git.txt | patch | blob | history | |
builtin-blame.c | patch | blob | history | |
builtin-rev-list.c | patch | blob | history | |
cache.h | patch | blob | history | |
log-tree.c | patch | blob | history | |
write_or_die.c | patch | blob | history |
diff --git a/Documentation/git.txt b/Documentation/git.txt
index 20b5b7bb48f75cea066857c6967a08203957d927..826914837bc0a3e1fa5f044f69b837abdd42cf8c 100644 (file)
--- a/Documentation/git.txt
+++ b/Documentation/git.txt
'GIT_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'::
If this variable is set to "1", "2" or "true" (comparison
is case insensitive), git will print `trace:` messages on
diff --git a/builtin-blame.c b/builtin-blame.c
index f7e2c13885a384d58c3481fa7259a64bf9525045..da23a6f9c99e1db691ba9329ea33a320b56b6afc 100644 (file)
--- a/builtin-blame.c
+++ b/builtin-blame.c
printf("boundary\n");
}
write_filename_info(suspect->path);
+ maybe_flush_or_die(stdout, "stdout");
}
}
diff --git a/builtin-rev-list.c b/builtin-rev-list.c
index 813aadf596df7fe2e61517915707717120842d74..86db8b03fe4295497cf011a75617d6dc8f172c64 100644 (file)
--- a/builtin-rev-list.c
+++ b/builtin-rev-list.c
printf("%s%c", buf, hdr_termination);
free(buf);
}
- fflush(stdout);
+ maybe_flush_or_die(stdout, "stdout");
if (commit->parents) {
free_commit_list(commit->parents);
commit->parents = NULL;
index ed83d92c5a2735b2b7f8a7fc06276acbf0df8b18..0525c4ee55a05304a6b2018cc27933baa5510aba 100644 (file)
--- a/cache.h
+++ b/cache.h
extern const char *git_commit_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 read_in_full(int fd, void *buf, size_t count);
extern int write_in_full(int fd, const void *buf, size_t count);
diff --git a/log-tree.c b/log-tree.c
index 0cf21bc05180b577a5f14dc57031c260e7c44334..ced3f332ef767e39239874edd68c8445ba6991d9 100644 (file)
--- a/log-tree.c
+++ b/log-tree.c
shown = 1;
}
opt->loginfo = NULL;
+ maybe_flush_or_die(stdout, "stdout");
return shown;
}
diff --git a/write_or_die.c b/write_or_die.c
index 5c4bc8515ab9484131de7e065e08657315004f8c..e125e11d3b63e3dab9077d7b414e83e7ff7d16ad 100644 (file)
--- a/write_or_die.c
+++ b/write_or_die.c
#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)
{
char *p = buf;