@@ -179,10 +179,13 @@ static int remove_redundant(struct repository *r, struct commit **array, int cnt
* the array, and return the number of commits that
* are independent from each other.
*/
- int i, count_non_stale = 0;
+ int i, count_non_stale = 0, count_still_independent = cnt;
timestamp_t min_generation = GENERATION_NUMBER_INFINITY;
struct commit **dup;
- struct prio_queue queue = { compare_commits_by_gen_then_commit_date };
+ struct commit **walk_start;
+ size_t walk_start_nr = 0, walk_start_alloc = cnt;
+
+ ALLOC_ARRAY(walk_start, walk_start_alloc);
/* Mark all parents of the input as STALE */
for (i = 0; i < cnt; i++) {
@@ -190,13 +193,15 @@ static int remove_redundant(struct repository *r, struct commit **array, int cnt
timestamp_t generation;
repo_parse_commit(r, array[i]);
+ array[i]->object.flags |= RESULT;
parents = array[i]->parents;
while (parents) {
repo_parse_commit(r, parents->item);
if (!(parents->item->object.flags & STALE)) {
parents->item->object.flags |= STALE;
- prio_queue_put(&queue, parents->item);
+ ALLOC_GROW(walk_start, walk_start_nr + 1, walk_start_alloc);
+ walk_start[walk_start_nr++] = parents->item;
}
parents = parents->next;
}
@@ -207,30 +212,65 @@ static int remove_redundant(struct repository *r, struct commit **array, int cnt
min_generation = generation;
}
- /* push the STALE bits up to min generation */
- while (queue.nr) {
- struct commit_list *parents;
- struct commit *c = prio_queue_get(&queue);
+ QSORT(walk_start, walk_start_nr, compare_commits_by_gen);
- repo_parse_commit(r, c);
+ /* remove STALE bit for now to allow walking through parents */
+ for (i = 0; i < walk_start_nr; i++)
+ walk_start[i]->object.flags &= ~STALE;
- if (commit_graph_generation(c) < min_generation)
- continue;
+ /*
+ * Start walking from the highest generation. Hopefully, it will
+ * find all other items during the first-parent walk, and we can
+ * terminate early. Otherwise, we will do the same amount of work
+ * as before.
+ */
+ for (i = walk_start_nr - 1; i >= 0 && count_still_independent > 1; i--) {
+ /* push the STALE bits up to min generation */
+ struct commit_list *stack = NULL;
- parents = c->parents;
- while (parents) {
- if (!(parents->item->object.flags & STALE)) {
- parents->item->object.flags |= STALE;
- prio_queue_put(&queue, parents->item);
+ commit_list_insert(walk_start[i], &stack);
+ walk_start[i]->object.flags |= STALE;
+
+ while (stack) {
+ struct commit_list *parents;
+ struct commit *c = stack->item;
+
+ repo_parse_commit(r, c);
+
+ if (c->object.flags & RESULT) {
+ c->object.flags &= ~RESULT;
+ if (--count_still_independent <= 1)
+ break;
}
- parents = parents->next;
+
+ if (commit_graph_generation(c) < min_generation) {
+ pop_commit(&stack);
+ continue;
+ }
+
+ parents = c->parents;
+ while (parents) {
+ if (!(parents->item->object.flags & STALE)) {
+ parents->item->object.flags |= STALE;
+ commit_list_insert(parents->item, &stack);
+ break;
+ }
+ parents = parents->next;
+ }
+
+ /* pop if all parents have been visited already */
+ if (!parents)
+ pop_commit(&stack);
}
+ free_commit_list(stack);
}
+ free(walk_start);
/* rearrange array */
dup = xcalloc(cnt, sizeof(struct commit *));
COPY_ARRAY(dup, array, cnt);
for (i = 0; i < cnt; i++) {
+ dup[i]->object.flags &= ~RESULT;
if (dup[i]->object.flags & STALE) {
int insert = cnt - 1 - (i - count_non_stale);
array[insert] = dup[i];