@ -25,6 +25,8 @@
@@ -25,6 +25,8 @@
#include "worktree.h"
#include "argv-array.h"
#include "commit-reach.h"
#include "commit-graph.h"
#include "prio-queue.h"
volatile show_early_output_fn_t show_early_output;
@ -767,8 +769,8 @@ static void commit_list_insert_by_date_cached(struct commit *p, struct commit_li
@@ -767,8 +769,8 @@ static void commit_list_insert_by_date_cached(struct commit *p, struct commit_li
*cache = new_entry;
}
static int add_parents_to_list(struct rev_info *revs, struct commit *commit,
struct commit_list **list, struct commit_list **cache_ptr)
static int process_parents(struct rev_info *revs, struct commit *commit,
struct commit_list **list, struct commit_list **cache_ptr)
{
struct commit_list *parent = commit->parents;
unsigned left_flag;
@ -807,7 +809,8 @@ static int add_parents_to_list(struct rev_info *revs, struct commit *commit,
@@ -807,7 +809,8 @@ static int add_parents_to_list(struct rev_info *revs, struct commit *commit,
if (p->object.flags & SEEN)
continue;
p->object.flags |= SEEN;
commit_list_insert_by_date_cached(p, list, cached_base, cache_ptr);
if (list)
commit_list_insert_by_date_cached(p, list, cached_base, cache_ptr);
}
return 0;
}
@ -846,7 +849,8 @@ static int add_parents_to_list(struct rev_info *revs, struct commit *commit,
@@ -846,7 +849,8 @@ static int add_parents_to_list(struct rev_info *revs, struct commit *commit,
p->object.flags |= left_flag;
if (!(p->object.flags & SEEN)) {
p->object.flags |= SEEN;
commit_list_insert_by_date_cached(p, list, cached_base, cache_ptr);
if (list)
commit_list_insert_by_date_cached(p, list, cached_base, cache_ptr);
}
if (revs->first_parent_only)
break;
@ -1090,7 +1094,7 @@ static int limit_list(struct rev_info *revs)
@@ -1090,7 +1094,7 @@ static int limit_list(struct rev_info *revs)
if (revs->max_age != -1 && (commit->date < revs->max_age))
obj->flags |= UNINTERESTING;
if (add_parents_to_list(revs, commit, &list, NULL) < 0)
if (process_parents(revs, commit, &list, NULL) < 0)
return -1;
if (obj->flags & UNINTERESTING) {
mark_parents_uninteresting(commit);
@ -2468,7 +2472,7 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, struct s
@@ -2468,7 +2472,7 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, struct s
if (revs->diffopt.objfind)
revs->simplify_history = 0;
if (revs->topo_order)
if (revs->topo_order && !generation_numbers_enabled(the_repository))
revs->limited = 1;
if (revs->prune_data.nr) {
@ -2907,6 +2911,217 @@ static int mark_uninteresting(const struct object_id *oid,
@@ -2907,6 +2911,217 @@ static int mark_uninteresting(const struct object_id *oid,
return 0;
}
define_commit_slab(indegree_slab, int);
define_commit_slab(author_date_slab, timestamp_t);
struct topo_walk_info {
uint32_t min_generation;
struct prio_queue explore_queue;
struct prio_queue indegree_queue;
struct prio_queue topo_queue;
struct indegree_slab indegree;
struct author_date_slab author_date;
};
static inline void test_flag_and_insert(struct prio_queue *q, struct commit *c, int flag)
{
if (c->object.flags & flag)
return;
c->object.flags |= flag;
prio_queue_put(q, c);
}
static void explore_walk_step(struct rev_info *revs)
{
struct topo_walk_info *info = revs->topo_walk_info;
struct commit_list *p;
struct commit *c = prio_queue_get(&info->explore_queue);
if (!c)
return;
if (parse_commit_gently(c, 1) < 0)
return;
if (revs->sort_order == REV_SORT_BY_AUTHOR_DATE)
record_author_date(&info->author_date, c);
if (revs->max_age != -1 && (c->date < revs->max_age))
c->object.flags |= UNINTERESTING;
if (process_parents(revs, c, NULL, NULL) < 0)
return;
if (c->object.flags & UNINTERESTING)
mark_parents_uninteresting(c);
for (p = c->parents; p; p = p->next)
test_flag_and_insert(&info->explore_queue, p->item, TOPO_WALK_EXPLORED);
}
static void explore_to_depth(struct rev_info *revs,
uint32_t gen_cutoff)
{
struct topo_walk_info *info = revs->topo_walk_info;
struct commit *c;
while ((c = prio_queue_peek(&info->explore_queue)) &&
c->generation >= gen_cutoff)
explore_walk_step(revs);
}
static void indegree_walk_step(struct rev_info *revs)
{
struct commit_list *p;
struct topo_walk_info *info = revs->topo_walk_info;
struct commit *c = prio_queue_get(&info->indegree_queue);
if (!c)
return;
if (parse_commit_gently(c, 1) < 0)
return;
explore_to_depth(revs, c->generation);
for (p = c->parents; p; p = p->next) {
struct commit *parent = p->item;
int *pi = indegree_slab_at(&info->indegree, parent);
if (*pi)
(*pi)++;
else
*pi = 2;
test_flag_and_insert(&info->indegree_queue, parent, TOPO_WALK_INDEGREE);
if (revs->first_parent_only)
return;
}
}
static void compute_indegrees_to_depth(struct rev_info *revs,
uint32_t gen_cutoff)
{
struct topo_walk_info *info = revs->topo_walk_info;
struct commit *c;
while ((c = prio_queue_peek(&info->indegree_queue)) &&
c->generation >= gen_cutoff)
indegree_walk_step(revs);
}
static void init_topo_walk(struct rev_info *revs)
{
struct topo_walk_info *info;
struct commit_list *list;
revs->topo_walk_info = xmalloc(sizeof(struct topo_walk_info));
info = revs->topo_walk_info;
memset(info, 0, sizeof(struct topo_walk_info));
init_indegree_slab(&info->indegree);
memset(&info->explore_queue, 0, sizeof(info->explore_queue));
memset(&info->indegree_queue, 0, sizeof(info->indegree_queue));
memset(&info->topo_queue, 0, sizeof(info->topo_queue));
switch (revs->sort_order) {
default: /* REV_SORT_IN_GRAPH_ORDER */
info->topo_queue.compare = NULL;
break;
case REV_SORT_BY_COMMIT_DATE:
info->topo_queue.compare = compare_commits_by_commit_date;
break;
case REV_SORT_BY_AUTHOR_DATE:
init_author_date_slab(&info->author_date);
info->topo_queue.compare = compare_commits_by_author_date;
info->topo_queue.cb_data = &info->author_date;
break;
}
info->explore_queue.compare = compare_commits_by_gen_then_commit_date;
info->indegree_queue.compare = compare_commits_by_gen_then_commit_date;
info->min_generation = GENERATION_NUMBER_INFINITY;
for (list = revs->commits; list; list = list->next) {
struct commit *c = list->item;
if (parse_commit_gently(c, 1))
continue;
test_flag_and_insert(&info->explore_queue, c, TOPO_WALK_EXPLORED);
test_flag_and_insert(&info->indegree_queue, c, TOPO_WALK_INDEGREE);
if (c->generation < info->min_generation)
info->min_generation = c->generation;
*(indegree_slab_at(&info->indegree, c)) = 1;
if (revs->sort_order == REV_SORT_BY_AUTHOR_DATE)
record_author_date(&info->author_date, c);
}
compute_indegrees_to_depth(revs, info->min_generation);
for (list = revs->commits; list; list = list->next) {
struct commit *c = list->item;
if (*(indegree_slab_at(&info->indegree, c)) == 1)
prio_queue_put(&info->topo_queue, c);
}
/*
* This is unfortunate; the initial tips need to be shown
* in the order given from the revision traversal machinery.
*/
if (revs->sort_order == REV_SORT_IN_GRAPH_ORDER)
prio_queue_reverse(&info->topo_queue);
}
static struct commit *next_topo_commit(struct rev_info *revs)
{
struct commit *c;
struct topo_walk_info *info = revs->topo_walk_info;
/* pop next off of topo_queue */
c = prio_queue_get(&info->topo_queue);
if (c)
*(indegree_slab_at(&info->indegree, c)) = 0;
return c;
}
static void expand_topo_walk(struct rev_info *revs, struct commit *commit)
{
struct commit_list *p;
struct topo_walk_info *info = revs->topo_walk_info;
if (process_parents(revs, commit, NULL, NULL) < 0) {
if (!revs->ignore_missing_links)
die("Failed to traverse parents of commit %s",
oid_to_hex(&commit->object.oid));
}
for (p = commit->parents; p; p = p->next) {
struct commit *parent = p->item;
int *pi;
if (parse_commit_gently(parent, 1) < 0)
continue;
if (parent->generation < info->min_generation) {
info->min_generation = parent->generation;
compute_indegrees_to_depth(revs, info->min_generation);
}
pi = indegree_slab_at(&info->indegree, parent);
(*pi)--;
if (*pi == 1)
prio_queue_put(&info->topo_queue, parent);
if (revs->first_parent_only)
return;
}
}
int prepare_revision_walk(struct rev_info *revs)
{
int i;
@ -2943,11 +3158,13 @@ int prepare_revision_walk(struct rev_info *revs)
@@ -2943,11 +3158,13 @@ int prepare_revision_walk(struct rev_info *revs)
commit_list_sort_by_date(&revs->commits);
if (revs->no_walk)
return 0;
if (revs->limited)
if (revs->limited) {
if (limit_list(revs) < 0)
return -1;
if (revs->topo_order)
sort_in_topological_order(&revs->commits, revs->sort_order);
if (revs->topo_order)
sort_in_topological_order(&revs->commits, revs->sort_order);
} else if (revs->topo_order)
init_topo_walk(revs);
if (revs->line_level_traverse)
line_log_filter(revs);
if (revs->simplify_merges)
@ -2964,7 +3181,7 @@ static enum rewrite_result rewrite_one(struct rev_info *revs, struct commit **pp
@@ -2964,7 +3181,7 @@ static enum rewrite_result rewrite_one(struct rev_info *revs, struct commit **pp
for (;;) {
struct commit *p = *pp;
if (!revs->limited)
if (add_parents_to_list(revs, p, &revs->commits, &cache) < 0)
if (process_parents(revs, p, &revs->commits, &cache) < 0)
return rewrite_one_error;
if (p->object.flags & UNINTERESTING)
return rewrite_one_ok;
@ -3272,6 +3489,8 @@ static struct commit *get_revision_1(struct rev_info *revs)
@@ -3272,6 +3489,8 @@ static struct commit *get_revision_1(struct rev_info *revs)
if (revs->reflog_info)
commit = next_reflog_entry(revs->reflog_info);
else if (revs->topo_walk_info)
commit = next_topo_commit(revs);
else
commit = pop_commit(&revs->commits);
@ -3293,7 +3512,9 @@ static struct commit *get_revision_1(struct rev_info *revs)
@@ -3293,7 +3512,9 @@ static struct commit *get_revision_1(struct rev_info *revs)
if (revs->reflog_info)
try_to_simplify_commit(revs, commit);
else if (add_parents_to_list(revs, commit, &revs->commits, NULL) < 0) {
else if (revs->topo_walk_info)
expand_topo_walk(revs, commit);
else if (process_parents(revs, commit, &revs->commits, NULL) < 0) {
if (!revs->ignore_missing_links)
die("Failed to traverse parents of commit %s",
oid_to_hex(&commit->object.oid));