All of lore.kernel.org
 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>
Subject: [PATCH 02/10] unpack-trees: move all skip-worktree check back to unpack_trees()
Date: Mon, 15 Nov 2010 17:36:42 +0700	[thread overview]
Message-ID: <1289817410-32470-3-git-send-email-pclouds@gmail.com> (raw)
In-Reply-To: <1289817410-32470-1-git-send-email-pclouds@gmail.com>

Earlier, the will_have_skip_worktree() checks are done in various places:

1. in verify_* functions to prevent absent/uptodate checks outside
   worktree
2. in merged_entry for new index entries
3. in apply_sparse_checkout() for all entries

In case all entries are added new ($GIT_DIR/index is missing) all the
above checks will be done for all entries, which in the worst case can
become cache_nr*el->nr*3 fnmatch() calls. Quite expensive.

By moving all will_have_skip_worktree() checks to unpack_trees(), we
now have two places to run the checks:

 - one before calling traverse_trees(), where all current index
   entries are checked.
 - one after traverse_trees(), where newly-added entries are checked.

In worst case, each entry will be checked once, or cache_nr*el->nr
fnmatch() calls at most. The two places are a loop over all entries,
which also makes optimization easier.

CE_ADDED is used to mark new entries. The flag is only used by
add_to_index(), which should not be called while unpack_trees() is
running.

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 cache.h        |    1 +
 unpack-trees.c |   69 ++++++++++++++++++++++++++++++++++++++++++++++++++-----
 2 files changed, 63 insertions(+), 7 deletions(-)

diff --git a/cache.h b/cache.h
index 33decd9..d87708a 100644
--- a/cache.h
+++ b/cache.h
@@ -182,6 +182,7 @@ struct cache_entry {
 #define CE_WT_REMOVE (0x400000) /* remove in work directory */
 
 #define CE_UNPACKED  (0x1000000)
+#define CE_NEW_SKIP_WORKTREE (0x2000000)
 
 /*
  * Extended on-disk flags
diff --git a/unpack-trees.c b/unpack-trees.c
index 803445a..9acd9be 100644
--- a/unpack-trees.c
+++ b/unpack-trees.c
@@ -258,7 +258,7 @@ static int apply_sparse_checkout(struct cache_entry *ce, struct unpack_trees_opt
 {
 	int was_skip_worktree = ce_skip_worktree(ce);
 
-	if (!ce_stage(ce) && will_have_skip_worktree(ce, o))
+	if (ce->ce_flags & CE_NEW_SKIP_WORKTREE)
 		ce->ce_flags |= CE_SKIP_WORKTREE;
 	else
 		ce->ce_flags &= ~CE_SKIP_WORKTREE;
@@ -834,6 +834,49 @@ static int unpack_callback(int n, unsigned long mask, unsigned long dirmask, str
 	return mask;
 }
 
+static void set_new_skip_worktree_1(struct unpack_trees_options *o)
+{
+	int i;
+
+	for (i = 0;i < o->src_index->cache_nr;i++) {
+		struct cache_entry *ce = o->src_index->cache[i];
+		ce->ce_flags &= ~CE_ADDED;
+		if (!ce_stage(ce) && will_have_skip_worktree(ce, o))
+			ce->ce_flags |= CE_NEW_SKIP_WORKTREE;
+		else
+			ce->ce_flags &= ~CE_NEW_SKIP_WORKTREE;
+	}
+}
+
+static int verify_absent(struct cache_entry *, enum unpack_trees_error_types, struct unpack_trees_options *);
+static int set_new_skip_worktree_2(struct unpack_trees_options *o)
+{
+	int i;
+
+	/*
+	 * CE_ADDED marks new index entries. These have not been processed
+	 * by set_new_skip_worktree_1() so we do it here.
+	 */
+	for (i = 0;i < o->result.cache_nr;i++) {
+		struct cache_entry *ce = o->result.cache[i];
+
+		if (!(ce->ce_flags & CE_ADDED))
+			continue;
+
+		ce->ce_flags &= ~CE_ADDED;
+		if (!ce_stage(ce) && will_have_skip_worktree(ce, o))
+			ce->ce_flags |= CE_SKIP_WORKTREE | CE_NEW_SKIP_WORKTREE;
+		else
+			ce->ce_flags &= ~(CE_SKIP_WORKTREE | CE_NEW_SKIP_WORKTREE);
+
+		/* Left-over checks from merged_entry when old == NULL */
+		if (verify_absent(ce, ERROR_WOULD_LOSE_UNTRACKED_OVERWRITTEN, o))
+			return -1;
+	}
+
+	return 0;
+}
+
 /*
  * N-way merge "len" trees.  Returns 0 on success, -1 on failure to manipulate the
  * resulting index, -2 on failure to reflect the changes to the work tree.
@@ -862,6 +905,9 @@ int unpack_trees(unsigned len, struct tree_desc *t, struct unpack_trees_options
 			o->el = &el;
 	}
 
+	if (!o->skip_sparse_checkout)
+		set_new_skip_worktree_1(o);
+
 	memset(&o->result, 0, sizeof(o->result));
 	o->result.initialized = 1;
 	o->result.timestamp.sec = o->src_index->timestamp.sec;
@@ -922,6 +968,10 @@ int unpack_trees(unsigned len, struct tree_desc *t, struct unpack_trees_options
 
 	if (!o->skip_sparse_checkout) {
 		int empty_worktree = 1;
+
+		if (set_new_skip_worktree_2(o))
+			goto return_failed;
+
 		for (i = 0;i < o->result.cache_nr;i++) {
 			struct cache_entry *ce = o->result.cache[i];
 
@@ -1017,7 +1067,7 @@ static int verify_uptodate_1(struct cache_entry *ce,
 static int verify_uptodate(struct cache_entry *ce,
 			   struct unpack_trees_options *o)
 {
-	if (!o->skip_sparse_checkout && will_have_skip_worktree(ce, o))
+	if (!o->skip_sparse_checkout && (ce->ce_flags & CE_NEW_SKIP_WORKTREE))
 		return 0;
 	return verify_uptodate_1(ce, o, ERROR_NOT_UPTODATE_FILE);
 }
@@ -1204,7 +1254,7 @@ static int verify_absent(struct cache_entry *ce,
 			 enum unpack_trees_error_types error_type,
 			 struct unpack_trees_options *o)
 {
-	if (!o->skip_sparse_checkout && will_have_skip_worktree(ce, o))
+	if (!o->skip_sparse_checkout && (ce->ce_flags & CE_NEW_SKIP_WORKTREE))
 		return 0;
 	return verify_absent_1(ce, error_type, o);
 }
@@ -1226,10 +1276,15 @@ static int merged_entry(struct cache_entry *merge, struct cache_entry *old,
 	int update = CE_UPDATE;
 
 	if (!old) {
+		/*
+		 * Set CE_NEW_SKIP_WORKTREE on "merge" to make
+		 * verify_absent() no-op. The true check will be done
+		 * later on in unpack_trees().
+		 */
+		merge->ce_flags |= CE_NEW_SKIP_WORKTREE;
 		if (verify_absent(merge, ERROR_WOULD_LOSE_UNTRACKED_OVERWRITTEN, o))
 			return -1;
-		if (!o->skip_sparse_checkout && will_have_skip_worktree(merge, o))
-			update |= CE_SKIP_WORKTREE;
+		update |= CE_ADDED;
 		invalidate_ce_path(merge, o);
 	} else if (!(old->ce_flags & CE_CONFLICTED)) {
 		/*
@@ -1245,8 +1300,8 @@ static int merged_entry(struct cache_entry *merge, struct cache_entry *old,
 		} else {
 			if (verify_uptodate(old, o))
 				return -1;
-			if (ce_skip_worktree(old))
-				update |= CE_SKIP_WORKTREE;
+			/* Migrate old bits over */
+			update |= old->ce_flags & (CE_SKIP_WORKTREE | CE_NEW_SKIP_WORKTREE);
 			invalidate_ce_path(old, o);
 		}
 	} else {
-- 
1.7.3.2.210.g045198

  parent reply	other threads:[~2010-11-15 10:38 UTC|newest]

Thread overview: 34+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2010-11-15 10:36 [PATCH 00/10] Sparse checkout fixes and improvements Nguyễn Thái Ngọc Duy
2010-11-15 10:36 ` [PATCH 01/10] add: do not rely on dtype being NULL behavior Nguyễn Thái Ngọc Duy
2010-11-15 12:14   ` Jonathan Nieder
2010-11-16  2:18     ` Nguyen Thai Ngoc Duy
2010-11-16  2:42       ` Jonathan Nieder
2010-11-16 18:58       ` Junio C Hamano
2010-11-17  6:38         ` Nguyen Thai Ngoc Duy
2010-11-15 10:36 ` Nguyễn Thái Ngọc Duy [this message]
2010-11-15 12:34   ` [PATCH 02/10] unpack-trees: move all skip-worktree check back to unpack_trees() Thiago Farina
2010-11-16  2:19     ` Nguyen Thai Ngoc Duy
2010-11-15 16:01   ` Jonathan Nieder
2010-11-16  2:39     ` Nguyen Thai Ngoc Duy
2010-11-15 10:36 ` [PATCH 03/10] unpack-trees: add function to update ce_flags based on sparse patterns Nguyễn Thái Ngọc Duy
2010-11-15 18:30   ` Jonathan Nieder
2010-11-15 20:19   ` Jonathan Nieder
2010-11-15 10:36 ` [PATCH 04/10] unpack-trees: fix sparse checkout's "unable to match directories" fault Nguyễn Thái Ngọc Duy
2010-11-15 19:10   ` Jonathan Nieder
2010-11-16  2:43     ` Nguyen Thai Ngoc Duy
2010-11-15 10:36 ` [PATCH 05/10] unpack-trees: optimize full checkout case Nguyễn Thái Ngọc Duy
2010-11-15 20:41   ` Jonathan Nieder
2010-11-15 10:36 ` [PATCH 06/10] templates: add info/sparse-checkout Nguyễn Thái Ngọc Duy
2010-11-15 10:36 ` [PATCH 07/10] checkout: add -S to update sparse checkout Nguyễn Thái Ngọc Duy
2010-11-15 21:16   ` Jonathan Nieder
2010-11-15 21:52     ` Miles Bader
2010-11-17 15:02       ` Nguyen Thai Ngoc Duy
2010-11-16  3:08     ` Nguyen Thai Ngoc Duy
2010-11-15 10:36 ` [PATCH 08/10] checkout: add --full to fully populate working directory Nguyễn Thái Ngọc Duy
2010-11-15 21:23   ` Jonathan Nieder
2010-11-16  2:50     ` Nguyen Thai Ngoc Duy
2010-11-15 10:36 ` [PATCH 09/10] git-checkout.txt: mention of sparse checkout Nguyễn Thái Ngọc Duy
2010-11-15 10:36 ` [PATCH 10/10] clean: support cleaning sparse checkout with -S Nguyễn Thái Ngọc Duy
2010-11-15 21:30   ` Jonathan Nieder
2010-11-16  2:53     ` Nguyen Thai Ngoc Duy
2010-11-16  3:07       ` Jonathan Nieder

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=1289817410-32470-3-git-send-email-pclouds@gmail.com \
    --to=pclouds@gmail.com \
    --cc=git@vger.kernel.org \
    /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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.