Skip to content

Commit

Permalink
Improvements to ignore performance on Windows.
Browse files Browse the repository at this point in the history
Minimizing the number directory and file opens, minimizes the amount of IO thus reducing the overall cost of performing ignore operations.
  • Loading branch information
J Wyman authored and Edward Thomson committed Apr 28, 2015
1 parent d969d41 commit 4c09e19
Show file tree
Hide file tree
Showing 7 changed files with 45 additions and 18 deletions.
6 changes: 3 additions & 3 deletions src/attr.c
Expand Up @@ -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)
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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 ||
Expand Down
18 changes: 16 additions & 2 deletions src/attr_file.c
Expand Up @@ -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;

Expand Down Expand Up @@ -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;
}
Expand Down
4 changes: 3 additions & 1 deletion src/attr_file.h
Expand Up @@ -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);

Expand Down
6 changes: 3 additions & 3 deletions src/ignore.c
Expand Up @@ -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;
Expand All @@ -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 */
Expand Down Expand Up @@ -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;

Expand Down
2 changes: 1 addition & 1 deletion src/ignore.h
Expand Up @@ -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
Expand Down
21 changes: 16 additions & 5 deletions src/iterator.c
Expand Up @@ -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;
Expand All @@ -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;
}
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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;
}
Expand Down
6 changes: 3 additions & 3 deletions tests/attr/lookup.c
Expand Up @@ -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);
Expand All @@ -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;
Expand Down Expand Up @@ -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);
Expand Down

0 comments on commit 4c09e19

Please sign in to comment.