From mboxrd@z Thu Jan 1 00:00:00 1970 From: =?UTF-8?q?Nguy=E1=BB=85n=20Th=C3=A1i=20Ng=E1=BB=8Dc=20Duy?= Subject: [PATCH 03/24] untracked cache: initial untracked cache validation Date: Tue, 20 Jan 2015 20:03:12 +0700 Message-ID: <1421759013-8494-4-git-send-email-pclouds@gmail.com> References: <1421759013-8494-1-git-send-email-pclouds@gmail.com> Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: QUOTED-PRINTABLE Cc: =?UTF-8?q?Nguy=E1=BB=85n=20Th=C3=A1i=20Ng=E1=BB=8Dc=20Duy?= , Junio C Hamano To: git@vger.kernel.org X-From: git-owner@vger.kernel.org Tue Jan 20 14:03:54 2015 Return-path: Envelope-to: gcvg-git-2@plane.gmane.org Received: from vger.kernel.org ([209.132.180.67]) by plane.gmane.org with esmtp (Exim 4.69) (envelope-from ) id 1YDYTJ-0003JK-R2 for gcvg-git-2@plane.gmane.org; Tue, 20 Jan 2015 14:03:54 +0100 Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1754080AbbATNDt convert rfc822-to-quoted-printable (ORCPT ); Tue, 20 Jan 2015 08:03:49 -0500 Received: from mail-pa0-f43.google.com ([209.85.220.43]:41224 "EHLO mail-pa0-f43.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753389AbbATNDt (ORCPT ); Tue, 20 Jan 2015 08:03:49 -0500 Received: by mail-pa0-f43.google.com with SMTP id eu11so8258767pac.2 for ; Tue, 20 Jan 2015 05:03:48 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-type:content-transfer-encoding; bh=+1UlEhwPEFPflvDm0dmZiH0ypEQPOobeAr4+UWlzAKg=; b=YyTz+cB7WLijgjl2TkMckO9sdwxU1RkOJUYT6xCPbEtwksm1hh2fWPEhBXcP97ONpD J/6Odu06m04C8vvVepmgc/KMSpWq38AA1PKVpp8J43RLwa2fKwZnVlSdKTozQYgiAvOt JwuQ5FTufDPod0WW+rmiKMmavbT2O3kam4LnASWvJOGuSQvx9QQjGA6B0HhvxcJOZtc9 WfLuJz4dKKVldOPNMd0CL3lnEFoRHz/p63Uubgh8CY+zx2Q3UuaT6OhjV0ZdjhwTTaPK q9REfGYuk95lbIttyc3S5jZcZses/xXlvXu1l63qoK/BoxWboJcoTeOhk55iaHDZ7PEA fzYw== X-Received: by 10.68.197.72 with SMTP id is8mr53592849pbc.17.1421759028504; Tue, 20 Jan 2015 05:03:48 -0800 (PST) Received: from lanh ([115.73.212.1]) by mx.google.com with ESMTPSA id xl12sm3221142pac.41.2015.01.20.05.03.44 (version=TLSv1.2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Tue, 20 Jan 2015 05:03:47 -0800 (PST) Received: by lanh (sSMTP sendmail emulation); Tue, 20 Jan 2015 20:03:57 +0700 X-Mailer: git-send-email 2.2.0.84.ge9c7a8a In-Reply-To: <1421759013-8494-1-git-send-email-pclouds@gmail.com> Sender: git-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org Archived-At: 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=E1=BB=85n Th=C3=A1i Ng=E1=BB=8Dc Duy Signed-off-by: Junio C Hamano --- dir.c | 113 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++= ++++++-- dir.h | 4 +++ 2 files changed, 114 insertions(+), 3 deletions(-) diff --git a/dir.c b/dir.c index 27734f0..44ed9f2 100644 --- a/dir.c +++ b/dir.c @@ -582,6 +582,22 @@ static struct untracked_cache_dir *lookup_untracke= d(struct untracked_cache *uc, return d; } =20 +static void do_invalidate_gitignore(struct untracked_cache_dir *dir) +{ + int i; + dir->valid =3D 0; + dir->untracked_nr =3D 0; + for (i =3D 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 @@ -697,6 +713,13 @@ static void add_excludes_from_file_1(struct dir_st= ruct *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 =3D 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); @@ -704,6 +727,7 @@ static void add_excludes_from_file_1(struct dir_str= uct *dir, const char *fname, =20 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); } =20 @@ -1572,9 +1596,87 @@ static int treat_leading_path(struct dir_struct = *dir, return rc; } =20 +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 !=3D 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 !=3D 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 =3D sizeof(*dir->untracked->root); + dir->untracked->root =3D xmalloc(len); + memset(dir->untracked->root, 0, len); + } + + /* Validate $GIT_DIR/info/exclude and core.excludesfile */ + root =3D 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 =3D 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 =3D 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; =20 /* * Check out create_simplify() @@ -1598,10 +1700,15 @@ int read_directory(struct dir_struct *dir, cons= t char *path, int len, const stru * create_simplify(). */ simplify =3D create_simplify(pathspec ? pathspec->_raw : NULL); + untracked =3D validate_untracked_cache(dir, len, pathspec); + if (!untracked) + /* + * make sure untracked cache code path is disabled, + * e.g. prep_exclude() + */ + dir->untracked =3D 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; }; =20 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; }; =20 /* --=20 2.2.0.84.ge9c7a8a