refs.c: remove extra git_path calls from read_loose_refs
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>
This commit is contained in:
parent
b21a5d6605
commit
f5b2dec165
23
refs.c
23
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;
|
||||
const char *path;
|
||||
struct dirent *de;
|
||||
int dirnamelen = strlen(dirname);
|
||||
struct strbuf refname;
|
||||
struct strbuf path = STRBUF_INIT;
|
||||
size_t path_baselen;
|
||||
|
||||
if (*refs->name)
|
||||
path = git_path_submodule(refs->name, "%s", dirname);
|
||||
strbuf_git_path_submodule(&path, refs->name, "%s", dirname);
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
const char *refdir;
|
||||
|
||||
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, '/');
|
||||
@ -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);
|
||||
strbuf_setlen(&path, path_baselen);
|
||||
}
|
||||
strbuf_release(&refname);
|
||||
strbuf_release(&path);
|
||||
closedir(d);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user