merge: Use `git_index__fill` to populate the index Instead of calling `git_index_add` in a loop, use the new `git_index_fill` internal API to fill the index with the initial staged entries. The new `fill` helper assumes that all the entries will be unique and valid, so it can append them at the end of the entries vector and only sort it once at the end. It performs no validation checks. This prevents the quadratic behavior caused by having to sort the entries list once after every insertion.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86
diff --git a/src/index.c b/src/index.c
index 26cd838..60e4d44 100644
--- a/src/index.c
+++ b/src/index.c
@@ -1542,6 +1542,43 @@ int git_index_remove_bypath(git_index *index, const char *path)
return 0;
}
+int git_index__fill(git_index *index, const git_vector *source_entries)
+{
+ const git_index_entry *source_entry = NULL;
+ size_t i;
+ int ret = 0;
+
+ assert(index);
+
+ if (git_mutex_lock(&index->lock) < 0) {
+ giterr_set(GITERR_OS, "Unable to acquire index lock");
+ return -1;
+ }
+
+ git_vector_foreach(source_entries, i, source_entry) {
+ git_index_entry *entry = NULL;
+
+ if ((ret = index_entry_dup(&entry, index, source_entry)) < 0)
+ break;
+
+ entry->flags_extended |= GIT_IDXENTRY_UPTODATE;
+
+ ret = git_vector_insert(&index->entries, entry);
+ if (ret < 0)
+ break;
+
+ INSERT_IN_MAP(index, entry, ret);
+ if (ret < 0)
+ break;
+ }
+
+ if (!ret)
+ git_vector_sort(&index->entries);
+
+ git_mutex_unlock(&index->lock);
+ return ret;
+}
+
int git_index_add(git_index *index, const git_index_entry *source_entry)
{
diff --git a/src/index.h b/src/index.h
index 9baf976..0909da8 100644
--- a/src/index.h
+++ b/src/index.h
@@ -113,6 +113,8 @@ GIT_INLINE(bool) git_index_entry_newer_than_index(
extern int git_index__find_pos(
size_t *at_pos, git_index *index, const char *path, size_t path_len, int stage);
+extern int git_index__fill(git_index *index, const git_vector *source_entries);
+
extern void git_index__set_ignore_case(git_index *index, bool ignore_case);
extern unsigned int git_index__create_mode(unsigned int mode);
diff --git a/src/merge.c b/src/merge.c
index 9eb3b09..61ff93c 100644
--- a/src/merge.c
+++ b/src/merge.c
@@ -1739,7 +1739,6 @@ static int index_from_diff_list(git_index **out,
{
git_index *index;
size_t i;
- git_index_entry *entry;
git_merge_diff *conflict;
int error = 0;
@@ -1748,10 +1747,8 @@ static int index_from_diff_list(git_index **out,
if ((error = git_index_new(&index)) < 0)
return error;
- git_vector_foreach(&diff_list->staged, i, entry) {
- if ((error = git_index_add(index, entry)) < 0)
- goto on_error;
- }
+ if ((error = git_index__fill(index, &diff_list->staged)) < 0)
+ goto on_error;
git_vector_foreach(&diff_list->conflicts, i, conflict) {
const git_index_entry *ancestor =