Skip to content

Commit

Permalink
Speedup scanning for excluded files.
Browse files Browse the repository at this point in the history
Try to avoid a lot of work scanning for excluded files,
by caching some more information when setting up the exclusion
data structure.

Speeds up 'git runstatus' on a repository containing the Qt sources by 30% and
reduces the amount of instructions executed (as measured by valgrind) by a
factor of 2.

Signed-off-by: Junio C Hamano <gitster@pobox.com>
  • Loading branch information
Lars Knoll authored and gitster committed Oct 30, 2007
1 parent 79f3368 commit 68492fc
Show file tree
Hide file tree
Showing 2 changed files with 50 additions and 16 deletions.
59 changes: 43 additions & 16 deletions dir.c
Expand Up @@ -118,14 +118,32 @@ int match_pathspec(const char **pathspec, const char *name, int namelen, int pre
return retval;
}

static int no_wildcard(const char *string)
{
return string[strcspn(string, "*?[{")] == '\0';
}

void add_exclude(const char *string, const char *base,
int baselen, struct exclude_list *which)
{
struct exclude *x = xmalloc(sizeof (*x));

x->to_exclude = 1;
if (*string == '!') {
x->to_exclude = 0;
string++;
}
x->pattern = string;
x->patternlen = strlen(string);
x->base = base;
x->baselen = baselen;
x->flags = 0;
if (!strchr(string, '/'))
x->flags |= EXC_FLAG_NODIR;
if (no_wildcard(string))
x->flags |= EXC_FLAG_NOWILDCARD;
if (*string == '*' && no_wildcard(string+1))
x->flags |= EXC_FLAG_ENDSWITH;
if (which->nr == which->alloc) {
which->alloc = alloc_nr(which->alloc);
which->excludes = xrealloc(which->excludes,
Expand Down Expand Up @@ -209,7 +227,7 @@ void pop_exclude_per_directory(struct dir_struct *dir, int stk)
* Return 1 for exclude, 0 for include and -1 for undecided.
*/
static int excluded_1(const char *pathname,
int pathlen,
int pathlen, const char *basename,
struct exclude_list *el)
{
int i;
Expand All @@ -218,19 +236,21 @@ static int excluded_1(const char *pathname,
for (i = el->nr - 1; 0 <= i; i--) {
struct exclude *x = el->excludes[i];
const char *exclude = x->pattern;
int to_exclude = 1;
int to_exclude = x->to_exclude;

if (*exclude == '!') {
to_exclude = 0;
exclude++;
}

if (!strchr(exclude, '/')) {
if (x->flags & EXC_FLAG_NODIR) {
/* match basename */
const char *basename = strrchr(pathname, '/');
basename = (basename) ? basename+1 : pathname;
if (fnmatch(exclude, basename, 0) == 0)
return to_exclude;
if (x->flags & EXC_FLAG_NOWILDCARD) {
if (!strcmp(exclude, basename))
return to_exclude;
} else if (x->flags & EXC_FLAG_ENDSWITH) {
if (x->patternlen - 1 <= pathlen &&
!strcmp(exclude + 1, pathname + pathlen - x->patternlen + 1))
return to_exclude;
} else {
if (fnmatch(exclude, basename, 0) == 0)
return to_exclude;
}
}
else {
/* match with FNM_PATHNAME:
Expand All @@ -246,9 +266,14 @@ static int excluded_1(const char *pathname,
strncmp(pathname, x->base, baselen))
continue;

if (fnmatch(exclude, pathname+baselen,
FNM_PATHNAME) == 0)
return to_exclude;
if (x->flags & EXC_FLAG_NOWILDCARD) {
if (!strcmp(exclude, pathname + baselen))
return to_exclude;
} else {
if (fnmatch(exclude, pathname+baselen,
FNM_PATHNAME) == 0)
return to_exclude;
}
}
}
}
Expand All @@ -259,9 +284,11 @@ int excluded(struct dir_struct *dir, const char *pathname)
{
int pathlen = strlen(pathname);
int st;
const char *basename = strrchr(pathname, '/');
basename = (basename) ? basename+1 : pathname;

for (st = EXC_CMDL; st <= EXC_FILE; st++) {
switch (excluded_1(pathname, pathlen, &dir->exclude_list[st])) {
switch (excluded_1(pathname, pathlen, basename, &dir->exclude_list[st])) {
case 0:
return 0;
case 1:
Expand Down
7 changes: 7 additions & 0 deletions dir.h
Expand Up @@ -17,13 +17,20 @@ struct dir_entry {
char name[FLEX_ARRAY]; /* more */
};

#define EXC_FLAG_NODIR 1
#define EXC_FLAG_NOWILDCARD 2
#define EXC_FLAG_ENDSWITH 4

struct exclude_list {
int nr;
int alloc;
struct exclude {
const char *pattern;
int patternlen;
const char *base;
int baselen;
int to_exclude;
int flags;
} **excludes;
};

Expand Down

0 comments on commit 68492fc

Please sign in to comment.