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 = ⪙
}
+ 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
next prev 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 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).