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.
This commit is contained in:
J Wyman 2015-03-30 14:07:44 -07:00 committed by Edward Thomson
parent d969d41547
commit 4c09e19a37
7 changed files with 45 additions and 18 deletions

View File

@ -55,7 +55,7 @@ int git_attr_get(
*value = NULL; *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; return -1;
if ((error = collect_attr_files(repo, NULL, flags, pathname, &files)) < 0) 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); 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; return -1;
if ((error = collect_attr_files(repo, attr_session, flags, pathname, &files)) < 0) if ((error = collect_attr_files(repo, attr_session, flags, pathname, &files)) < 0)
@ -193,7 +193,7 @@ int git_attr_foreach(
assert(repo && callback); 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; return -1;
if ((error = collect_attr_files(repo, NULL, flags, pathname, &files)) < 0 || if ((error = collect_attr_files(repo, NULL, flags, pathname, &files)) < 0 ||

View File

@ -457,7 +457,7 @@ git_attr_assignment *git_attr_rule__lookup_assignment(
} }
int git_attr_path__init( 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; ssize_t root;
@ -488,7 +488,21 @@ int git_attr_path__init(
if (!info->basename || !*info->basename) if (!info->basename || !*info->basename)
info->basename = info->path; 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; return 0;
} }

View File

@ -202,8 +202,10 @@ extern bool git_attr_rule__match(
extern git_attr_assignment *git_attr_rule__lookup_assignment( extern git_attr_assignment *git_attr_rule__lookup_assignment(
git_attr_rule *rule, const char *name); 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( 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); extern void git_attr_path__free(git_attr_path *info);

View File

@ -388,7 +388,7 @@ static bool ignore_lookup_in_rules(
} }
int git_ignore__lookup( 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; unsigned int i;
git_attr_file *file; git_attr_file *file;
@ -397,7 +397,7 @@ int git_ignore__lookup(
*out = GIT_IGNORE_NOTFOUND; *out = GIT_IGNORE_NOTFOUND;
if (git_attr_path__init( 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; return -1;
/* first process builtins - success means path was found */ /* first process builtins - success means path was found */
@ -470,7 +470,7 @@ int git_ignore_path_is_ignored(
memset(&path, 0, sizeof(path)); memset(&path, 0, sizeof(path));
memset(&ignores, 0, sizeof(ignores)); 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) (error = git_ignore__for_path(repo, path.path, &ignores)) < 0)
goto cleanup; goto cleanup;

View File

@ -49,7 +49,7 @@ enum {
GIT_IGNORE_TRUE = 1, 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 /* command line Git sometimes generates an error message if given a
* pathspec that contains an exact match to an ignored file (provided * pathspec that contains an exact match to an ignored file (provided

View File

@ -1344,6 +1344,16 @@ static int is_submodule(workdir_iterator *wi, git_path_with_stat *ie)
return is_submodule; 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) static int workdir_iterator__enter_dir(fs_iterator *fi)
{ {
workdir_iterator *wi = (workdir_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; git_path_with_stat *entry;
bool found_submodules = false; bool found_submodules = false;
git_dir_flag dir_flag = git_entry__dir_flag(&fi->entry);
/* check if this directory is ignored */ /* check if this directory is ignored */
if (git_ignore__lookup( if (git_ignore__lookup(&ff->is_ignored, &wi->ignores, fi->path.ptr + fi->root_len, dir_flag) < 0) {
&ff->is_ignored, &wi->ignores, fi->path.ptr + fi->root_len) < 0) {
giterr_clear(); giterr_clear();
ff->is_ignored = GIT_IGNORE_NOTFOUND; 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); return fs_iterator__initialize(out, &wi->fi, repo_workdir);
} }
void git_iterator_free(git_iterator *iter) void git_iterator_free(git_iterator *iter)
{ {
if (iter == NULL) if (iter == NULL)
@ -1574,8 +1584,9 @@ int git_iterator_current_parent_tree(
static void workdir_iterator_update_is_ignored(workdir_iterator *wi) static void workdir_iterator_update_is_ignored(workdir_iterator *wi)
{ {
if (git_ignore__lookup( git_dir_flag dir_flag = git_entry__dir_flag(&wi->fi.entry);
&wi->is_ignored, &wi->ignores, wi->fi.entry.path) < 0) {
if (git_ignore__lookup(&wi->is_ignored, &wi->ignores, wi->fi.entry.path, dir_flag) < 0) {
giterr_clear(); giterr_clear();
wi->is_ignored = GIT_IGNORE_NOTFOUND; wi->is_ignored = GIT_IGNORE_NOTFOUND;
} }

View File

@ -13,7 +13,7 @@ void test_attr_lookup__simple(void)
cl_assert_equal_s(cl_fixture("attr/attr0"), file->entry->path); cl_assert_equal_s(cl_fixture("attr/attr0"), file->entry->path);
cl_assert(file->rules.length == 1); 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.path);
cl_assert_equal_s("test", path.basename); cl_assert_equal_s("test", path.basename);
cl_assert(!path.is_dir); 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; int error;
for (c = cases; c->path != NULL; c++) { 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) if (force_dir)
path.is_dir = 1; 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_equal_s(cl_fixture("attr/attr1"), file->entry->path);
cl_assert(file->rules.length == 10); 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); cl_assert_equal_s("pat0", path.basename);
run_test_cases(file, cases, 0); run_test_cases(file, cases, 0);