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:
parent
61eea521fe
commit
679f2f9fdd
19
fsmonitor.c
19
fsmonitor.c
@ -191,12 +191,25 @@ void refresh_fsmonitor(struct index_state *istate)
|
|||||||
}
|
}
|
||||||
if (bol < query_result.len)
|
if (bol < query_result.len)
|
||||||
fsmonitor_refresh_callback(istate, buf + bol);
|
fsmonitor_refresh_callback(istate, buf + bol);
|
||||||
|
|
||||||
|
/* Now mark the untracked cache for fsmonitor usage */
|
||||||
|
if (istate->untracked)
|
||||||
|
istate->untracked->use_fsmonitor = 1;
|
||||||
} else {
|
} 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 */
|
/* Mark all entries invalid */
|
||||||
for (i = 0; i < istate->cache_nr; i++)
|
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;
|
istate->cache[i]->ce_flags &= ~CE_FSMONITOR_VALID;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* If we're going to check every file, ensure we save the results */
|
/* If we're going to check every file, ensure we save the results */
|
||||||
|
if (is_cache_changed)
|
||||||
istate->cache_changed |= FSMONITOR_CHANGED;
|
istate->cache_changed |= FSMONITOR_CHANGED;
|
||||||
|
|
||||||
if (istate->untracked)
|
if (istate->untracked)
|
||||||
@ -259,9 +272,7 @@ void tweak_fsmonitor(struct index_state *istate)
|
|||||||
(uintmax_t)istate->fsmonitor_dirty->bit_size, istate->cache_nr);
|
(uintmax_t)istate->fsmonitor_dirty->bit_size, istate->cache_nr);
|
||||||
ewah_each_bit(istate->fsmonitor_dirty, fsmonitor_ewah_callback, istate);
|
ewah_each_bit(istate->fsmonitor_dirty, fsmonitor_ewah_callback, istate);
|
||||||
|
|
||||||
/* Now mark the untracked cache for fsmonitor usage */
|
refresh_fsmonitor(istate);
|
||||||
if (istate->untracked)
|
|
||||||
istate->untracked->use_fsmonitor = 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ewah_free(istate->fsmonitor_dirty);
|
ewah_free(istate->fsmonitor_dirty);
|
||||||
|
@ -106,6 +106,8 @@ EOF
|
|||||||
|
|
||||||
# test that "update-index --fsmonitor-valid" sets the fsmonitor valid bit
|
# test that "update-index --fsmonitor-valid" sets the fsmonitor valid bit
|
||||||
test_expect_success '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 &&
|
||||||
git update-index --fsmonitor-valid dir1/modified &&
|
git update-index --fsmonitor-valid dir1/modified &&
|
||||||
git update-index --fsmonitor-valid dir2/modified &&
|
git update-index --fsmonitor-valid dir2/modified &&
|
||||||
@ -164,6 +166,8 @@ EOF
|
|||||||
|
|
||||||
# test that newly added files are marked valid
|
# test that newly added files are marked valid
|
||||||
test_expect_success '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 new &&
|
||||||
git add dir1/new &&
|
git add dir1/new &&
|
||||||
git add dir2/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
|
# Ensure commands that call refresh_index() to move the index back in time
|
||||||
# properly invalidate the fsmonitor cache
|
# properly invalidate the fsmonitor cache
|
||||||
test_expect_success 'refresh_index() invalidates fsmonitor cache' '
|
test_expect_success 'refresh_index() invalidates fsmonitor cache' '
|
||||||
write_script .git/hooks/fsmonitor-test<<-\EOF &&
|
|
||||||
EOF
|
|
||||||
clean_repo &&
|
clean_repo &&
|
||||||
dirty_repo &&
|
dirty_repo &&
|
||||||
|
write_integration_script &&
|
||||||
git add . &&
|
git add . &&
|
||||||
|
write_script .git/hooks/fsmonitor-test<<-\EOF &&
|
||||||
|
EOF
|
||||||
git commit -m "to reset" &&
|
git commit -m "to reset" &&
|
||||||
git reset HEAD~1 &&
|
git reset HEAD~1 &&
|
||||||
git status >actual &&
|
git status >actual &&
|
||||||
|
@ -1494,6 +1494,9 @@ int unpack_trees(unsigned len, struct tree_desc *t, struct unpack_trees_options
|
|||||||
o->merge_size = len;
|
o->merge_size = len;
|
||||||
mark_all_ce_unused(o->src_index);
|
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
|
* 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)) {
|
if (old && same(old, a)) {
|
||||||
int update = 0;
|
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;
|
struct stat st;
|
||||||
if (lstat(old->name, &st) ||
|
if (lstat(old->name, &st) ||
|
||||||
ie_match_stat(o->src_index, old, &st, CE_MATCH_IGNORE_VALID|CE_MATCH_IGNORE_SKIP_WORKTREE))
|
ie_match_stat(o->src_index, old, &st, CE_MATCH_IGNORE_VALID|CE_MATCH_IGNORE_SKIP_WORKTREE))
|
||||||
|
Loading…
Reference in New Issue
Block a user