Skip to content

Commit 858119f

Browse files
committed
Merge branch 'nk/diff-index-fsmonitor'
"git diff-index" codepath has been taught to trust fsmonitor status to reduce number of lstat() calls. * nk/diff-index-fsmonitor: fsmonitor: add perf test for git diff HEAD fsmonitor: add assertion that fsmonitor is valid to check_removed fsmonitor: skip lstat deletion check during git diff-index
2 parents e537784 + 7e5aa13 commit 858119f

File tree

4 files changed

+32
-10
lines changed

4 files changed

+32
-10
lines changed

diff-lib.c

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,10 @@
2828
* exists for ce that is a submodule -- it is a submodule that is not
2929
* checked out). Return negative for an error.
3030
*/
31-
static int check_removed(const struct cache_entry *ce, struct stat *st)
31+
static int check_removed(const struct index_state *istate, const struct cache_entry *ce, struct stat *st)
3232
{
33-
if (lstat(ce->name, st) < 0) {
33+
assert(is_fsmonitor_refreshed(istate));
34+
if (!(ce->ce_flags & CE_FSMONITOR_VALID) && lstat(ce->name, st) < 0) {
3435
if (!is_missing_file_error(errno))
3536
return -1;
3637
return 1;
@@ -136,7 +137,7 @@ int run_diff_files(struct rev_info *revs, unsigned int option)
136137
memset(&(dpath->parent[0]), 0,
137138
sizeof(struct combine_diff_parent)*5);
138139

139-
changed = check_removed(ce, &st);
140+
changed = check_removed(istate, ce, &st);
140141
if (!changed)
141142
wt_mode = ce_mode_from_stat(ce, st.st_mode);
142143
else {
@@ -216,7 +217,7 @@ int run_diff_files(struct rev_info *revs, unsigned int option)
216217
} else {
217218
struct stat st;
218219

219-
changed = check_removed(ce, &st);
220+
changed = check_removed(istate, ce, &st);
220221
if (changed) {
221222
if (changed < 0) {
222223
perror(ce->name);
@@ -278,7 +279,8 @@ static void diff_index_show_file(struct rev_info *revs,
278279
oid, oid_valid, ce->name, dirty_submodule);
279280
}
280281

281-
static int get_stat_data(const struct cache_entry *ce,
282+
static int get_stat_data(const struct index_state *istate,
283+
const struct cache_entry *ce,
282284
const struct object_id **oidp,
283285
unsigned int *modep,
284286
int cached, int match_missing,
@@ -290,7 +292,7 @@ static int get_stat_data(const struct cache_entry *ce,
290292
if (!cached && !ce_uptodate(ce)) {
291293
int changed;
292294
struct stat st;
293-
changed = check_removed(ce, &st);
295+
changed = check_removed(istate, ce, &st);
294296
if (changed < 0)
295297
return -1;
296298
else if (changed) {
@@ -321,12 +323,13 @@ static void show_new_file(struct rev_info *revs,
321323
const struct object_id *oid;
322324
unsigned int mode;
323325
unsigned dirty_submodule = 0;
326+
struct index_state *istate = revs->diffopt.repo->index;
324327

325328
/*
326329
* New file in the index: it might actually be different in
327330
* the working tree.
328331
*/
329-
if (get_stat_data(new_file, &oid, &mode, cached, match_missing,
332+
if (get_stat_data(istate, new_file, &oid, &mode, cached, match_missing,
330333
&dirty_submodule, &revs->diffopt) < 0)
331334
return;
332335

@@ -342,8 +345,9 @@ static int show_modified(struct rev_info *revs,
342345
unsigned int mode, oldmode;
343346
const struct object_id *oid;
344347
unsigned dirty_submodule = 0;
348+
struct index_state *istate = revs->diffopt.repo->index;
345349

346-
if (get_stat_data(new_entry, &oid, &mode, cached, match_missing,
350+
if (get_stat_data(istate, new_entry, &oid, &mode, cached, match_missing,
347351
&dirty_submodule, &revs->diffopt) < 0) {
348352
if (report_missing)
349353
diff_index_show_file(revs, "-", old_entry,
@@ -574,13 +578,16 @@ int run_diff_index(struct rev_info *revs, unsigned int option)
574578
struct object_id oid;
575579
const char *name;
576580
char merge_base_hex[GIT_MAX_HEXSZ + 1];
581+
struct index_state *istate = revs->diffopt.repo->index;
577582

578583
if (revs->pending.nr != 1)
579584
BUG("run_diff_index must be passed exactly one tree");
580585

581586
trace_performance_enter();
582587
ent = revs->pending.objects;
583588

589+
refresh_fsmonitor(istate);
590+
584591
if (merge_base) {
585592
diff_get_merge_base(revs, &oid);
586593
name = oid_to_hex_r(merge_base_hex, &oid);

fsmonitor.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,17 @@ void refresh_fsmonitor(struct index_state *istate);
4949
*/
5050
int fsmonitor_is_trivial_response(const struct strbuf *query_result);
5151

52+
/*
53+
* Check if refresh_fsmonitor has been called at least once.
54+
* refresh_fsmonitor is idempotent. Returns true if fsmonitor is
55+
* not enabled (since the state will be "fresh" w/ CE_FSMONITOR_VALID unset)
56+
* This version is useful for assertions
57+
*/
58+
static inline int is_fsmonitor_refreshed(const struct index_state *istate)
59+
{
60+
return !core_fsmonitor || istate->fsmonitor_has_run_once;
61+
}
62+
5263
/*
5364
* Set the given cache entries CE_FSMONITOR_VALID bit. This should be
5465
* called any time the cache entry has been updated to reflect the

t/helper/test-chmtime.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -109,9 +109,9 @@ int cmd__chmtime(int argc, const char **argv)
109109
uintmax_t mtime;
110110

111111
if (stat(argv[i], &sb) < 0) {
112-
fprintf(stderr, "Failed to stat %s: %s\n",
112+
fprintf(stderr, "Failed to stat %s: %s. Skipping\n",
113113
argv[i], strerror(errno));
114-
return 1;
114+
continue;
115115
}
116116

117117
#ifdef GIT_WINDOWS_NATIVE

t/perf/p7519-fsmonitor.sh

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,10 @@ test_fsmonitor_suite() {
216216
git diff
217217
'
218218

219+
test_perf_w_drop_caches "diff HEAD ($DESC)" '
220+
git diff HEAD
221+
'
222+
219223
test_perf_w_drop_caches "diff -- 0_files ($DESC)" '
220224
git diff -- 1_file
221225
'

0 commit comments

Comments
 (0)