Subject: [PATCH v3 07/13] exclude: avoid calling prep_exclude on entries of the same directory

From: Nguyễn Thái Ngọc Duy <[email-masked]>
Date: Tue, 12 Mar 2013 20:04:54 +0700

prep_exclude is only necessary when we enter or leave a directory. Now
it's called for every entry in a directory. With this patch, the
number of prep_exclude calls in webkit.git goes from 188k down to
11k. This patch does not make exclude any faster, but it prepares for
making prep_exclude heavier in terms of computation, where a large
number of calls may have bigger impacts.

Signed-off-by: Nguyễn Thái Ngọc Duy <[email-masked]>
---
 dir.c | 10 +++++++++-
 dir.h |  1 +
 2 files changed, 10 insertions(+), 1 deletion(-)

diff --git a/dir.c b/dir.c
index 58739f3..f8f7a7e 100644
--- a/dir.c
+++ b/dir.c
@@ -804,7 +804,10 @@ static struct exclude *last_exclude_matching(struct dir_struct *dir,
 	basename = (basename) ? basename+1 : pathname;
 
 	START_CLOCK();
-	prep_exclude(dir, pathname, basename-pathname);
+	if (!dir->exclude_prepared) {
+		prep_exclude(dir, pathname, basename-pathname);
+		dir->exclude_prepared = 1;
+	}
 	STOP_CLOCK(tv_prep_exclude);
 
 	START_CLOCK();
@@ -894,6 +897,7 @@ struct exclude *last_exclude_matching_path(struct path_exclude_check *check,
 
 		if (ch == '/') {
 			int dt = DT_DIR;
+			check->dir->exclude_prepared = 0;
 			exclude = last_exclude_matching(check->dir,
 							path->buf, path->len,
 							&dt);
@@ -908,6 +912,7 @@ struct exclude *last_exclude_matching_path(struct path_exclude_check *check,
 	/* An entry in the index; cannot be a directory with subentries */
 	strbuf_setlen(path, 0);
 
+	check->dir->exclude_prepared = 0;
 	return last_exclude_matching(check->dir, name, namelen, dtype);
 }
 
@@ -1394,6 +1399,7 @@ static int read_directory_recursive(struct dir_struct *dir,
 	if (!fdir)
 		goto out;
 
+	dir->exclude_prepared = 0;
 	while ((de = readdir(fdir)) != NULL) {
 		switch (treat_path(dir, de, &path, baselen, simplify)) {
 		case path_recurse:
@@ -1415,6 +1421,7 @@ static int read_directory_recursive(struct dir_struct *dir,
 	}
 	closedir(fdir);
  out:
+	dir->exclude_prepared = 0;
 	strbuf_release(&path);
 
 	return contents;
@@ -1486,6 +1493,7 @@ static int treat_leading_path(struct dir_struct *dir,
 			break;
 		if (simplify_away(sb.buf, sb.len, simplify))
 			break;
+		dir->exclude_prepared = 0;
 		if (treat_one_path(dir, &sb, simplify,
 				   DT_DIR, NULL) == path_ignored)
 			break; /* do not recurse into it */
diff --git a/dir.h b/dir.h
index 560ade4..0748407 100644
--- a/dir.h
+++ b/dir.h
@@ -86,6 +86,7 @@ struct dir_struct {
 
 	/* Exclude info */
 	const char *exclude_per_dir;
+	int exclude_prepared;
 
 	/*
 	 * We maintain three groups of exclude pattern lists:
-- 
1.8.1.2.536.gf441e6d