38
#define GRAPH_MIN_SIZE (5 * GRAPH_CHUNKLOOKUP_WIDTH + GRAPH_FANOUT_SIZE + \
39
GRAPH_OID_LEN + 8)
40
41
-
41
char *get_commit_graph_filename(const char *obj_dir)
42
{
43
return xstrfmt("%s/info/commit-graph", obj_dir);
178
exit(1);
179
}
180
181
+/* global storage */
182
+static struct commit_graph *commit_graph = NULL;
183
+
184
+static void prepare_commit_graph_one(const char *obj_dir)
185
+{
186
+ char *graph_name;
187
+
188
+ if (commit_graph)
189
+ return;
190
+
191
+ graph_name = get_commit_graph_filename(obj_dir);
192
+ commit_graph = load_commit_graph_one(graph_name);
193
+
194
+ FREE_AND_NULL(graph_name);
195
+}
196
+
197
+static int prepare_commit_graph_run_once = 0;
198
+static void prepare_commit_graph(void)
199
+{
200
+ struct alternate_object_database *alt;
201
+ char *obj_dir;
202
+
203
+ if (prepare_commit_graph_run_once)
204
+ return;
205
+ prepare_commit_graph_run_once = 1;
206
+
207
+ obj_dir = get_object_directory();
208
+ prepare_commit_graph_one(obj_dir);
209
+ prepare_alt_odb();
210
+ for (alt = alt_odb_list; !commit_graph && alt; alt = alt->next)
211
+ prepare_commit_graph_one(alt->path);
212
+}
213
+
214
+static void close_commit_graph(void)
215
+{
216
+ if (!commit_graph)
217
+ return;
218
+
219
+ if (commit_graph->graph_fd >= 0) {
220
+ munmap((void *)commit_graph->data, commit_graph->data_len);
221
+ commit_graph->data = NULL;
222
+ close(commit_graph->graph_fd);
223
+ }
224
+
225
+ FREE_AND_NULL(commit_graph);
226
+}
227
+
228
+static int bsearch_graph(struct commit_graph *g, struct object_id *oid, uint32_t *pos)
229
+{
230
+ return bsearch_hash(oid->hash, g->chunk_oid_fanout,
231
+ g->chunk_oid_lookup, g->hash_len, pos);
232
+}
233
+
234
+static struct commit_list **insert_parent_or_die(struct commit_graph *g,
235
+ uint64_t pos,
236
+ struct commit_list **pptr)
237
+{
238
+ struct commit *c;
239
+ struct object_id oid;
240
+ hashcpy(oid.hash, g->chunk_oid_lookup + g->hash_len * pos);
241
+ c = lookup_commit(&oid);
242
+ if (!c)
243
+ die("could not find commit %s", oid_to_hex(&oid));
244
+ c->graph_pos = pos;
245
+ return &commit_list_insert(c, pptr)->next;
246
+}
247
+
248
+static int fill_commit_in_graph(struct commit *item, struct commit_graph *g, uint32_t pos)
249
+{
250
+ struct object_id oid;
251
+ uint32_t edge_value;
252
+ uint32_t *parent_data_ptr;
253
+ uint64_t date_low, date_high;
254
+ struct commit_list **pptr;
255
+ const unsigned char *commit_data = g->chunk_commit_data + (g->hash_len + 16) * pos;
256
+
257
+ item->object.parsed = 1;
258
+ item->graph_pos = pos;
259
+
260
+ hashcpy(oid.hash, commit_data);
261
+ item->tree = lookup_tree(&oid);
262
+
263
+ date_high = get_be32(commit_data + g->hash_len + 8) & 0x3;
264
+ date_low = get_be32(commit_data + g->hash_len + 12);
265
+ item->date = (timestamp_t)((date_high << 32) | date_low);
266
+
267
+ pptr = &item->parents;
268
+
269
+ edge_value = get_be32(commit_data + g->hash_len);
270
+ if (edge_value == GRAPH_PARENT_NONE)
271
+ return 1;
272
+ pptr = insert_parent_or_die(g, edge_value, pptr);
273
+
274
+ edge_value = get_be32(commit_data + g->hash_len + 4);
275
+ if (edge_value == GRAPH_PARENT_NONE)
276
+ return 1;
277
+ if (!(edge_value & GRAPH_OCTOPUS_EDGES_NEEDED)) {
278
+ pptr = insert_parent_or_die(g, edge_value, pptr);
279
+ return 1;
280
+ }
281
+
282
+ parent_data_ptr = (uint32_t*)(g->chunk_large_edges +
283
+ 4 * (uint64_t)(edge_value & GRAPH_EDGE_LAST_MASK));
284
+ do {
285
+ edge_value = get_be32(parent_data_ptr);
286
+ pptr = insert_parent_or_die(g,
287
+ edge_value & GRAPH_EDGE_LAST_MASK,
288
+ pptr);
289
+ parent_data_ptr++;
290
+ } while (!(edge_value & GRAPH_LAST_EDGE));
291
+
292
+ return 1;
293
+}
294
+
295
+int parse_commit_in_graph(struct commit *item)
296
+{
297
+ if (!core_commit_graph)
298
+ return 0;
299
+ if (item->object.parsed)
300
+ return 1;
301
+
302
+ prepare_commit_graph();
303
+ if (commit_graph) {
304
+ uint32_t pos;
305
+ int found;
306
+ if (item->graph_pos != COMMIT_NOT_FROM_GRAPH) {
307
+ pos = item->graph_pos;
308
+ found = 1;
309
+ } else {
310
+ found = bsearch_graph(commit_graph, &(item->object.oid), &pos);
311
+ }
312
+
313
+ if (found)
314
+ return fill_commit_in_graph(item, commit_graph, pos);
315
+ }
316
+
317
+ return 0;
318
+}
319
+
320
static void write_graph_chunk_fanout(struct hashfile *f,
321
struct commit **commits,
322
int nr_commits)
668
write_graph_chunk_data(f, GRAPH_OID_LEN, commits.list, commits.nr);
669
write_graph_chunk_large_edges(f, commits.list, commits.nr);
670
671
+ close_commit_graph();
672
finalize_hashfile(f, NULL, CSUM_HASH_IN_STREAM | CSUM_FSYNC);
673
commit_lock_file(&lk);
674