зеркало из https://github.com/microsoft/git.git
unpack-trees: skip stat on fsmonitor-valid files
The index might be aware that a file hasn't modified via fsmonitor, but unpack-trees did not pay attention to it and checked via ie_match_stat which can be inefficient on certain filesystems. This significantly slows down commands that run oneway_merge, like checkout and reset --hard. This patch makes oneway_merge check whether a file is considered unchanged through fsmonitor and skips ie_match_stat on it. unpack-trees also now correctly copies over fsmonitor validity state from the source index. Finally, for correctness, we force a refresh of fsmonitor state in tweak_fsmonitor. After this change, commands like stash (that use reset --hard internally) go from 8s or more to ~2s on a 250k file repository on a mac. Helped-by: Junio C Hamano <gitster@pobox.com> Helped-by: Kevin Willford <Kevin.Willford@microsoft.com> Signed-off-by: Utsav Shah <utsav@dropbox.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
Родитель
61eea521fe
Коммит
679f2f9fdd
23
fsmonitor.c
23
fsmonitor.c
|
@ -191,13 +191,26 @@ void refresh_fsmonitor(struct index_state *istate)
|
|||
}
|
||||
if (bol < query_result.len)
|
||||
fsmonitor_refresh_callback(istate, buf + bol);
|
||||
|
||||
/* Now mark the untracked cache for fsmonitor usage */
|
||||
if (istate->untracked)
|
||||
istate->untracked->use_fsmonitor = 1;
|
||||
} else {
|
||||
|
||||
/* We only want to run the post index changed hook if we've actually changed entries, so keep track
|
||||
* if we actually changed entries or not */
|
||||
int is_cache_changed = 0;
|
||||
/* Mark all entries invalid */
|
||||
for (i = 0; i < istate->cache_nr; i++)
|
||||
istate->cache[i]->ce_flags &= ~CE_FSMONITOR_VALID;
|
||||
for (i = 0; i < istate->cache_nr; i++) {
|
||||
if (istate->cache[i]->ce_flags & CE_FSMONITOR_VALID) {
|
||||
is_cache_changed = 1;
|
||||
istate->cache[i]->ce_flags &= ~CE_FSMONITOR_VALID;
|
||||
}
|
||||
}
|
||||
|
||||
/* If we're going to check every file, ensure we save the results */
|
||||
istate->cache_changed |= FSMONITOR_CHANGED;
|
||||
if (is_cache_changed)
|
||||
istate->cache_changed |= FSMONITOR_CHANGED;
|
||||
|
||||
if (istate->untracked)
|
||||
istate->untracked->use_fsmonitor = 0;
|
||||
|
@ -259,9 +272,7 @@ void tweak_fsmonitor(struct index_state *istate)
|
|||
(uintmax_t)istate->fsmonitor_dirty->bit_size, istate->cache_nr);
|
||||
ewah_each_bit(istate->fsmonitor_dirty, fsmonitor_ewah_callback, istate);
|
||||
|
||||
/* Now mark the untracked cache for fsmonitor usage */
|
||||
if (istate->untracked)
|
||||
istate->untracked->use_fsmonitor = 1;
|
||||
refresh_fsmonitor(istate);
|
||||
}
|
||||
|
||||
ewah_free(istate->fsmonitor_dirty);
|
||||
|
|
|
@ -106,6 +106,8 @@ EOF
|
|||
|
||||
# test that "update-index --fsmonitor-valid" sets the fsmonitor valid bit
|
||||
test_expect_success 'update-index --fsmonitor-valid" sets the fsmonitor valid bit' '
|
||||
write_script .git/hooks/fsmonitor-test<<-\EOF &&
|
||||
EOF
|
||||
git update-index --fsmonitor &&
|
||||
git update-index --fsmonitor-valid dir1/modified &&
|
||||
git update-index --fsmonitor-valid dir2/modified &&
|
||||
|
@ -164,6 +166,8 @@ EOF
|
|||
|
||||
# test that newly added files are marked valid
|
||||
test_expect_success 'newly added files are marked valid' '
|
||||
write_script .git/hooks/fsmonitor-test<<-\EOF &&
|
||||
EOF
|
||||
git add new &&
|
||||
git add dir1/new &&
|
||||
git add dir2/new &&
|
||||
|
@ -218,11 +222,12 @@ test_expect_success '*only* files returned by the integration script get flagged
|
|||
# Ensure commands that call refresh_index() to move the index back in time
|
||||
# properly invalidate the fsmonitor cache
|
||||
test_expect_success 'refresh_index() invalidates fsmonitor cache' '
|
||||
write_script .git/hooks/fsmonitor-test<<-\EOF &&
|
||||
EOF
|
||||
clean_repo &&
|
||||
dirty_repo &&
|
||||
write_integration_script &&
|
||||
git add . &&
|
||||
write_script .git/hooks/fsmonitor-test<<-\EOF &&
|
||||
EOF
|
||||
git commit -m "to reset" &&
|
||||
git reset HEAD~1 &&
|
||||
git status >actual &&
|
||||
|
|
|
@ -1494,6 +1494,9 @@ int unpack_trees(unsigned len, struct tree_desc *t, struct unpack_trees_options
|
|||
o->merge_size = len;
|
||||
mark_all_ce_unused(o->src_index);
|
||||
|
||||
if (o->src_index->fsmonitor_last_update)
|
||||
o->result.fsmonitor_last_update = o->src_index->fsmonitor_last_update;
|
||||
|
||||
/*
|
||||
* Sparse checkout loop #1: set NEW_SKIP_WORKTREE on existing entries
|
||||
*/
|
||||
|
@ -2374,7 +2377,8 @@ int oneway_merge(const struct cache_entry * const *src,
|
|||
|
||||
if (old && same(old, a)) {
|
||||
int update = 0;
|
||||
if (o->reset && o->update && !ce_uptodate(old) && !ce_skip_worktree(old)) {
|
||||
if (o->reset && o->update && !ce_uptodate(old) && !ce_skip_worktree(old) &&
|
||||
!(old->ce_flags & CE_FSMONITOR_VALID)) {
|
||||
struct stat st;
|
||||
if (lstat(old->name, &st) ||
|
||||
ie_match_stat(o->src_index, old, &st, CE_MATCH_IGNORE_VALID|CE_MATCH_IGNORE_SKIP_WORKTREE))
|
||||
|
|
Загрузка…
Ссылка в новой задаче