Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
do_compare_entry: use already-computed path
In traverse_trees, we generate the complete traverse path for a
traverse_info.  Later, in do_compare_entry, we used to go do a bunch
of work to compare the traverse_info to a cache_entry's name without
computing that path.  But since we already have that path, we don't
need to do all that work.  Instead, we can just put the generated
path into the traverse_info, and do the comparison more directly.

We copy the path because prune_traversal might mutate `base`. This
doesn't happen in any codepaths where do_compare_entry is called,
but it's better to be safe.

This makes git checkout much faster -- about 25% on Twitter's
monorepo.  Deeper directory trees are likely to benefit more than
shallower ones.

Signed-off-by: David Turner <dturner@twopensource.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
  • Loading branch information
David Turner authored and Junio C Hamano committed Jan 5, 2016
1 parent f3adf45 commit d9c2bd5
Show file tree
Hide file tree
Showing 3 changed files with 44 additions and 2 deletions.
7 changes: 7 additions & 0 deletions tree-walk.c
Expand Up @@ -320,6 +320,7 @@ int traverse_trees(int n, struct tree_desc *t, struct traverse_info *info)
struct tree_desc_x *tx = xcalloc(n, sizeof(*tx));
struct strbuf base = STRBUF_INIT;
int interesting = 1;
char *traverse_path;

for (i = 0; i < n; i++)
tx[i].d = t[i];
Expand All @@ -329,7 +330,11 @@ int traverse_trees(int n, struct tree_desc *t, struct traverse_info *info)
make_traverse_path(base.buf, info->prev, &info->name);
base.buf[info->pathlen-1] = '/';
strbuf_setlen(&base, info->pathlen);
traverse_path = xstrndup(base.buf, info->pathlen);
} else {
traverse_path = xstrndup(info->name.path, info->pathlen);
}
info->traverse_path = traverse_path;
for (;;) {
int trees_used;
unsigned long mask, dirmask;
Expand Down Expand Up @@ -411,6 +416,8 @@ int traverse_trees(int n, struct tree_desc *t, struct traverse_info *info)
for (i = 0; i < n; i++)
free_extended_entry(tx + i);
free(tx);
free(traverse_path);
info->traverse_path = NULL;
strbuf_release(&base);
return error;
}
Expand Down
1 change: 1 addition & 0 deletions tree-walk.h
Expand Up @@ -59,6 +59,7 @@ enum follow_symlinks_result {
enum follow_symlinks_result get_tree_entry_follow_symlinks(unsigned char *tree_sha1, const char *name, unsigned char *result, struct strbuf *result_path, unsigned *mode);

struct traverse_info {
const char *traverse_path;
struct traverse_info *prev;
struct name_entry name;
int pathlen;
Expand Down
38 changes: 36 additions & 2 deletions unpack-trees.c
Expand Up @@ -498,13 +498,14 @@ static int traverse_trees_recursive(int n, unsigned long dirmask,
* itself - the caller needs to do the final check for the cache
* entry having more data at the end!
*/
static int do_compare_entry(const struct cache_entry *ce, const struct traverse_info *info, const struct name_entry *n)
static int do_compare_entry_piecewise(const struct cache_entry *ce, const struct traverse_info *info, const struct name_entry *n)
{
int len, pathlen, ce_len;
const char *ce_name;

if (info->prev) {
int cmp = do_compare_entry(ce, info->prev, &info->name);
int cmp = do_compare_entry_piecewise(ce, info->prev,
&info->name);
if (cmp)
return cmp;
}
Expand All @@ -522,6 +523,39 @@ static int do_compare_entry(const struct cache_entry *ce, const struct traverse_
return df_name_compare(ce_name, ce_len, S_IFREG, n->path, len, n->mode);
}

static int do_compare_entry(const struct cache_entry *ce,
const struct traverse_info *info,
const struct name_entry *n)
{
int len, pathlen, ce_len;
const char *ce_name;
int cmp;

/*
* If we have not precomputed the traverse path, it is quicker
* to avoid doing so. But if we have precomputed it,
* it is quicker to use the precomputed version.
*/
if (!info->traverse_path)
return do_compare_entry_piecewise(ce, info, n);

cmp = strncmp(ce->name, info->traverse_path, info->pathlen);
if (cmp)
return cmp;

pathlen = info->pathlen;
ce_len = ce_namelen(ce);

if (ce_len < pathlen)
return -1;

ce_len -= pathlen;
ce_name = ce->name + pathlen;

len = tree_entry_len(n);
return df_name_compare(ce_name, ce_len, S_IFREG, n->path, len, n->mode);
}

static int compare_entry(const struct cache_entry *ce, const struct traverse_info *info, const struct name_entry *n)
{
int cmp = do_compare_entry(ce, info, n);
Expand Down

0 comments on commit d9c2bd5

Please sign in to comment.