mirror of
https://github.com/git/git.git
synced 2026-01-28 11:32:24 +00:00
read-cache: speed up add_index_entry during checkout
Teach add_index_entry_with_check() and has_dir_name() to see if the path of the new item is greater than the last path in the index array before attempting to search for it. This is a performance optimization. During checkout, merge_working_tree() populates the new index in sorted order, so this change saves at least 2 lookups per file. Signed-off-by: Jeff Hostetler <jeffhost@microsoft.com>
This commit is contained in:
committed by
Johannes Schindelin
parent
d5251c7b08
commit
4e6cb0e08b
1
cache.h
1
cache.h
@@ -572,6 +572,7 @@ extern int write_locked_index(struct index_state *, struct lock_file *lock, unsi
|
||||
extern int discard_index(struct index_state *);
|
||||
extern int unmerged_index(const struct index_state *);
|
||||
extern int verify_path(const char *path);
|
||||
extern int strcmp_offset(const char *s1_in, const char *s2_in, int *first_change);
|
||||
extern int index_dir_exists(struct index_state *istate, const char *name, int namelen);
|
||||
extern void adjust_dirname_case(struct index_state *istate, char *name);
|
||||
extern struct cache_entry *index_file_exists(struct index_state *istate, const char *name, int namelen, int igncase);
|
||||
|
||||
72
read-cache.c
72
read-cache.c
@@ -894,6 +894,34 @@ static int has_file_name(struct index_state *istate,
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*
|
||||
* Like strcmp(), but also return the offset of the first change.
|
||||
*/
|
||||
int strcmp_offset(const char *s1_in, const char *s2_in, int *first_change)
|
||||
{
|
||||
const unsigned char *s1 = (const unsigned char *)s1_in;
|
||||
const unsigned char *s2 = (const unsigned char *)s2_in;
|
||||
int diff = 0;
|
||||
int k;
|
||||
|
||||
*first_change = 0;
|
||||
for (k=0; s1[k]; k++)
|
||||
if ((diff = (s1[k] - s2[k])))
|
||||
goto found_it;
|
||||
if (!s2[k])
|
||||
return 0;
|
||||
diff = -1;
|
||||
|
||||
found_it:
|
||||
*first_change = k;
|
||||
if (diff > 0)
|
||||
return 1;
|
||||
else if (diff < 0)
|
||||
return -1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Do we have another file with a pathname that is a proper
|
||||
* subset of the name we're trying to add?
|
||||
@@ -905,6 +933,21 @@ static int has_dir_name(struct index_state *istate,
|
||||
int stage = ce_stage(ce);
|
||||
const char *name = ce->name;
|
||||
const char *slash = name + ce_namelen(ce);
|
||||
int len_eq_last;
|
||||
int cmp_last = 0;
|
||||
|
||||
if (istate->cache_nr > 0) {
|
||||
/*
|
||||
* Compare the entry's full path with the last path in the index.
|
||||
* If it sorts AFTER the last entry in the index and they have no
|
||||
* common prefix, then there cannot be any F/D name conflicts.
|
||||
*/
|
||||
cmp_last = strcmp_offset(name,
|
||||
istate->cache[istate->cache_nr-1]->name,
|
||||
&len_eq_last);
|
||||
if (cmp_last > 0 && len_eq_last == 0)
|
||||
return retval;
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
int len;
|
||||
@@ -917,6 +960,24 @@ static int has_dir_name(struct index_state *istate,
|
||||
}
|
||||
len = slash - name;
|
||||
|
||||
if (cmp_last > 0) {
|
||||
/*
|
||||
* If this part of the directory prefix (including the trailing
|
||||
* slash) already appears in the path of the last entry in the
|
||||
* index, then we cannot also have a file with this prefix (or
|
||||
* any parent directory prefix).
|
||||
*/
|
||||
if (len+1 <= len_eq_last)
|
||||
return retval;
|
||||
/*
|
||||
* If this part of the directory prefix (excluding the trailing
|
||||
* slash) is longer than the known equal portions, then this part
|
||||
* of the prefix cannot collide with a file. Go on to the parent.
|
||||
*/
|
||||
if (len > len_eq_last)
|
||||
continue;
|
||||
}
|
||||
|
||||
pos = index_name_stage_pos(istate, name, len, stage);
|
||||
if (pos >= 0) {
|
||||
/*
|
||||
@@ -1008,7 +1069,16 @@ static int add_index_entry_with_check(struct index_state *istate, struct cache_e
|
||||
|
||||
if (!(option & ADD_CACHE_KEEP_CACHE_TREE))
|
||||
cache_tree_invalidate_path(istate, ce->name);
|
||||
pos = index_name_stage_pos(istate, ce->name, ce_namelen(ce), ce_stage(ce));
|
||||
|
||||
/*
|
||||
* If this entry's path sorts after the last entry in the index,
|
||||
* we can avoid searching for it.
|
||||
*/
|
||||
if (istate->cache_nr > 0 &&
|
||||
strcmp(ce->name, istate->cache[istate->cache_nr - 1]->name) > 0)
|
||||
pos = -istate->cache_nr - 1;
|
||||
else
|
||||
pos = index_name_stage_pos(istate, ce->name, ce_namelen(ce), ce_stage(ce));
|
||||
|
||||
/* existing match? Just replace it. */
|
||||
if (pos >= 0) {
|
||||
|
||||
Reference in New Issue
Block a user