Skip to content

Commit f0d9cc4

Browse files
derrickstoleegitster
authored andcommitted
revision.c: begin refactoring --topo-order logic
When running 'git rev-list --topo-order' and its kin, the topo_order setting in struct rev_info implies the limited setting. This means that the following things happen during prepare_revision_walk(): * revs->limited implies we run limit_list() to walk the entire reachable set. There are some short-cuts here, such as if we perform a range query like 'git rev-list COMPARE..HEAD' and we can stop limit_list() when all queued commits are uninteresting. * revs->topo_order implies we run sort_in_topological_order(). See the implementation of that method in commit.c. It implies that the full set of commits to order is in the given commit_list. These two methods imply that a 'git rev-list --topo-order HEAD' command must walk the entire reachable set of commits _twice_ before returning a single result. If we have a commit-graph file with generation numbers computed, then there is a better way. This patch introduces some necessary logic redirection when we are in this situation. In v2.18.0, the commit-graph file contains zero-valued bytes in the positions where the generation number is stored in v2.19.0 and later. Thus, we use generation_numbers_enabled() to check if the commit-graph is available and has non-zero generation numbers. When setting revs->limited only because revs->topo_order is true, only do so if generation numbers are not available. There is no reason to use the new logic as it will behave similarly when all generation numbers are INFINITY or ZERO. In prepare_revision_walk(), if we have revs->topo_order but not revs->limited, then we trigger the new logic. It breaks the logic into three pieces, to fit with the existing framework: 1. init_topo_walk() fills a new struct topo_walk_info in the rev_info struct. We use the presence of this struct as a signal to use the new methods during our walk. In this patch, this method simply calls limit_list() and sort_in_topological_order(). In the future, this method will set up a new data structure to perform that logic in-line. 2. next_topo_commit() provides get_revision_1() with the next topo- ordered commit in the list. Currently, this simply pops the commit from revs->commits. 3. expand_topo_walk() provides get_revision_1() with a way to signal walking beyond the latest commit. Currently, this calls add_parents_to_list() exactly like the old logic. While this commit presents method redirection for performing the exact same logic as before, it allows the next commit to focus only on the new logic. Signed-off-by: Derrick Stolee <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent d6b4071 commit f0d9cc4

File tree

2 files changed

+42
-4
lines changed

2 files changed

+42
-4
lines changed

revision.c

Lines changed: 38 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
#include "worktree.h"
2626
#include "argv-array.h"
2727
#include "commit-reach.h"
28+
#include "commit-graph.h"
2829

2930
volatile show_early_output_fn_t show_early_output;
3031

@@ -2454,7 +2455,7 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, struct s
24542455
if (revs->diffopt.objfind)
24552456
revs->simplify_history = 0;
24562457

2457-
if (revs->topo_order)
2458+
if (revs->topo_order && !generation_numbers_enabled(the_repository))
24582459
revs->limited = 1;
24592460

24602461
if (revs->prune_data.nr) {
@@ -2892,6 +2893,33 @@ static int mark_uninteresting(const struct object_id *oid,
28922893
return 0;
28932894
}
28942895

2896+
struct topo_walk_info {};
2897+
2898+
static void init_topo_walk(struct rev_info *revs)
2899+
{
2900+
struct topo_walk_info *info;
2901+
revs->topo_walk_info = xmalloc(sizeof(struct topo_walk_info));
2902+
info = revs->topo_walk_info;
2903+
memset(info, 0, sizeof(struct topo_walk_info));
2904+
2905+
limit_list(revs);
2906+
sort_in_topological_order(&revs->commits, revs->sort_order);
2907+
}
2908+
2909+
static struct commit *next_topo_commit(struct rev_info *revs)
2910+
{
2911+
return pop_commit(&revs->commits);
2912+
}
2913+
2914+
static void expand_topo_walk(struct rev_info *revs, struct commit *commit)
2915+
{
2916+
if (add_parents_to_list(revs, commit, &revs->commits, NULL) < 0) {
2917+
if (!revs->ignore_missing_links)
2918+
die("Failed to traverse parents of commit %s",
2919+
oid_to_hex(&commit->object.oid));
2920+
}
2921+
}
2922+
28952923
int prepare_revision_walk(struct rev_info *revs)
28962924
{
28972925
int i;
@@ -2928,11 +2956,13 @@ int prepare_revision_walk(struct rev_info *revs)
29282956
commit_list_sort_by_date(&revs->commits);
29292957
if (revs->no_walk)
29302958
return 0;
2931-
if (revs->limited)
2959+
if (revs->limited) {
29322960
if (limit_list(revs) < 0)
29332961
return -1;
2934-
if (revs->topo_order)
2935-
sort_in_topological_order(&revs->commits, revs->sort_order);
2962+
if (revs->topo_order)
2963+
sort_in_topological_order(&revs->commits, revs->sort_order);
2964+
} else if (revs->topo_order)
2965+
init_topo_walk(revs);
29362966
if (revs->line_level_traverse)
29372967
line_log_filter(revs);
29382968
if (revs->simplify_merges)
@@ -3257,6 +3287,8 @@ static struct commit *get_revision_1(struct rev_info *revs)
32573287

32583288
if (revs->reflog_info)
32593289
commit = next_reflog_entry(revs->reflog_info);
3290+
else if (revs->topo_walk_info)
3291+
commit = next_topo_commit(revs);
32603292
else
32613293
commit = pop_commit(&revs->commits);
32623294

@@ -3278,6 +3310,8 @@ static struct commit *get_revision_1(struct rev_info *revs)
32783310

32793311
if (revs->reflog_info)
32803312
try_to_simplify_commit(revs, commit);
3313+
else if (revs->topo_walk_info)
3314+
expand_topo_walk(revs, commit);
32813315
else if (add_parents_to_list(revs, commit, &revs->commits, NULL) < 0) {
32823316
if (!revs->ignore_missing_links)
32833317
die("Failed to traverse parents of commit %s",

revision.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,8 @@ struct rev_cmdline_info {
5656
#define REVISION_WALK_NO_WALK_SORTED 1
5757
#define REVISION_WALK_NO_WALK_UNSORTED 2
5858

59+
struct topo_walk_info;
60+
5961
struct rev_info {
6062
/* Starting list */
6163
struct commit_list *commits;
@@ -245,6 +247,8 @@ struct rev_info {
245247
const char *break_bar;
246248

247249
struct revision_sources *sources;
250+
251+
struct topo_walk_info *topo_walk_info;
248252
};
249253

250254
int ref_excluded(struct string_list *, const char *path);

0 commit comments

Comments
 (0)