git.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: "Nguyễn Thái Ngọc Duy" <pclouds@gmail.com>
To: git@vger.kernel.org
Cc: "Nguyễn Thái Ngọc Duy" <pclouds@gmail.com>,
	"Junio C Hamano" <gitster@pobox.com>
Subject: [PATCH 03/24] untracked cache: initial untracked cache validation
Date: Sun,  8 Mar 2015 17:12:26 +0700	[thread overview]
Message-ID: <1425809567-25518-4-git-send-email-pclouds@gmail.com> (raw)
In-Reply-To: <1425809567-25518-1-git-send-email-pclouds@gmail.com>

Make sure the starting conditions and all global exclude files are
good to go. If not, either disable untracked cache completely, or wipe
out the cache and start fresh.

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
---
 dir.c | 113 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
 dir.h |   4 +++
 2 files changed, 114 insertions(+), 3 deletions(-)

diff --git a/dir.c b/dir.c
index e05a6ba..b1c5faa 100644
--- a/dir.c
+++ b/dir.c
@@ -582,6 +582,22 @@ static struct untracked_cache_dir *lookup_untracked(struct untracked_cache *uc,
 	return d;
 }
 
+static void do_invalidate_gitignore(struct untracked_cache_dir *dir)
+{
+	int i;
+	dir->valid = 0;
+	dir->untracked_nr = 0;
+	for (i = 0; i < dir->dirs_nr; i++)
+		do_invalidate_gitignore(dir->dirs[i]);
+}
+
+static void invalidate_gitignore(struct untracked_cache *uc,
+				 struct untracked_cache_dir *dir)
+{
+	uc->gitignore_invalidated++;
+	do_invalidate_gitignore(dir);
+}
+
 /*
  * Given a file with name "fname", read it (either from disk, or from
  * the index if "check_index" is non-zero), parse it and store the
@@ -698,6 +714,13 @@ static void add_excludes_from_file_1(struct dir_struct *dir, const char *fname,
 				     struct sha1_stat *sha1_stat)
 {
 	struct exclude_list *el;
+	/*
+	 * catch setup_standard_excludes() that's called before
+	 * dir->untracked is assigned. That function behaves
+	 * differently when dir->untracked is non-NULL.
+	 */
+	if (!dir->untracked)
+		dir->unmanaged_exclude_files++;
 	el = add_exclude_list(dir, EXC_FILE, fname);
 	if (add_excludes(fname, "", 0, el, 0, sha1_stat) < 0)
 		die("cannot use %s as an exclude file", fname);
@@ -705,6 +728,7 @@ static void add_excludes_from_file_1(struct dir_struct *dir, const char *fname,
 
 void add_excludes_from_file(struct dir_struct *dir, const char *fname)
 {
+	dir->unmanaged_exclude_files++; /* see validate_untracked_cache() */
 	add_excludes_from_file_1(dir, fname, NULL);
 }
 
@@ -1573,9 +1597,87 @@ static int treat_leading_path(struct dir_struct *dir,
 	return rc;
 }
 
+static struct untracked_cache_dir *validate_untracked_cache(struct dir_struct *dir,
+						      int base_len,
+						      const struct pathspec *pathspec)
+{
+	struct untracked_cache_dir *root;
+
+	if (!dir->untracked)
+		return NULL;
+
+	/*
+	 * We only support $GIT_DIR/info/exclude and core.excludesfile
+	 * as the global ignore rule files. Any other additions
+	 * (e.g. from command line) invalidate the cache. This
+	 * condition also catches running setup_standard_excludes()
+	 * before setting dir->untracked!
+	 */
+	if (dir->unmanaged_exclude_files)
+		return NULL;
+
+	/*
+	 * Optimize for the main use case only: whole-tree git
+	 * status. More work involved in treat_leading_path() if we
+	 * use cache on just a subset of the worktree. pathspec
+	 * support could make the matter even worse.
+	 */
+	if (base_len || (pathspec && pathspec->nr))
+		return NULL;
+
+	/* Different set of flags may produce different results */
+	if (dir->flags != dir->untracked->dir_flags ||
+	    /*
+	     * See treat_directory(), case index_nonexistent. Without
+	     * this flag, we may need to also cache .git file content
+	     * for the resolve_gitlink_ref() call, which we don't.
+	     */
+	    !(dir->flags & DIR_SHOW_OTHER_DIRECTORIES) ||
+	    /* We don't support collecting ignore files */
+	    (dir->flags & (DIR_SHOW_IGNORED | DIR_SHOW_IGNORED_TOO |
+			   DIR_COLLECT_IGNORED)))
+		return NULL;
+
+	/*
+	 * If we use .gitignore in the cache and now you change it to
+	 * .gitexclude, everything will go wrong.
+	 */
+	if (dir->exclude_per_dir != dir->untracked->exclude_per_dir &&
+	    strcmp(dir->exclude_per_dir, dir->untracked->exclude_per_dir))
+		return NULL;
+
+	/*
+	 * EXC_CMDL is not considered in the cache. If people set it,
+	 * skip the cache.
+	 */
+	if (dir->exclude_list_group[EXC_CMDL].nr)
+		return NULL;
+
+	if (!dir->untracked->root) {
+		const int len = sizeof(*dir->untracked->root);
+		dir->untracked->root = xmalloc(len);
+		memset(dir->untracked->root, 0, len);
+	}
+
+	/* Validate $GIT_DIR/info/exclude and core.excludesfile */
+	root = dir->untracked->root;
+	if (hashcmp(dir->ss_info_exclude.sha1,
+		    dir->untracked->ss_info_exclude.sha1)) {
+		invalidate_gitignore(dir->untracked, root);
+		dir->untracked->ss_info_exclude = dir->ss_info_exclude;
+	}
+	if (hashcmp(dir->ss_excludes_file.sha1,
+		    dir->untracked->ss_excludes_file.sha1)) {
+		invalidate_gitignore(dir->untracked, root);
+		dir->untracked->ss_excludes_file = dir->ss_excludes_file;
+	}
+	return root;
+}
+
 int read_directory(struct dir_struct *dir, const char *path, int len, const struct pathspec *pathspec)
 {
 	struct path_simplify *simplify;
+	struct untracked_cache_dir *untracked;
 
 	/*
 	 * Check out create_simplify()
@@ -1599,10 +1701,15 @@ int read_directory(struct dir_struct *dir, const char *path, int len, const stru
 	 * create_simplify().
 	 */
 	simplify = create_simplify(pathspec ? pathspec->_raw : NULL);
+	untracked = validate_untracked_cache(dir, len, pathspec);
+	if (!untracked)
+		/*
+		 * make sure untracked cache code path is disabled,
+		 * e.g. prep_exclude()
+		 */
+		dir->untracked = NULL;
 	if (!len || treat_leading_path(dir, path, len, simplify))
-		read_directory_recursive(dir, path, len,
-					 dir->untracked ? dir->untracked->root : NULL,
-					 0, simplify);
+		read_directory_recursive(dir, path, len, untracked, 0, simplify);
 	free_simplify(simplify);
 	qsort(dir->entries, dir->nr, sizeof(struct dir_entry *), cmp_name);
 	qsort(dir->ignored, dir->ignored_nr, sizeof(struct dir_entry *), cmp_name);
diff --git a/dir.h b/dir.h
index 9ab74b4..1d7a958 100644
--- a/dir.h
+++ b/dir.h
@@ -115,6 +115,8 @@ struct untracked_cache_dir {
 	unsigned int untracked_alloc, dirs_nr, dirs_alloc;
 	unsigned int untracked_nr;
 	unsigned int check_only : 1;
+	/* all data in this struct are good */
+	unsigned int valid : 1;
 	/* null SHA-1 means this directory does not have .gitignore */
 	unsigned char exclude_sha1[20];
 	char name[FLEX_ARRAY];
@@ -132,6 +134,7 @@ struct untracked_cache {
 	struct untracked_cache_dir *root;
 	/* Statistics */
 	int dir_created;
+	int gitignore_invalidated;
 };
 
 struct dir_struct {
@@ -186,6 +189,7 @@ struct dir_struct {
 	struct untracked_cache *untracked;
 	struct sha1_stat ss_info_exclude;
 	struct sha1_stat ss_excludes_file;
+	unsigned unmanaged_exclude_files;
 };
 
 /*
-- 
2.3.0.rc1.137.g477eb31

  parent reply	other threads:[~2015-03-08 10:13 UTC|newest]

Thread overview: 27+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2015-03-08 10:12 [PATCH 00/24] nd/untracked-cache updates Nguyễn Thái Ngọc Duy
2015-03-08 10:12 ` [PATCH 01/24] dir.c: optionally compute sha-1 of a .gitignore file Nguyễn Thái Ngọc Duy
2015-03-08 10:12 ` [PATCH 02/24] untracked cache: record .gitignore information and dir hierarchy Nguyễn Thái Ngọc Duy
2015-03-08 10:12 ` Nguyễn Thái Ngọc Duy [this message]
2015-03-08 10:12 ` [PATCH 04/24] untracked cache: invalidate dirs recursively if .gitignore changes Nguyễn Thái Ngọc Duy
2015-03-08 10:12 ` [PATCH 05/24] untracked cache: make a wrapper around {open,read,close}dir() Nguyễn Thái Ngọc Duy
2015-03-08 10:12 ` [PATCH 06/24] untracked cache: record/validate dir mtime and reuse cached output Nguyễn Thái Ngọc Duy
2015-03-08 10:12 ` [PATCH 07/24] untracked cache: mark what dirs should be recursed/saved Nguyễn Thái Ngọc Duy
2015-03-08 10:12 ` [PATCH 08/24] untracked cache: don't open non-existent .gitignore Nguyễn Thái Ngọc Duy
2015-03-08 10:12 ` [PATCH 09/24] ewah: add convenient wrapper ewah_serialize_strbuf() Nguyễn Thái Ngọc Duy
2015-03-08 10:12 ` [PATCH 10/24] untracked cache: save to an index extension Nguyễn Thái Ngọc Duy
2015-03-08 10:12 ` [PATCH 11/24] untracked cache: load from UNTR " Nguyễn Thái Ngọc Duy
2015-03-08 10:12 ` [PATCH 12/24] untracked cache: invalidate at index addition or removal Nguyễn Thái Ngọc Duy
2015-03-08 10:12 ` [PATCH 13/24] read-cache.c: split racy stat test to a separate function Nguyễn Thái Ngọc Duy
2015-03-08 10:12 ` [PATCH 14/24] untracked cache: avoid racy timestamps Nguyễn Thái Ngọc Duy
2015-03-08 10:12 ` [PATCH 15/24] untracked cache: print stats with $GIT_TRACE_UNTRACKED_STATS Nguyễn Thái Ngọc Duy
2015-03-08 10:12 ` [PATCH 16/24] untracked cache: mark index dirty if untracked cache is updated Nguyễn Thái Ngọc Duy
2015-03-08 10:12 ` [PATCH 17/24] untracked-cache: temporarily disable with $GIT_DISABLE_UNTRACKED_CACHE Nguyễn Thái Ngọc Duy
2015-03-08 10:12 ` [PATCH 18/24] status: enable untracked cache Nguyễn Thái Ngọc Duy
2015-03-08 10:12 ` [PATCH 19/24] update-index: manually enable or disable " Nguyễn Thái Ngọc Duy
2015-03-08 10:12 ` [PATCH 20/24] update-index: test the system before enabling " Nguyễn Thái Ngọc Duy
2015-03-08 10:12 ` [PATCH 21/24] t7063: tests for " Nguyễn Thái Ngọc Duy
2015-03-08 10:12 ` [PATCH 22/24] mingw32: add uname() Nguyễn Thái Ngọc Duy
2015-03-08 10:12 ` [PATCH 23/24] untracked cache: guard and disable on system changes Nguyễn Thái Ngọc Duy
2015-03-08 10:12 ` [PATCH 24/24] git-status.txt: advertisement for untracked cache Nguyễn Thái Ngọc Duy
  -- strict thread matches above, loose matches on Subject: below --
2015-02-08  8:55 [PATCH 00/24] nd/untracked-cache updates Nguyễn Thái Ngọc Duy
2015-02-08  8:55 ` [PATCH 03/24] untracked cache: initial untracked cache validation Nguyễn Thái Ngọc Duy
2015-01-20 13:03 [PATCH 00/24] nd/untracked-cache update Nguyễn Thái Ngọc Duy
2015-01-20 13:03 ` [PATCH 03/24] untracked cache: initial untracked cache validation Nguyễn Thái Ngọc Duy

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1425809567-25518-4-git-send-email-pclouds@gmail.com \
    --to=pclouds@gmail.com \
    --cc=git@vger.kernel.org \
    --cc=gitster@pobox.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).