Skip to content

Commit eadb583

Browse files
gitstertorvalds
authored andcommitted
Avoid running lstat(2) on the same cache entry.
Aside from the lstat(2) done for work tree files, there are quite many lstat(2) calls in refname dwimming codepath. This patch is not about reducing them. * It adds a new ce_flag, CE_UPTODATE, that is meant to mark the cache entries that record a regular file blob that is up to date in the work tree. If somebody later walks the index and wants to see if the work tree has changes, they do not have to be checked with lstat(2) again. * fill_stat_cache_info() marks the cache entry it just added with CE_UPTODATE. This has the effect of marking the paths we write out of the index and lstat(2) immediately as "no need to lstat -- we know it is up-to-date", from quite a lot fo callers: - git-apply --index - git-update-index - git-checkout-index - git-add (uses add_file_to_index()) - git-commit (ditto) - git-mv (ditto) * refresh_cache_ent() also marks the cache entry that are clean with CE_UPTODATE. * write_index is changed not to write CE_UPTODATE out to the index file, because CE_UPTODATE is meant to be transient only in core. For the same reason, CE_UPDATE is not written to prevent an accident from happening. Signed-off-by: Junio C Hamano <[email protected]> Signed-off-by: Linus Torvalds <[email protected]>
1 parent 7fec10b commit eadb583

File tree

3 files changed

+32
-10
lines changed

3 files changed

+32
-10
lines changed

cache.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,7 @@ struct cache_entry {
130130
/* In-memory only */
131131
#define CE_UPDATE (0x10000)
132132
#define CE_REMOVE (0x20000)
133+
#define CE_UPTODATE (0x40000)
133134

134135
static inline unsigned create_ce_flags(size_t len, unsigned stage)
135136
{
@@ -149,6 +150,8 @@ static inline size_t ce_namelen(const struct cache_entry *ce)
149150
#define ce_size(ce) cache_entry_size(ce_namelen(ce))
150151
#define ondisk_ce_size(ce) ondisk_cache_entry_size(ce_namelen(ce))
151152
#define ce_stage(ce) ((CE_STAGEMASK & (ce)->ce_flags) >> CE_STAGESHIFT)
153+
#define ce_uptodate(ce) ((ce)->ce_flags & CE_UPTODATE)
154+
#define ce_mark_uptodate(ce) ((ce)->ce_flags |= CE_UPTODATE)
152155

153156
#define ce_permissions(mode) (((mode) & 0100) ? 0755 : 0644)
154157
static inline unsigned int create_ce_mode(unsigned int mode)

diff.c

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1510,17 +1510,22 @@ static int reuse_worktree_file(const char *name, const unsigned char *sha1, int
15101510
if (pos < 0)
15111511
return 0;
15121512
ce = active_cache[pos];
1513-
if ((lstat(name, &st) < 0) ||
1514-
!S_ISREG(st.st_mode) || /* careful! */
1515-
ce_match_stat(ce, &st, 0) ||
1516-
hashcmp(sha1, ce->sha1))
1513+
1514+
/*
1515+
* This is not the sha1 we are looking for, or
1516+
* unreusable because it is not a regular file.
1517+
*/
1518+
if (hashcmp(sha1, ce->sha1) || !S_ISREG(ce->ce_mode))
15171519
return 0;
1518-
/* we return 1 only when we can stat, it is a regular file,
1519-
* stat information matches, and sha1 recorded in the cache
1520-
* matches. I.e. we know the file in the work tree really is
1521-
* the same as the <name, sha1> pair.
1520+
1521+
/*
1522+
* If ce matches the file in the work tree, we can reuse it.
15221523
*/
1523-
return 1;
1524+
if (ce_uptodate(ce) ||
1525+
(!lstat(name, &st) && !ce_match_stat(ce, &st, 0)))
1526+
return 1;
1527+
1528+
return 0;
15241529
}
15251530

15261531
static int populate_from_stdin(struct diff_filespec *s)

read-cache.c

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,9 @@ void fill_stat_cache_info(struct cache_entry *ce, struct stat *st)
4040

4141
if (assume_unchanged)
4242
ce->ce_flags |= CE_VALID;
43+
44+
if (S_ISREG(st->st_mode))
45+
ce_mark_uptodate(ce);
4346
}
4447

4548
static int ce_compare_data(struct cache_entry *ce, struct stat *st)
@@ -412,6 +415,7 @@ int add_file_to_index(struct index_state *istate, const char *path, int verbose)
412415
!ie_match_stat(istate, istate->cache[pos], &st, ce_option)) {
413416
/* Nothing changed, really */
414417
free(ce);
418+
ce_mark_uptodate(istate->cache[pos]);
415419
return 0;
416420
}
417421

@@ -779,6 +783,9 @@ static struct cache_entry *refresh_cache_ent(struct index_state *istate,
779783
int changed, size;
780784
int ignore_valid = options & CE_MATCH_IGNORE_VALID;
781785

786+
if (ce_uptodate(ce))
787+
return ce;
788+
782789
if (lstat(ce->name, &st) < 0) {
783790
if (err)
784791
*err = errno;
@@ -797,8 +804,15 @@ static struct cache_entry *refresh_cache_ent(struct index_state *istate,
797804
if (ignore_valid && assume_unchanged &&
798805
!(ce->ce_flags & CE_VALID))
799806
; /* mark this one VALID again */
800-
else
807+
else {
808+
/*
809+
* We do not mark the index itself "modified"
810+
* because CE_UPTODATE flag is in-core only;
811+
* we are not going to write this change out.
812+
*/
813+
ce_mark_uptodate(ce);
801814
return ce;
815+
}
802816
}
803817

804818
if (ie_modified(istate, ce, &st, options)) {

0 commit comments

Comments
 (0)