summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJ Wyman <jeremy.wyman@microsoft.com>2015-03-30 14:07:44 -0700
committerEdward Thomson <ethomson@microsoft.com>2015-04-28 14:24:58 -0400
commit4c09e19a3764a1e5f3340dabf8104dfed32e7673 (patch)
tree8df38e74e802445528d626d37276e8b119a7eb46
parentd969d41547080d5e924d49f44ba5de1ade5b343c (diff)
downloadlibgit2-4c09e19a3764a1e5f3340dabf8104dfed32e7673.tar.gz
Improvements to ignore performance on Windows.
Minimizing the number directory and file opens, minimizes the amount of IO thus reducing the overall cost of performing ignore operations.
-rw-r--r--src/attr.c6
-rw-r--r--src/attr_file.c18
-rw-r--r--src/attr_file.h4
-rw-r--r--src/ignore.c6
-rw-r--r--src/ignore.h2
-rw-r--r--src/iterator.c21
-rw-r--r--tests/attr/lookup.c6
7 files changed, 45 insertions, 18 deletions
diff --git a/src/attr.c b/src/attr.c
index 38420807a..102d0248c 100644
--- a/src/attr.c
+++ b/src/attr.c
@@ -55,7 +55,7 @@ int git_attr_get(
*value = NULL;
- if (git_attr_path__init(&path, pathname, git_repository_workdir(repo)) < 0)
+ if (git_attr_path__init(&path, pathname, git_repository_workdir(repo), GIT_DIR_FLAG_UNKNOWN) < 0)
return -1;
if ((error = collect_attr_files(repo, NULL, flags, pathname, &files)) < 0)
@@ -114,7 +114,7 @@ int git_attr_get_many_with_session(
assert(values && repo && names);
- if (git_attr_path__init(&path, pathname, git_repository_workdir(repo)) < 0)
+ if (git_attr_path__init(&path, pathname, git_repository_workdir(repo), GIT_DIR_FLAG_UNKNOWN) < 0)
return -1;
if ((error = collect_attr_files(repo, attr_session, flags, pathname, &files)) < 0)
@@ -193,7 +193,7 @@ int git_attr_foreach(
assert(repo && callback);
- if (git_attr_path__init(&path, pathname, git_repository_workdir(repo)) < 0)
+ if (git_attr_path__init(&path, pathname, git_repository_workdir(repo), GIT_DIR_FLAG_UNKNOWN) < 0)
return -1;
if ((error = collect_attr_files(repo, NULL, flags, pathname, &files)) < 0 ||
diff --git a/src/attr_file.c b/src/attr_file.c
index eed39661f..ef98aacc2 100644
--- a/src/attr_file.c
+++ b/src/attr_file.c
@@ -457,7 +457,7 @@ git_attr_assignment *git_attr_rule__lookup_assignment(
}
int git_attr_path__init(
- git_attr_path *info, const char *path, const char *base)
+ git_attr_path *info, const char *path, const char *base, git_dir_flag dir_flag)
{
ssize_t root;
@@ -488,7 +488,21 @@ int git_attr_path__init(
if (!info->basename || !*info->basename)
info->basename = info->path;
- info->is_dir = (int)git_path_isdir(info->full.ptr);
+ switch (dir_flag)
+ {
+ case GIT_DIR_FLAG_FALSE:
+ info->is_dir = 0;
+ break;
+
+ case GIT_DIR_FLAG_TRUE:
+ info->is_dir = 1;
+ break;
+
+ case GIT_DIR_FLAG_UNKNOWN:
+ default:
+ info->is_dir = (int)git_path_isdir(info->full.ptr);
+ break;
+ }
return 0;
}
diff --git a/src/attr_file.h b/src/attr_file.h
index aa9a16de0..388ecf4c0 100644
--- a/src/attr_file.h
+++ b/src/attr_file.h
@@ -202,8 +202,10 @@ extern bool git_attr_rule__match(
extern git_attr_assignment *git_attr_rule__lookup_assignment(
git_attr_rule *rule, const char *name);
+typedef enum { GIT_DIR_FLAG_TRUE = 1, GIT_DIR_FLAG_FALSE = 0, GIT_DIR_FLAG_UNKNOWN = -1 } git_dir_flag;
+
extern int git_attr_path__init(
- git_attr_path *info, const char *path, const char *base);
+ git_attr_path *info, const char *path, const char *base, git_dir_flag is_dir);
extern void git_attr_path__free(git_attr_path *info);
diff --git a/src/ignore.c b/src/ignore.c
index 3a5efedce..7ad8500e8 100644
--- a/src/ignore.c
+++ b/src/ignore.c
@@ -388,7 +388,7 @@ static bool ignore_lookup_in_rules(
}
int git_ignore__lookup(
- int *out, git_ignores *ignores, const char *pathname)
+ int *out, git_ignores *ignores, const char *pathname, git_dir_flag dir_flag)
{
unsigned int i;
git_attr_file *file;
@@ -397,7 +397,7 @@ int git_ignore__lookup(
*out = GIT_IGNORE_NOTFOUND;
if (git_attr_path__init(
- &path, pathname, git_repository_workdir(ignores->repo)) < 0)
+ &path, pathname, git_repository_workdir(ignores->repo), dir_flag) < 0)
return -1;
/* first process builtins - success means path was found */
@@ -470,7 +470,7 @@ int git_ignore_path_is_ignored(
memset(&path, 0, sizeof(path));
memset(&ignores, 0, sizeof(ignores));
- if ((error = git_attr_path__init(&path, pathname, workdir)) < 0 ||
+ if ((error = git_attr_path__init(&path, pathname, workdir, GIT_DIR_FLAG_UNKNOWN)) < 0 ||
(error = git_ignore__for_path(repo, path.path, &ignores)) < 0)
goto cleanup;
diff --git a/src/ignore.h b/src/ignore.h
index 77668c661..d40bd60f9 100644
--- a/src/ignore.h
+++ b/src/ignore.h
@@ -49,7 +49,7 @@ enum {
GIT_IGNORE_TRUE = 1,
};
-extern int git_ignore__lookup(int *out, git_ignores *ign, const char *path);
+extern int git_ignore__lookup(int *out, git_ignores *ign, const char *path, git_dir_flag dir_flag);
/* command line Git sometimes generates an error message if given a
* pathspec that contains an exact match to an ignored file (provided
diff --git a/src/iterator.c b/src/iterator.c
index 9ddacebd1..8bab1aab0 100644
--- a/src/iterator.c
+++ b/src/iterator.c
@@ -1344,6 +1344,16 @@ static int is_submodule(workdir_iterator *wi, git_path_with_stat *ie)
return is_submodule;
}
+GIT_INLINE(git_dir_flag) git_entry__dir_flag(git_index_entry *entry) {
+#if defined(GIT_WIN32) && !defined(__MINGW32__)
+ return (entry && entry->mode)
+ ? S_ISDIR(entry->mode) ? GIT_DIR_FLAG_TRUE : GIT_DIR_FLAG_FALSE
+ : GIT_DIR_FLAG_UNKNOWN;
+#else
+ return GIT_DIR_FLAG_UNKNOWN;
+#endif
+}
+
static int workdir_iterator__enter_dir(fs_iterator *fi)
{
workdir_iterator *wi = (workdir_iterator *)fi;
@@ -1352,9 +1362,10 @@ static int workdir_iterator__enter_dir(fs_iterator *fi)
git_path_with_stat *entry;
bool found_submodules = false;
+ git_dir_flag dir_flag = git_entry__dir_flag(&fi->entry);
+
/* check if this directory is ignored */
- if (git_ignore__lookup(
- &ff->is_ignored, &wi->ignores, fi->path.ptr + fi->root_len) < 0) {
+ if (git_ignore__lookup(&ff->is_ignored, &wi->ignores, fi->path.ptr + fi->root_len, dir_flag) < 0) {
giterr_clear();
ff->is_ignored = GIT_IGNORE_NOTFOUND;
}
@@ -1483,7 +1494,6 @@ int git_iterator_for_workdir_ext(
return fs_iterator__initialize(out, &wi->fi, repo_workdir);
}
-
void git_iterator_free(git_iterator *iter)
{
if (iter == NULL)
@@ -1574,8 +1584,9 @@ int git_iterator_current_parent_tree(
static void workdir_iterator_update_is_ignored(workdir_iterator *wi)
{
- if (git_ignore__lookup(
- &wi->is_ignored, &wi->ignores, wi->fi.entry.path) < 0) {
+ git_dir_flag dir_flag = git_entry__dir_flag(&wi->fi.entry);
+
+ if (git_ignore__lookup(&wi->is_ignored, &wi->ignores, wi->fi.entry.path, dir_flag) < 0) {
giterr_clear();
wi->is_ignored = GIT_IGNORE_NOTFOUND;
}
diff --git a/tests/attr/lookup.c b/tests/attr/lookup.c
index 030ea075d..71e87cbae 100644
--- a/tests/attr/lookup.c
+++ b/tests/attr/lookup.c
@@ -13,7 +13,7 @@ void test_attr_lookup__simple(void)
cl_assert_equal_s(cl_fixture("attr/attr0"), file->entry->path);
cl_assert(file->rules.length == 1);
- cl_git_pass(git_attr_path__init(&path, "test", NULL));
+ cl_git_pass(git_attr_path__init(&path, "test", NULL, GIT_DIR_FLAG_UNKNOWN));
cl_assert_equal_s("test", path.path);
cl_assert_equal_s("test", path.basename);
cl_assert(!path.is_dir);
@@ -36,7 +36,7 @@ static void run_test_cases(git_attr_file *file, struct attr_expected *cases, int
int error;
for (c = cases; c->path != NULL; c++) {
- cl_git_pass(git_attr_path__init(&path, c->path, NULL));
+ cl_git_pass(git_attr_path__init(&path, c->path, NULL, GIT_DIR_FLAG_UNKNOWN));
if (force_dir)
path.is_dir = 1;
@@ -133,7 +133,7 @@ void test_attr_lookup__match_variants(void)
cl_assert_equal_s(cl_fixture("attr/attr1"), file->entry->path);
cl_assert(file->rules.length == 10);
- cl_git_pass(git_attr_path__init(&path, "/testing/for/pat0", NULL));
+ cl_git_pass(git_attr_path__init(&path, "/testing/for/pat0", NULL, GIT_DIR_FLAG_UNKNOWN));
cl_assert_equal_s("pat0", path.basename);
run_test_cases(file, cases, 0);