avoid tips temp copy in fetch_commits_from_open_branches()
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 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182
diff --git a/lib/commit_graph.c b/lib/commit_graph.c
index 0165b20..ece10ad 100644
--- a/lib/commit_graph.c
+++ b/lib/commit_graph.c
@@ -36,6 +36,10 @@
#include "got_lib_object_idset.h"
#include "got_lib_path.h"
+#ifndef MIN
+#define MIN(_a,_b) ((_a) < (_b) ? (_a) : (_b))
+#endif
+
struct got_commit_graph_node {
struct got_object_id id;
@@ -56,8 +60,11 @@ struct got_commit_graph_node {
TAILQ_HEAD(got_commit_graph_iter_list, got_commit_graph_node);
struct got_commit_graph_branch_tip {
- struct got_object_id id;
- struct got_commit_graph_node *node;
+ struct got_object_id *commit_id;
+ struct got_commit_object *commit;
+ struct got_commit_graph_node *new_node;
+ int changed;
+ int branch_done;
};
struct got_commit_graph {
@@ -87,7 +94,7 @@ struct got_commit_graph {
*/
struct got_object_idset *open_branches;
- /* Copy of known branch tips for fetch_commits_from_open_branches(). */
+ /* Array of branch tips for fetch_commits_from_open_branches(). */
struct got_commit_graph_branch_tip *tips;
size_t ntips;
#define GOT_COMMIT_GRAPH_MIN_TIPS 10 /* minimum amount of tips to allocate */
@@ -485,87 +492,103 @@ got_commit_graph_open(struct got_commit_graph **graph,
return NULL;
}
-struct gather_branch_tips_arg {
+struct add_branch_tip_arg {
struct got_commit_graph_branch_tip *tips;
int ntips;
+ struct got_repository *repo;
+ struct got_commit_graph *graph;
};
static const struct got_error *
-gather_branch_tips(struct got_object_id *id, void *data, void *arg)
+add_branch_tip(struct got_object_id *commit_id, void *data, void *arg)
{
- struct gather_branch_tips_arg *a = arg;
- memcpy(&a->tips[a->ntips].id, id, sizeof(*id));
- a->tips[a->ntips].node = data;
+ const struct got_error *err;
+ struct got_commit_graph_node *child_node = data;
+ struct add_branch_tip_arg *a = arg;
+ struct got_commit_graph_node *new_node;
+ struct got_commit_object *commit;
+ int changed, branch_done;
+
+ err = got_object_open_as_commit(&commit, a->repo, commit_id);
+ if (err)
+ return err;
+
+ err = add_node(&new_node, &changed, &branch_done, a->graph,
+ commit_id, commit, child_node, a->repo);
+ if (err)
+ return err;
+
+ a->tips[a->ntips].commit_id = new_node ? &new_node->id : NULL;
+ a->tips[a->ntips].commit = commit;
+ a->tips[a->ntips].new_node = new_node;
+ a->tips[a->ntips].changed = changed;
+ a->tips[a->ntips].branch_done = branch_done;
a->ntips++;
+
return NULL;
}
static const struct got_error *
-fetch_commits_from_open_branches(int *ncommits,
+fetch_commits_from_open_branches(int *nfetched,
struct got_object_id **changed_id, struct got_commit_graph *graph,
struct got_repository *repo)
{
const struct got_error *err;
- struct gather_branch_tips_arg arg;
- int i;
+ struct add_branch_tip_arg arg;
+ int i, ntips;
- *ncommits = 0;
+ *nfetched = 0;
*changed_id = NULL;
- arg.ntips = got_object_idset_num_elements(graph->open_branches);
- if (arg.ntips == 0)
+ ntips = got_object_idset_num_elements(graph->open_branches);
+ if (ntips == 0)
return NULL;
- /*
- * Adding nodes to the graph might change the graph's open
- * branches state. Create a local copy of the current state.
- */
- if (graph->ntips < arg.ntips) {
+ /* (Re-)allocate branch tips array if necessary. */
+ if (graph->ntips < ntips) {
struct got_commit_graph_branch_tip *tips;
- if (arg.ntips < GOT_COMMIT_GRAPH_MIN_TIPS)
- arg.ntips = GOT_COMMIT_GRAPH_MIN_TIPS;
- tips = reallocarray(graph->tips, arg.ntips, sizeof(*tips));
+ tips = reallocarray(graph->tips,
+ MIN(ntips, GOT_COMMIT_GRAPH_MIN_TIPS), sizeof(*tips));
if (tips == NULL)
return got_error_from_errno();
graph->tips = tips;
- graph->ntips = arg.ntips;
+ graph->ntips = ntips;
}
- arg.ntips = 0; /* reset; gather_branch_tips() will increment */
arg.tips = graph->tips;
- err = got_object_idset_for_each(graph->open_branches,
- gather_branch_tips, &arg);
+ arg.ntips = 0; /* add_branch_tip() will increment */
+ arg.repo = repo;
+ arg.graph = graph;
+ err = got_object_idset_for_each(graph->open_branches, add_branch_tip,
+ &arg);
if (err)
- return err;
+ goto done;
for (i = 0; i < arg.ntips; i++) {
struct got_object_id *commit_id;
- struct got_commit_graph_node *child_node, *new_node;
struct got_commit_object *commit;
- int changed, branch_done;
-
- commit_id = &graph->tips[i].id;
- child_node = graph->tips[i].node;
+ struct got_commit_graph_node *new_node;
+ int branch_done, changed;
- err = got_object_open_as_commit(&commit, repo, commit_id);
- if (err)
- break;
+ commit_id = arg.tips[i].commit_id;
+ commit = arg.tips[i].commit;
+ new_node = arg.tips[i].new_node;
+ branch_done = arg.tips[i].branch_done;
+ changed = arg.tips[i].changed;
- err = add_node(&new_node, &changed, &branch_done, graph,
- commit_id, commit, child_node, repo);
if (branch_done)
err = close_branch(graph, commit_id);
else
err = advance_branch(graph, new_node, commit_id,
commit, repo);
- if (changed && *changed_id == NULL)
- *changed_id = commit_id;
- got_object_commit_close(commit);
if (err)
break;
- if (new_node)
- (*ncommits)++;
+ if (changed && *changed_id == NULL)
+ *changed_id = commit_id;
}
-
+done:
+ for (i = 0; i < ntips; i++)
+ got_object_commit_close(arg.tips[i].commit);
+ (*nfetched) = arg.ntips;
return err;
}