summaryrefslogtreecommitdiff
path: root/diff.c
diff options
context:
space:
mode:
authorShawn O. Pearce <spearce@spearce.org>2006-12-14 06:15:57 -0500
committerJunio C Hamano <junkio@cox.net>2006-12-15 22:11:19 -0800
commit1510fea781cb0517eeba8c378964f7bc4f9577ab (patch)
tree80be67e623e96f28290834a443c5dd685952115d /diff.c
parent1576f5f7b2addd648a41fb5cfbcd2e6d632b7461 (diff)
downloadgit-1510fea781cb0517eeba8c378964f7bc4f9577ab.tar.gz
Avoid accessing a slow working copy during diffcore operations.
The Cygwin folks have done a fine job at creating a POSIX layer on Windows That Just Works(tm). However it comes with a penalty; accessing files in the working tree by way of stat/open/mmap can be slower for diffcore than inflating the data from a blob which is stored in a packfile. This performance problem is especially an issue in merge-recursive when dealing with nearly 7000 added files, as we are loading each file's content from the working directory to perform rename detection. I have literally seen (and sadly watched) paint dry in less time than it takes for merge-recursive to finish such a merge. On the other hand this very same merge runs very fast on Solaris. If Git is compiled with NO_FAST_WORKING_DIRECTORY set then we will avoid looking at the working directory when the blob in question is available within a packfile and the caller doesn't need the data unpacked into a temporary file. We don't use loose objects as they have the same open/mmap/close costs as the working directory file access, but have the additional CPU overhead of needing to inflate the content before use. So it is still faster to use the working tree file over the loose object. If the caller needs the file data unpacked into a temporary file its likely because they are going to call an external diff program, passing the file as a parameter. In this case reusing the working tree file will be faster as we don't need to inflate the data and write it out to a temporary file. The NO_FAST_WORKING_DIRECTORY feature is enabled by default on Cygwin, as that is the platform which currently appears to benefit the most from this option. Signed-off-by: Shawn O. Pearce <spearce@spearce.org> Signed-off-by: Junio C Hamano <junkio@cox.net>
Diffstat (limited to 'diff.c')
-rw-r--r--diff.c24
1 files changed, 21 insertions, 3 deletions
diff --git a/diff.c b/diff.c
index 2df14b2469..77ba641aa4 100644
--- a/diff.c
+++ b/diff.c
@@ -12,6 +12,12 @@
#include "xdiff-interface.h"
#include "color.h"
+#ifdef NO_FAST_WORKING_DIRECTORY
+#define FAST_WORKING_DIRECTORY 0
+#else
+#define FAST_WORKING_DIRECTORY 1
+#endif
+
static int use_size_cache;
static int diff_detect_rename_default;
@@ -1158,7 +1164,7 @@ void fill_filespec(struct diff_filespec *spec, const unsigned char *sha1,
* the work tree has that object contents, return true, so that
* prepare_temp_file() does not have to inflate and extract.
*/
-static int work_tree_matches(const char *name, const unsigned char *sha1)
+static int reuse_worktree_file(const char *name, const unsigned char *sha1, int want_file)
{
struct cache_entry *ce;
struct stat st;
@@ -1179,6 +1185,18 @@ static int work_tree_matches(const char *name, const unsigned char *sha1)
if (!active_cache)
return 0;
+ /* We want to avoid the working directory if our caller
+ * doesn't need the data in a normal file, this system
+ * is rather slow with its stat/open/mmap/close syscalls,
+ * and the object is contained in a pack file. The pack
+ * is probably already open and will be faster to obtain
+ * the data through than the working directory. Loose
+ * objects however would tend to be slower as they need
+ * to be individually opened and inflated.
+ */
+ if (FAST_WORKING_DIRECTORY && !want_file && has_sha1_pack(sha1, NULL))
+ return 0;
+
len = strlen(name);
pos = cache_name_pos(name, len);
if (pos < 0)
@@ -1265,7 +1283,7 @@ int diff_populate_filespec(struct diff_filespec *s, int size_only)
if (s->data)
return err;
if (!s->sha1_valid ||
- work_tree_matches(s->path, s->sha1)) {
+ reuse_worktree_file(s->path, s->sha1, 0)) {
struct stat st;
int fd;
if (lstat(s->path, &st) < 0) {
@@ -1372,7 +1390,7 @@ static void prepare_temp_file(const char *name,
}
if (!one->sha1_valid ||
- work_tree_matches(name, one->sha1)) {
+ reuse_worktree_file(name, one->sha1, 1)) {
struct stat st;
if (lstat(name, &st) < 0) {
if (errno == ENOENT)