Commit d307a013 by Vicent Marti

reuc: Be smarter when inserting new REUC entries

Inserting new REUC entries can quickly become pathological given that
each insert unsorts the REUC vector, and both subsequent lookups *and*
insertions will require sorting it again before being successful.

To avoid this, we're switching to `git_vector_insert_sorted`: this keeps
the REUC vector constantly sorted and lets us use the `on_dup` callback
to skip an extra binary search on each insertion.
parent 2382d1bc
...@@ -2000,27 +2000,24 @@ size_t git_index_reuc_entrycount(git_index *index) ...@@ -2000,27 +2000,24 @@ size_t git_index_reuc_entrycount(git_index *index)
return index->reuc.length; return index->reuc.length;
} }
static int index_reuc_on_dup(void **old, void *new)
{
index_entry_reuc_free(*old);
*old = new;
return GIT_EEXISTS;
}
static int index_reuc_insert( static int index_reuc_insert(
git_index *index, git_index *index,
git_index_reuc_entry *reuc, git_index_reuc_entry *reuc)
int replace)
{ {
git_index_reuc_entry **existing = NULL; int res;
size_t position;
assert(index && reuc && reuc->path != NULL); assert(index && reuc && reuc->path != NULL);
assert(git_vector_is_sorted(&index->reuc));
if (!git_index_reuc_find(&position, index, reuc->path)) res = git_vector_insert_sorted(&index->reuc, reuc, &index_reuc_on_dup);
existing = (git_index_reuc_entry **)&index->reuc.contents[position]; return res == GIT_EEXISTS ? 0 : res;
if (!replace || !existing)
return git_vector_insert(&index->reuc, reuc);
/* exists, replace it */
git__free(*existing);
*existing = reuc;
return 0;
} }
int git_index_reuc_add(git_index *index, const char *path, int git_index_reuc_add(git_index *index, const char *path,
...@@ -2035,7 +2032,7 @@ int git_index_reuc_add(git_index *index, const char *path, ...@@ -2035,7 +2032,7 @@ int git_index_reuc_add(git_index *index, const char *path,
if ((error = index_entry_reuc_init(&reuc, path, ancestor_mode, if ((error = index_entry_reuc_init(&reuc, path, ancestor_mode,
ancestor_oid, our_mode, our_oid, their_mode, their_oid)) < 0 || ancestor_oid, our_mode, our_oid, their_mode, their_oid)) < 0 ||
(error = index_reuc_insert(index, reuc, 1)) < 0) (error = index_reuc_insert(index, reuc)) < 0)
index_entry_reuc_free(reuc); index_entry_reuc_free(reuc);
return error; return error;
...@@ -2055,7 +2052,7 @@ const git_index_reuc_entry *git_index_reuc_get_bypath( ...@@ -2055,7 +2052,7 @@ const git_index_reuc_entry *git_index_reuc_get_bypath(
if (!index->reuc.length) if (!index->reuc.length)
return NULL; return NULL;
git_vector_sort(&index->reuc); assert(git_vector_is_sorted(&index->reuc));
if (git_index_reuc_find(&pos, index, path) < 0) if (git_index_reuc_find(&pos, index, path) < 0)
return NULL; return NULL;
...@@ -2067,8 +2064,8 @@ const git_index_reuc_entry *git_index_reuc_get_byindex( ...@@ -2067,8 +2064,8 @@ const git_index_reuc_entry *git_index_reuc_get_byindex(
git_index *index, size_t n) git_index *index, size_t n)
{ {
assert(index); assert(index);
assert(git_vector_is_sorted(&index->reuc));
git_vector_sort(&index->reuc);
return git_vector_get(&index->reuc, n); return git_vector_get(&index->reuc, n);
} }
...@@ -2077,7 +2074,7 @@ int git_index_reuc_remove(git_index *index, size_t position) ...@@ -2077,7 +2074,7 @@ int git_index_reuc_remove(git_index *index, size_t position)
int error; int error;
git_index_reuc_entry *reuc; git_index_reuc_entry *reuc;
git_vector_sort(&index->reuc); assert(git_vector_is_sorted(&index->reuc));
reuc = git_vector_get(&index->reuc, position); reuc = git_vector_get(&index->reuc, position);
error = git_vector_remove(&index->reuc, position); error = git_vector_remove(&index->reuc, position);
......
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