read-cache: speed up has_dir_name (part 1)
Teach 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. has_dir_name() is looking for file/directory collisions in the index and has to consider each sub-directory prefix in turn. This can cause multiple binary searches for each path. During operations like checkout, merge_working_tree() populates the new index in sorted order, so we expect to be able to append in many cases. This commit is part 1 of 2. This commit handles the top of has_dir_name() and the trivial optimization. Signed-off-by: Jeff Hostetler <jeffhost@microsoft.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
parent
e5494631ed
commit
06b6d81b79
45
read-cache.c
45
read-cache.c
@ -910,6 +910,9 @@ int strcmp_offset(const char *s1, const char *s2, size_t *first_change)
|
|||||||
/*
|
/*
|
||||||
* Do we have another file with a pathname that is a proper
|
* Do we have another file with a pathname that is a proper
|
||||||
* subset of the name we're trying to add?
|
* subset of the name we're trying to add?
|
||||||
|
*
|
||||||
|
* That is, is there another file in the index with a path
|
||||||
|
* that matches a sub-directory in the given entry?
|
||||||
*/
|
*/
|
||||||
static int has_dir_name(struct index_state *istate,
|
static int has_dir_name(struct index_state *istate,
|
||||||
const struct cache_entry *ce, int pos, int ok_to_replace)
|
const struct cache_entry *ce, int pos, int ok_to_replace)
|
||||||
@ -918,6 +921,48 @@ static int has_dir_name(struct index_state *istate,
|
|||||||
int stage = ce_stage(ce);
|
int stage = ce_stage(ce);
|
||||||
const char *name = ce->name;
|
const char *name = ce->name;
|
||||||
const char *slash = name + ce_namelen(ce);
|
const char *slash = name + ce_namelen(ce);
|
||||||
|
size_t len_eq_last;
|
||||||
|
int cmp_last = 0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We are frequently called during an iteration on a sorted
|
||||||
|
* list of pathnames and while building a new index. Therefore,
|
||||||
|
* there is a high probability that this entry will eventually
|
||||||
|
* be appended to the index, rather than inserted in the middle.
|
||||||
|
* If we can confirm that, we can avoid binary searches on the
|
||||||
|
* components of the pathname.
|
||||||
|
*
|
||||||
|
* Compare the entry's full path with the last path in the index.
|
||||||
|
*/
|
||||||
|
if (istate->cache_nr > 0) {
|
||||||
|
cmp_last = strcmp_offset(name,
|
||||||
|
istate->cache[istate->cache_nr - 1]->name,
|
||||||
|
&len_eq_last);
|
||||||
|
if (cmp_last > 0) {
|
||||||
|
if (len_eq_last == 0) {
|
||||||
|
/*
|
||||||
|
* The entry sorts AFTER the last one in the
|
||||||
|
* index and their paths have no common prefix,
|
||||||
|
* so there cannot be a F/D conflict.
|
||||||
|
*/
|
||||||
|
return retval;
|
||||||
|
} else {
|
||||||
|
/*
|
||||||
|
* The entry sorts AFTER the last one in the
|
||||||
|
* index, but has a common prefix. Fall through
|
||||||
|
* to the loop below to disect the entry's path
|
||||||
|
* and see where the difference is.
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
} else if (cmp_last == 0) {
|
||||||
|
/*
|
||||||
|
* The entry exactly matches the last one in the
|
||||||
|
* index, but because of multiple stage and CE_REMOVE
|
||||||
|
* items, we fall through and let the regular search
|
||||||
|
* code handle it.
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
int len;
|
int len;
|
||||||
|
Loading…
Reference in New Issue
Block a user