refs.c: remove extra git_path calls from read_loose_refs
authorJeff King <peff@peff.net>
Mon, 10 Aug 2015 09:36:19 +0000 (05:36 -0400)
committerJunio C Hamano <gitster@pobox.com>
Mon, 10 Aug 2015 22:37:13 +0000 (15:37 -0700)
In iterating over the loose refs in "refs/foo/", we keep a
running strbuf with "refs/foo/one", "refs/foo/two", etc. But
we also need to access these files in the filesystem, as
".git/refs/foo/one", etc. For this latter purpose, we make a
series of independent calls to git_path(). These are safe
(we only use the result to call stat()), but assigning the
result of git_path is a suspicious pattern that we'd rather
avoid.

This patch keeps a running buffer with ".git/refs/foo/", and
we can just append/reset each directory element as we loop.
This matches how we handle the refnames. It should also be
more efficient, as we do not keep formatting the same
".git/refs/foo" prefix (which can be arbitrarily deep).

Technically we are dropping a call to strbuf_cleanup() on
each generated filename, but that's OK; it wasn't doing
anything, as we are putting in single-level names we read
from the filesystem (so it could not possibly be cleaning up
cruft like "./" in this instance).

A clever reader may also note that the running refname
buffer ("refs/foo/") is actually a subset of the filesystem
path buffer (".git/refs/foo/"). We could get by with one
buffer, indexing the length of $GIT_DIR when we want the
refname. However, having tried this, the resulting code
actually ends up a little more confusing, and the efficiency
improvement is tiny (and almost certainly dwarfed by the
system calls we are making).

Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
refs.c
diff --git a/refs.c b/refs.c
index e70941a090b96fd04e2f9f68d422fd0b7e0cd7d9..06f95c4c12666e40ef5b5dfff72c211a823367e7 100644 (file)
--- a/refs.c
+++ b/refs.c
@@ -1352,19 +1352,23 @@ static void read_loose_refs(const char *dirname, struct ref_dir *dir)
 {
        struct ref_cache *refs = dir->ref_cache;
        DIR *d;
 {
        struct ref_cache *refs = dir->ref_cache;
        DIR *d;
-       const char *path;
        struct dirent *de;
        int dirnamelen = strlen(dirname);
        struct strbuf refname;
        struct dirent *de;
        int dirnamelen = strlen(dirname);
        struct strbuf refname;
+       struct strbuf path = STRBUF_INIT;
+       size_t path_baselen;
 
        if (*refs->name)
 
        if (*refs->name)
-               path = git_path_submodule(refs->name, "%s", dirname);
+               strbuf_git_path_submodule(&path, refs->name, "%s", dirname);
        else
        else
-               path = git_path("%s", dirname);
+               strbuf_git_path(&path, "%s", dirname);
+       path_baselen = path.len;
 
 
-       d = opendir(path);
-       if (!d)
+       d = opendir(path.buf);
+       if (!d) {
+               strbuf_release(&path);
                return;
                return;
+       }
 
        strbuf_init(&refname, dirnamelen + 257);
        strbuf_add(&refname, dirname, dirnamelen);
 
        strbuf_init(&refname, dirnamelen + 257);
        strbuf_add(&refname, dirname, dirnamelen);
@@ -1373,17 +1377,14 @@ static void read_loose_refs(const char *dirname, struct ref_dir *dir)
                unsigned char sha1[20];
                struct stat st;
                int flag;
                unsigned char sha1[20];
                struct stat st;
                int flag;
-               const char *refdir;
 
                if (de->d_name[0] == '.')
                        continue;
                if (ends_with(de->d_name, ".lock"))
                        continue;
                strbuf_addstr(&refname, de->d_name);
 
                if (de->d_name[0] == '.')
                        continue;
                if (ends_with(de->d_name, ".lock"))
                        continue;
                strbuf_addstr(&refname, de->d_name);
-               refdir = *refs->name
-                       ? git_path_submodule(refs->name, "%s", refname.buf)
-                       : git_path("%s", refname.buf);
-               if (stat(refdir, &st) < 0) {
+               strbuf_addstr(&path, de->d_name);
+               if (stat(path.buf, &st) < 0) {
                        ; /* silently ignore */
                } else if (S_ISDIR(st.st_mode)) {
                        strbuf_addch(&refname, '/');
                        ; /* silently ignore */
                } else if (S_ISDIR(st.st_mode)) {
                        strbuf_addch(&refname, '/');
@@ -1430,8 +1431,10 @@ static void read_loose_refs(const char *dirname, struct ref_dir *dir)
                                         create_ref_entry(refname.buf, sha1, flag, 0));
                }
                strbuf_setlen(&refname, dirnamelen);
                                         create_ref_entry(refname.buf, sha1, flag, 0));
                }
                strbuf_setlen(&refname, dirnamelen);
+               strbuf_setlen(&path, path_baselen);
        }
        strbuf_release(&refname);
        }
        strbuf_release(&refname);
+       strbuf_release(&path);
        closedir(d);
 }
 
        closedir(d);
 }