Commit 4c09e19a by J Wyman Committed by Edward Thomson

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.
parent d969d415
......@@ -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 ||
......
......@@ -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;
}
......
......@@ -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);
......
......@@ -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;
......
......@@ -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
......
......@@ -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;
}
......
......@@ -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);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment