Commit e28e17e6 by Patrick Steinhardt

attr: avoid stat'ting files for bare repositories

Depending on whether the path we want to look up an attribute for is a
file or a directory, the fnmatch function will be called with different
flags. Because of this, we have to first stat(3) the path to determine
whether it is a file or directory in `git_attr_path__init`. This is
wasteful though in bare repositories, where we can already be assured
that the path will never exist at all due to there being no worktree. In
this case, we will execute an unnecessary syscall, which might be
noticeable on networked file systems.

What happens right now is that we always pass the `GIT_DIR_FLAG_UNKOWN`
flag to `git_attr_path__init`, which causes it to `stat` the file itself
to determine its type. As it is calling `git_path_isdir` on the path,
which will always return `false` in case the path does not exist, we end
up with the path always being treated as a file in case of a bare
repository. As such, we can just check the bare-repository case in all
callers and then pass in `GIT_DIR_FLAG_FALSE` ourselves, avoiding the
need to `stat`. While this may not always be correct, it at least is no
different from our current behavior.
parent 71c43065
...@@ -56,12 +56,16 @@ int git_attr_get( ...@@ -56,12 +56,16 @@ int git_attr_get(
git_attr_file *file; git_attr_file *file;
git_attr_name attr; git_attr_name attr;
git_attr_rule *rule; git_attr_rule *rule;
git_dir_flag dir_flag = GIT_DIR_FLAG_UNKNOWN;
assert(value && repo && name); assert(value && repo && name);
*value = NULL; *value = NULL;
if (git_attr_path__init(&path, pathname, git_repository_workdir(repo), GIT_DIR_FLAG_UNKNOWN) < 0) if (git_repository_is_bare(repo))
dir_flag = GIT_DIR_FLAG_FALSE;
if (git_attr_path__init(&path, pathname, git_repository_workdir(repo), dir_flag) < 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,13 +118,17 @@ int git_attr_get_many_with_session( ...@@ -114,13 +118,17 @@ int git_attr_get_many_with_session(
git_attr_rule *rule; git_attr_rule *rule;
attr_get_many_info *info = NULL; attr_get_many_info *info = NULL;
size_t num_found = 0; size_t num_found = 0;
git_dir_flag dir_flag = GIT_DIR_FLAG_UNKNOWN;
if (!num_attr) if (!num_attr)
return 0; return 0;
assert(values && repo && names); assert(values && repo && names);
if (git_attr_path__init(&path, pathname, git_repository_workdir(repo), GIT_DIR_FLAG_UNKNOWN) < 0) if (git_repository_is_bare(repo))
dir_flag = GIT_DIR_FLAG_FALSE;
if (git_attr_path__init(&path, pathname, git_repository_workdir(repo), dir_flag) < 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)
...@@ -196,10 +204,14 @@ int git_attr_foreach( ...@@ -196,10 +204,14 @@ int git_attr_foreach(
git_attr_rule *rule; git_attr_rule *rule;
git_attr_assignment *assign; git_attr_assignment *assign;
git_strmap *seen = NULL; git_strmap *seen = NULL;
git_dir_flag dir_flag = GIT_DIR_FLAG_UNKNOWN;
assert(repo && callback); assert(repo && callback);
if (git_attr_path__init(&path, pathname, git_repository_workdir(repo), GIT_DIR_FLAG_UNKNOWN) < 0) if (git_repository_is_bare(repo))
dir_flag = GIT_DIR_FLAG_FALSE;
if (git_attr_path__init(&path, pathname, git_repository_workdir(repo), dir_flag) < 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 ||
......
...@@ -540,6 +540,7 @@ int git_ignore_path_is_ignored( ...@@ -540,6 +540,7 @@ int git_ignore_path_is_ignored(
git_ignores ignores; git_ignores ignores;
unsigned int i; unsigned int i;
git_attr_file *file; git_attr_file *file;
git_dir_flag dir_flag = GIT_DIR_FLAG_UNKNOWN;
assert(repo && ignored && pathname); assert(repo && ignored && pathname);
...@@ -548,7 +549,10 @@ int git_ignore_path_is_ignored( ...@@ -548,7 +549,10 @@ 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, GIT_DIR_FLAG_UNKNOWN)) < 0 || if (git_repository_is_bare(repo))
dir_flag = GIT_DIR_FLAG_FALSE;
if ((error = git_attr_path__init(&path, pathname, workdir, dir_flag)) < 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;
......
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