From: "Nguyễn Thái Ngọc Duy" <pclouds@gmail.com>
To: git@vger.kernel.org
Cc: "Junio C Hamano" <gitster@pobox.com>,
"Nguyễn Thái Ngọc Duy" <pclouds@gmail.com>
Subject: [PATCH] checkout: avoid unncessary match_pathspec calls
Date: Sat, 23 Mar 2013 17:55:42 +0700 [thread overview]
Message-ID: <1364036142-3031-1-git-send-email-pclouds@gmail.com> (raw)
In checkout_paths() we do this
- for i = 0..active_nr, if not updated, call match_pathspec
- for ..., call match_pathspec (inside unmerge_cache)
- for ..., call match_pathspec (for showing "path .. is unmerged)
- for ..., if not updated, call match_pathspec and update paths
That's a lot of duplicate match_pathspec(s) and the function is not
exactly cheap to be called so many times, especially on large indexes.
This patch makes it call match_pathspec once per index entry, save the
result in ce_flags and reuse the results in the following loops.
This command is used on webkit, 215k entries. The pattern is chosen
mainly to make match_pathspec sweat:
git checkout -- "*[a-zA-Z]*[a-zA-Z]*[a-zA-Z]*"
before after
real 0m3.493s 0m2.737s
user 0m2.239s 0m1.586s
sys 0m1.252s 0m1.151s
Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
Junio, this patch clearly conflicts wih nd/magic-pathspecs. Do you
want me to:
- hold it off until nd/magic-pathspecs graduates
- rebase on top of nd/magic-pathspecs and repost
- leave it to you to handle conflicts
?
builtin/checkout.c | 23 +++++++++++++++++++----
cache.h | 1 +
resolve-undo.c | 19 ++++++++++++++++++-
resolve-undo.h | 1 +
4 files changed, 39 insertions(+), 5 deletions(-)
diff --git a/builtin/checkout.c b/builtin/checkout.c
index a9c1b5a..fadc11b 100644
--- a/builtin/checkout.c
+++ b/builtin/checkout.c
@@ -273,22 +273,37 @@ static int checkout_paths(const struct checkout_opts *opts,
for (pos = 0; pos < active_nr; pos++) {
struct cache_entry *ce = active_cache[pos];
+ ce->ce_flags &= ~CE_MATCHED;
if (opts->source_tree && !(ce->ce_flags & CE_UPDATE))
continue;
- match_pathspec(opts->pathspec, ce->name, ce_namelen(ce), 0, ps_matched);
+ if (match_pathspec(opts->pathspec, ce->name,
+ ce_namelen(ce), 0, ps_matched))
+ ce->ce_flags |= CE_MATCHED;
}
if (report_path_error(ps_matched, opts->pathspec, opts->prefix))
return 1;
+ /*
+ * call match_pathspec on the remaining entries that have not
+ * been done in the previous loop
+ */
+ for (pos = 0; pos < active_nr; pos++) {
+ struct cache_entry *ce = active_cache[pos];
+ if (opts->source_tree && !(ce->ce_flags & CE_UPDATE) &&
+ match_pathspec(opts->pathspec, ce->name,
+ ce_namelen(ce), 0, ps_matched))
+ ce->ce_flags |= CE_MATCHED;
+ }
+
/* "checkout -m path" to recreate conflicted state */
if (opts->merge)
- unmerge_cache(opts->pathspec);
+ unmerge_marked_index(&the_index);
/* Any unmerged paths? */
for (pos = 0; pos < active_nr; pos++) {
struct cache_entry *ce = active_cache[pos];
- if (match_pathspec(opts->pathspec, ce->name, ce_namelen(ce), 0, NULL)) {
+ if (ce->ce_flags & CE_MATCHED) {
if (!ce_stage(ce))
continue;
if (opts->force) {
@@ -315,7 +330,7 @@ static int checkout_paths(const struct checkout_opts *opts,
struct cache_entry *ce = active_cache[pos];
if (opts->source_tree && !(ce->ce_flags & CE_UPDATE))
continue;
- if (match_pathspec(opts->pathspec, ce->name, ce_namelen(ce), 0, NULL)) {
+ if (ce->ce_flags & CE_MATCHED) {
if (!ce_stage(ce)) {
errs |= checkout_entry(ce, &state, NULL);
continue;
diff --git a/cache.h b/cache.h
index c56315c..04e6090 100644
--- a/cache.h
+++ b/cache.h
@@ -161,6 +161,7 @@ struct cache_entry {
#define CE_UNPACKED (1 << 24)
#define CE_NEW_SKIP_WORKTREE (1 << 25)
+#define CE_MATCHED (1 << 26)
/*
* Extended on-disk flags
diff --git a/resolve-undo.c b/resolve-undo.c
index 72b4612..639eb9c 100644
--- a/resolve-undo.c
+++ b/resolve-undo.c
@@ -118,7 +118,7 @@ int unmerge_index_entry_at(struct index_state *istate, int pos)
struct cache_entry *ce;
struct string_list_item *item;
struct resolve_undo_info *ru;
- int i, err = 0;
+ int i, err = 0, matched;
if (!istate->resolve_undo)
return pos;
@@ -137,6 +137,7 @@ int unmerge_index_entry_at(struct index_state *istate, int pos)
ru = item->util;
if (!ru)
return pos;
+ matched = ce->ce_flags & CE_MATCHED;
remove_index_entry_at(istate, pos);
for (i = 0; i < 3; i++) {
struct cache_entry *nce;
@@ -144,6 +145,8 @@ int unmerge_index_entry_at(struct index_state *istate, int pos)
continue;
nce = make_cache_entry(ru->mode[i], ru->sha1[i],
ce->name, i + 1, 0);
+ if (matched)
+ nce->ce_flags |= CE_MATCHED;
if (add_index_entry(istate, nce, ADD_CACHE_OK_TO_ADD)) {
err = 1;
error("cannot unmerge '%s'", ce->name);
@@ -156,6 +159,20 @@ int unmerge_index_entry_at(struct index_state *istate, int pos)
return unmerge_index_entry_at(istate, pos);
}
+void unmerge_marked_index(struct index_state *istate)
+{
+ int i;
+
+ if (!istate->resolve_undo)
+ return;
+
+ for (i = 0; i < istate->cache_nr; i++) {
+ struct cache_entry *ce = istate->cache[i];
+ if (ce->ce_flags & CE_MATCHED)
+ i = unmerge_index_entry_at(istate, i);
+ }
+}
+
void unmerge_index(struct index_state *istate, const char **pathspec)
{
int i;
diff --git a/resolve-undo.h b/resolve-undo.h
index 8458769..7a30206 100644
--- a/resolve-undo.h
+++ b/resolve-undo.h
@@ -12,5 +12,6 @@ extern struct string_list *resolve_undo_read(const char *, unsigned long);
extern void resolve_undo_clear_index(struct index_state *);
extern int unmerge_index_entry_at(struct index_state *, int);
extern void unmerge_index(struct index_state *, const char **);
+extern void unmerge_marked_index(struct index_state *);
#endif
--
1.8.2.83.gc99314b
next reply other threads:[~2013-03-23 10:56 UTC|newest]
Thread overview: 7+ messages / expand[flat|nested] mbox.gz Atom feed top
2013-03-23 10:55 Nguyễn Thái Ngọc Duy [this message]
2013-03-24 2:45 ` [PATCH] checkout: avoid unncessary match_pathspec calls Eric Sunshine
2013-03-24 6:47 ` Junio C Hamano
2013-03-24 12:55 ` [PATCH v2] checkout: avoid unnecessary " Nguyễn Thái Ngọc Duy
2013-03-25 16:26 ` Junio C Hamano
2013-03-27 5:58 ` [PATCH v3] " Nguyễn Thái Ngọc Duy
2013-03-28 22:32 ` Junio C Hamano
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=1364036142-3031-1-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).