Commit 06b6d81b authored by Jeff Hostetler's avatar Jeff Hostetler Committed by Junio C Hamano

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: default avatarJeff Hostetler <>
Signed-off-by: default avatarJunio C Hamano <>
parent e5494631
......@@ -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
* 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,
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);
const char *name = ce->name;
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,
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 (;;) {
int len;
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment