commit.cocci: refactor code, avoid double rewrite
[git] / commit-graph.c
1 #include "cache.h"
2 #include "config.h"
3 #include "dir.h"
4 #include "git-compat-util.h"
5 #include "lockfile.h"
6 #include "pack.h"
7 #include "packfile.h"
8 #include "commit.h"
9 #include "object.h"
10 #include "refs.h"
11 #include "revision.h"
12 #include "sha1-lookup.h"
13 #include "commit-graph.h"
14 #include "object-store.h"
15 #include "alloc.h"
16 #include "hashmap.h"
17 #include "replace-object.h"
18 #include "progress.h"
19
20 #define GRAPH_SIGNATURE 0x43475048 /* "CGPH" */
21 #define GRAPH_CHUNKID_OIDFANOUT 0x4f494446 /* "OIDF" */
22 #define GRAPH_CHUNKID_OIDLOOKUP 0x4f49444c /* "OIDL" */
23 #define GRAPH_CHUNKID_DATA 0x43444154 /* "CDAT" */
24 #define GRAPH_CHUNKID_EXTRAEDGES 0x45444745 /* "EDGE" */
25
26 #define GRAPH_DATA_WIDTH (the_hash_algo->rawsz + 16)
27
28 #define GRAPH_VERSION_1 0x1
29 #define GRAPH_VERSION GRAPH_VERSION_1
30
31 #define GRAPH_EXTRA_EDGES_NEEDED 0x80000000
32 #define GRAPH_EDGE_LAST_MASK 0x7fffffff
33 #define GRAPH_PARENT_NONE 0x70000000
34
35 #define GRAPH_LAST_EDGE 0x80000000
36
37 #define GRAPH_HEADER_SIZE 8
38 #define GRAPH_FANOUT_SIZE (4 * 256)
39 #define GRAPH_CHUNKLOOKUP_WIDTH 12
40 #define GRAPH_MIN_SIZE (GRAPH_HEADER_SIZE + 4 * GRAPH_CHUNKLOOKUP_WIDTH \
41                         + GRAPH_FANOUT_SIZE + the_hash_algo->rawsz)
42
43 char *get_commit_graph_filename(const char *obj_dir)
44 {
45         return xstrfmt("%s/info/commit-graph", obj_dir);
46 }
47
48 static uint8_t oid_version(void)
49 {
50         return 1;
51 }
52
53 static struct commit_graph *alloc_commit_graph(void)
54 {
55         struct commit_graph *g = xcalloc(1, sizeof(*g));
56         g->graph_fd = -1;
57
58         return g;
59 }
60
61 extern int read_replace_refs;
62
63 static int commit_graph_compatible(struct repository *r)
64 {
65         if (!r->gitdir)
66                 return 0;
67
68         if (read_replace_refs) {
69                 prepare_replace_object(r);
70                 if (hashmap_get_size(&r->objects->replace_map->map))
71                         return 0;
72         }
73
74         prepare_commit_graft(r);
75         if (r->parsed_objects && r->parsed_objects->grafts_nr)
76                 return 0;
77         if (is_repository_shallow(r))
78                 return 0;
79
80         return 1;
81 }
82
83 struct commit_graph *load_commit_graph_one(const char *graph_file)
84 {
85         void *graph_map;
86         size_t graph_size;
87         struct stat st;
88         struct commit_graph *ret;
89         int fd = git_open(graph_file);
90
91         if (fd < 0)
92                 return NULL;
93         if (fstat(fd, &st)) {
94                 close(fd);
95                 return NULL;
96         }
97         graph_size = xsize_t(st.st_size);
98
99         if (graph_size < GRAPH_MIN_SIZE) {
100                 close(fd);
101                 die(_("graph file %s is too small"), graph_file);
102         }
103         graph_map = xmmap(NULL, graph_size, PROT_READ, MAP_PRIVATE, fd, 0);
104         ret = parse_commit_graph(graph_map, fd, graph_size);
105
106         if (!ret) {
107                 munmap(graph_map, graph_size);
108                 close(fd);
109                 exit(1);
110         }
111
112         return ret;
113 }
114
115 struct commit_graph *parse_commit_graph(void *graph_map, int fd,
116                                         size_t graph_size)
117 {
118         const unsigned char *data, *chunk_lookup;
119         uint32_t i;
120         struct commit_graph *graph;
121         uint64_t last_chunk_offset;
122         uint32_t last_chunk_id;
123         uint32_t graph_signature;
124         unsigned char graph_version, hash_version;
125
126         if (!graph_map)
127                 return NULL;
128
129         if (graph_size < GRAPH_MIN_SIZE)
130                 return NULL;
131
132         data = (const unsigned char *)graph_map;
133
134         graph_signature = get_be32(data);
135         if (graph_signature != GRAPH_SIGNATURE) {
136                 error(_("graph signature %X does not match signature %X"),
137                       graph_signature, GRAPH_SIGNATURE);
138                 return NULL;
139         }
140
141         graph_version = *(unsigned char*)(data + 4);
142         if (graph_version != GRAPH_VERSION) {
143                 error(_("graph version %X does not match version %X"),
144                       graph_version, GRAPH_VERSION);
145                 return NULL;
146         }
147
148         hash_version = *(unsigned char*)(data + 5);
149         if (hash_version != oid_version()) {
150                 error(_("hash version %X does not match version %X"),
151                       hash_version, oid_version());
152                 return NULL;
153         }
154
155         graph = alloc_commit_graph();
156
157         graph->hash_len = the_hash_algo->rawsz;
158         graph->num_chunks = *(unsigned char*)(data + 6);
159         graph->graph_fd = fd;
160         graph->data = graph_map;
161         graph->data_len = graph_size;
162
163         last_chunk_id = 0;
164         last_chunk_offset = 8;
165         chunk_lookup = data + 8;
166         for (i = 0; i < graph->num_chunks; i++) {
167                 uint32_t chunk_id;
168                 uint64_t chunk_offset;
169                 int chunk_repeated = 0;
170
171                 if (data + graph_size - chunk_lookup <
172                     GRAPH_CHUNKLOOKUP_WIDTH) {
173                         error(_("chunk lookup table entry missing; graph file may be incomplete"));
174                         free(graph);
175                         return NULL;
176                 }
177
178                 chunk_id = get_be32(chunk_lookup + 0);
179                 chunk_offset = get_be64(chunk_lookup + 4);
180
181                 chunk_lookup += GRAPH_CHUNKLOOKUP_WIDTH;
182
183                 if (chunk_offset > graph_size - the_hash_algo->rawsz) {
184                         error(_("improper chunk offset %08x%08x"), (uint32_t)(chunk_offset >> 32),
185                               (uint32_t)chunk_offset);
186                         free(graph);
187                         return NULL;
188                 }
189
190                 switch (chunk_id) {
191                 case GRAPH_CHUNKID_OIDFANOUT:
192                         if (graph->chunk_oid_fanout)
193                                 chunk_repeated = 1;
194                         else
195                                 graph->chunk_oid_fanout = (uint32_t*)(data + chunk_offset);
196                         break;
197
198                 case GRAPH_CHUNKID_OIDLOOKUP:
199                         if (graph->chunk_oid_lookup)
200                                 chunk_repeated = 1;
201                         else
202                                 graph->chunk_oid_lookup = data + chunk_offset;
203                         break;
204
205                 case GRAPH_CHUNKID_DATA:
206                         if (graph->chunk_commit_data)
207                                 chunk_repeated = 1;
208                         else
209                                 graph->chunk_commit_data = data + chunk_offset;
210                         break;
211
212                 case GRAPH_CHUNKID_EXTRAEDGES:
213                         if (graph->chunk_extra_edges)
214                                 chunk_repeated = 1;
215                         else
216                                 graph->chunk_extra_edges = data + chunk_offset;
217                         break;
218                 }
219
220                 if (chunk_repeated) {
221                         error(_("chunk id %08x appears multiple times"), chunk_id);
222                         free(graph);
223                         return NULL;
224                 }
225
226                 if (last_chunk_id == GRAPH_CHUNKID_OIDLOOKUP)
227                 {
228                         graph->num_commits = (chunk_offset - last_chunk_offset)
229                                              / graph->hash_len;
230                 }
231
232                 last_chunk_id = chunk_id;
233                 last_chunk_offset = chunk_offset;
234         }
235
236         return graph;
237 }
238
239 static void prepare_commit_graph_one(struct repository *r, const char *obj_dir)
240 {
241         char *graph_name;
242
243         if (r->objects->commit_graph)
244                 return;
245
246         graph_name = get_commit_graph_filename(obj_dir);
247         r->objects->commit_graph =
248                 load_commit_graph_one(graph_name);
249
250         FREE_AND_NULL(graph_name);
251 }
252
253 /*
254  * Return 1 if commit_graph is non-NULL, and 0 otherwise.
255  *
256  * On the first invocation, this function attemps to load the commit
257  * graph if the_repository is configured to have one.
258  */
259 static int prepare_commit_graph(struct repository *r)
260 {
261         struct object_directory *odb;
262         int config_value;
263
264         if (r->objects->commit_graph_attempted)
265                 return !!r->objects->commit_graph;
266         r->objects->commit_graph_attempted = 1;
267
268         if (!git_env_bool(GIT_TEST_COMMIT_GRAPH, 0) &&
269             (repo_config_get_bool(r, "core.commitgraph", &config_value) ||
270             !config_value))
271                 /*
272                  * This repository is not configured to use commit graphs, so
273                  * do not load one. (But report commit_graph_attempted anyway
274                  * so that commit graph loading is not attempted again for this
275                  * repository.)
276                  */
277                 return 0;
278
279         if (!commit_graph_compatible(r))
280                 return 0;
281
282         prepare_alt_odb(r);
283         for (odb = r->objects->odb;
284              !r->objects->commit_graph && odb;
285              odb = odb->next)
286                 prepare_commit_graph_one(r, odb->path);
287         return !!r->objects->commit_graph;
288 }
289
290 int generation_numbers_enabled(struct repository *r)
291 {
292         uint32_t first_generation;
293         struct commit_graph *g;
294         if (!prepare_commit_graph(r))
295                return 0;
296
297         g = r->objects->commit_graph;
298
299         if (!g->num_commits)
300                 return 0;
301
302         first_generation = get_be32(g->chunk_commit_data +
303                                     g->hash_len + 8) >> 2;
304
305         return !!first_generation;
306 }
307
308 void close_commit_graph(struct repository *r)
309 {
310         free_commit_graph(r->objects->commit_graph);
311         r->objects->commit_graph = NULL;
312 }
313
314 static int bsearch_graph(struct commit_graph *g, struct object_id *oid, uint32_t *pos)
315 {
316         return bsearch_hash(oid->hash, g->chunk_oid_fanout,
317                             g->chunk_oid_lookup, g->hash_len, pos);
318 }
319
320 static struct commit_list **insert_parent_or_die(struct repository *r,
321                                                  struct commit_graph *g,
322                                                  uint64_t pos,
323                                                  struct commit_list **pptr)
324 {
325         struct commit *c;
326         struct object_id oid;
327
328         if (pos >= g->num_commits)
329                 die("invalid parent position %"PRIu64, pos);
330
331         hashcpy(oid.hash, g->chunk_oid_lookup + g->hash_len * pos);
332         c = lookup_commit(r, &oid);
333         if (!c)
334                 die(_("could not find commit %s"), oid_to_hex(&oid));
335         c->graph_pos = pos;
336         return &commit_list_insert(c, pptr)->next;
337 }
338
339 static void fill_commit_graph_info(struct commit *item, struct commit_graph *g, uint32_t pos)
340 {
341         const unsigned char *commit_data = g->chunk_commit_data + GRAPH_DATA_WIDTH * pos;
342         item->graph_pos = pos;
343         item->generation = get_be32(commit_data + g->hash_len + 8) >> 2;
344 }
345
346 static inline void set_commit_tree(struct commit *c, struct tree *t)
347 {
348         c->maybe_tree = t;
349 }
350
351 static int fill_commit_in_graph(struct repository *r,
352                                 struct commit *item,
353                                 struct commit_graph *g, uint32_t pos)
354 {
355         uint32_t edge_value;
356         uint32_t *parent_data_ptr;
357         uint64_t date_low, date_high;
358         struct commit_list **pptr;
359         const unsigned char *commit_data = g->chunk_commit_data + (g->hash_len + 16) * pos;
360
361         item->object.parsed = 1;
362         item->graph_pos = pos;
363
364         set_commit_tree(item, NULL);
365
366         date_high = get_be32(commit_data + g->hash_len + 8) & 0x3;
367         date_low = get_be32(commit_data + g->hash_len + 12);
368         item->date = (timestamp_t)((date_high << 32) | date_low);
369
370         item->generation = get_be32(commit_data + g->hash_len + 8) >> 2;
371
372         pptr = &item->parents;
373
374         edge_value = get_be32(commit_data + g->hash_len);
375         if (edge_value == GRAPH_PARENT_NONE)
376                 return 1;
377         pptr = insert_parent_or_die(r, g, edge_value, pptr);
378
379         edge_value = get_be32(commit_data + g->hash_len + 4);
380         if (edge_value == GRAPH_PARENT_NONE)
381                 return 1;
382         if (!(edge_value & GRAPH_EXTRA_EDGES_NEEDED)) {
383                 pptr = insert_parent_or_die(r, g, edge_value, pptr);
384                 return 1;
385         }
386
387         parent_data_ptr = (uint32_t*)(g->chunk_extra_edges +
388                           4 * (uint64_t)(edge_value & GRAPH_EDGE_LAST_MASK));
389         do {
390                 edge_value = get_be32(parent_data_ptr);
391                 pptr = insert_parent_or_die(r, g,
392                                             edge_value & GRAPH_EDGE_LAST_MASK,
393                                             pptr);
394                 parent_data_ptr++;
395         } while (!(edge_value & GRAPH_LAST_EDGE));
396
397         return 1;
398 }
399
400 static int find_commit_in_graph(struct commit *item, struct commit_graph *g, uint32_t *pos)
401 {
402         if (item->graph_pos != COMMIT_NOT_FROM_GRAPH) {
403                 *pos = item->graph_pos;
404                 return 1;
405         } else {
406                 return bsearch_graph(g, &(item->object.oid), pos);
407         }
408 }
409
410 static int parse_commit_in_graph_one(struct repository *r,
411                                      struct commit_graph *g,
412                                      struct commit *item)
413 {
414         uint32_t pos;
415
416         if (item->object.parsed)
417                 return 1;
418
419         if (find_commit_in_graph(item, g, &pos))
420                 return fill_commit_in_graph(r, item, g, pos);
421
422         return 0;
423 }
424
425 int parse_commit_in_graph(struct repository *r, struct commit *item)
426 {
427         if (!prepare_commit_graph(r))
428                 return 0;
429         return parse_commit_in_graph_one(r, r->objects->commit_graph, item);
430 }
431
432 void load_commit_graph_info(struct repository *r, struct commit *item)
433 {
434         uint32_t pos;
435         if (!prepare_commit_graph(r))
436                 return;
437         if (find_commit_in_graph(item, r->objects->commit_graph, &pos))
438                 fill_commit_graph_info(item, r->objects->commit_graph, pos);
439 }
440
441 static struct tree *load_tree_for_commit(struct repository *r,
442                                          struct commit_graph *g,
443                                          struct commit *c)
444 {
445         struct object_id oid;
446         const unsigned char *commit_data = g->chunk_commit_data +
447                                            GRAPH_DATA_WIDTH * (c->graph_pos);
448
449         hashcpy(oid.hash, commit_data);
450         set_commit_tree(c, lookup_tree(r, &oid));
451
452         return c->maybe_tree;
453 }
454
455 static struct tree *get_commit_tree_in_graph_one(struct repository *r,
456                                                  struct commit_graph *g,
457                                                  const struct commit *c)
458 {
459         if (c->maybe_tree)
460                 return c->maybe_tree;
461         if (c->graph_pos == COMMIT_NOT_FROM_GRAPH)
462                 BUG("get_commit_tree_in_graph_one called from non-commit-graph commit");
463
464         return load_tree_for_commit(r, g, (struct commit *)c);
465 }
466
467 struct tree *get_commit_tree_in_graph(struct repository *r, const struct commit *c)
468 {
469         return get_commit_tree_in_graph_one(r, r->objects->commit_graph, c);
470 }
471
472 static void write_graph_chunk_fanout(struct hashfile *f,
473                                      struct commit **commits,
474                                      int nr_commits,
475                                      struct progress *progress,
476                                      uint64_t *progress_cnt)
477 {
478         int i, count = 0;
479         struct commit **list = commits;
480
481         /*
482          * Write the first-level table (the list is sorted,
483          * but we use a 256-entry lookup to be able to avoid
484          * having to do eight extra binary search iterations).
485          */
486         for (i = 0; i < 256; i++) {
487                 while (count < nr_commits) {
488                         if ((*list)->object.oid.hash[0] != i)
489                                 break;
490                         display_progress(progress, ++*progress_cnt);
491                         count++;
492                         list++;
493                 }
494
495                 hashwrite_be32(f, count);
496         }
497 }
498
499 static void write_graph_chunk_oids(struct hashfile *f, int hash_len,
500                                    struct commit **commits, int nr_commits,
501                                    struct progress *progress,
502                                    uint64_t *progress_cnt)
503 {
504         struct commit **list = commits;
505         int count;
506         for (count = 0; count < nr_commits; count++, list++) {
507                 display_progress(progress, ++*progress_cnt);
508                 hashwrite(f, (*list)->object.oid.hash, (int)hash_len);
509         }
510 }
511
512 static const unsigned char *commit_to_sha1(size_t index, void *table)
513 {
514         struct commit **commits = table;
515         return commits[index]->object.oid.hash;
516 }
517
518 static void write_graph_chunk_data(struct hashfile *f, int hash_len,
519                                    struct commit **commits, int nr_commits,
520                                    struct progress *progress,
521                                    uint64_t *progress_cnt)
522 {
523         struct commit **list = commits;
524         struct commit **last = commits + nr_commits;
525         uint32_t num_extra_edges = 0;
526
527         while (list < last) {
528                 struct commit_list *parent;
529                 int edge_value;
530                 uint32_t packedDate[2];
531                 display_progress(progress, ++*progress_cnt);
532
533                 parse_commit(*list);
534                 hashwrite(f, get_commit_tree_oid(*list)->hash, hash_len);
535
536                 parent = (*list)->parents;
537
538                 if (!parent)
539                         edge_value = GRAPH_PARENT_NONE;
540                 else {
541                         edge_value = sha1_pos(parent->item->object.oid.hash,
542                                               commits,
543                                               nr_commits,
544                                               commit_to_sha1);
545
546                         if (edge_value < 0)
547                                 BUG("missing parent %s for commit %s",
548                                     oid_to_hex(&parent->item->object.oid),
549                                     oid_to_hex(&(*list)->object.oid));
550                 }
551
552                 hashwrite_be32(f, edge_value);
553
554                 if (parent)
555                         parent = parent->next;
556
557                 if (!parent)
558                         edge_value = GRAPH_PARENT_NONE;
559                 else if (parent->next)
560                         edge_value = GRAPH_EXTRA_EDGES_NEEDED | num_extra_edges;
561                 else {
562                         edge_value = sha1_pos(parent->item->object.oid.hash,
563                                               commits,
564                                               nr_commits,
565                                               commit_to_sha1);
566                         if (edge_value < 0)
567                                 BUG("missing parent %s for commit %s",
568                                     oid_to_hex(&parent->item->object.oid),
569                                     oid_to_hex(&(*list)->object.oid));
570                 }
571
572                 hashwrite_be32(f, edge_value);
573
574                 if (edge_value & GRAPH_EXTRA_EDGES_NEEDED) {
575                         do {
576                                 num_extra_edges++;
577                                 parent = parent->next;
578                         } while (parent);
579                 }
580
581                 if (sizeof((*list)->date) > 4)
582                         packedDate[0] = htonl(((*list)->date >> 32) & 0x3);
583                 else
584                         packedDate[0] = 0;
585
586                 packedDate[0] |= htonl((*list)->generation << 2);
587
588                 packedDate[1] = htonl((*list)->date);
589                 hashwrite(f, packedDate, 8);
590
591                 list++;
592         }
593 }
594
595 static void write_graph_chunk_extra_edges(struct hashfile *f,
596                                           struct commit **commits,
597                                           int nr_commits,
598                                           struct progress *progress,
599                                           uint64_t *progress_cnt)
600 {
601         struct commit **list = commits;
602         struct commit **last = commits + nr_commits;
603         struct commit_list *parent;
604
605         while (list < last) {
606                 int num_parents = 0;
607
608                 display_progress(progress, ++*progress_cnt);
609
610                 for (parent = (*list)->parents; num_parents < 3 && parent;
611                      parent = parent->next)
612                         num_parents++;
613
614                 if (num_parents <= 2) {
615                         list++;
616                         continue;
617                 }
618
619                 /* Since num_parents > 2, this initializer is safe. */
620                 for (parent = (*list)->parents->next; parent; parent = parent->next) {
621                         int edge_value = sha1_pos(parent->item->object.oid.hash,
622                                                   commits,
623                                                   nr_commits,
624                                                   commit_to_sha1);
625
626                         if (edge_value < 0)
627                                 BUG("missing parent %s for commit %s",
628                                     oid_to_hex(&parent->item->object.oid),
629                                     oid_to_hex(&(*list)->object.oid));
630                         else if (!parent->next)
631                                 edge_value |= GRAPH_LAST_EDGE;
632
633                         hashwrite_be32(f, edge_value);
634                 }
635
636                 list++;
637         }
638 }
639
640 static int commit_compare(const void *_a, const void *_b)
641 {
642         const struct object_id *a = (const struct object_id *)_a;
643         const struct object_id *b = (const struct object_id *)_b;
644         return oidcmp(a, b);
645 }
646
647 struct packed_commit_list {
648         struct commit **list;
649         int nr;
650         int alloc;
651 };
652
653 struct packed_oid_list {
654         struct object_id *list;
655         int nr;
656         int alloc;
657         struct progress *progress;
658         int progress_done;
659 };
660
661 static int add_packed_commits(const struct object_id *oid,
662                               struct packed_git *pack,
663                               uint32_t pos,
664                               void *data)
665 {
666         struct packed_oid_list *list = (struct packed_oid_list*)data;
667         enum object_type type;
668         off_t offset = nth_packed_object_offset(pack, pos);
669         struct object_info oi = OBJECT_INFO_INIT;
670
671         if (list->progress)
672                 display_progress(list->progress, ++list->progress_done);
673
674         oi.typep = &type;
675         if (packed_object_info(the_repository, pack, offset, &oi) < 0)
676                 die(_("unable to get type of object %s"), oid_to_hex(oid));
677
678         if (type != OBJ_COMMIT)
679                 return 0;
680
681         ALLOC_GROW(list->list, list->nr + 1, list->alloc);
682         oidcpy(&(list->list[list->nr]), oid);
683         list->nr++;
684
685         return 0;
686 }
687
688 static void add_missing_parents(struct packed_oid_list *oids, struct commit *commit)
689 {
690         struct commit_list *parent;
691         for (parent = commit->parents; parent; parent = parent->next) {
692                 if (!(parent->item->object.flags & UNINTERESTING)) {
693                         ALLOC_GROW(oids->list, oids->nr + 1, oids->alloc);
694                         oidcpy(&oids->list[oids->nr], &(parent->item->object.oid));
695                         oids->nr++;
696                         parent->item->object.flags |= UNINTERESTING;
697                 }
698         }
699 }
700
701 static void close_reachable(struct packed_oid_list *oids, int report_progress)
702 {
703         int i;
704         struct commit *commit;
705         struct progress *progress = NULL;
706
707         if (report_progress)
708                 progress = start_delayed_progress(
709                         _("Loading known commits in commit graph"), oids->nr);
710         for (i = 0; i < oids->nr; i++) {
711                 display_progress(progress, i + 1);
712                 commit = lookup_commit(the_repository, &oids->list[i]);
713                 if (commit)
714                         commit->object.flags |= UNINTERESTING;
715         }
716         stop_progress(&progress);
717
718         /*
719          * As this loop runs, oids->nr may grow, but not more
720          * than the number of missing commits in the reachable
721          * closure.
722          */
723         if (report_progress)
724                 progress = start_delayed_progress(
725                         _("Expanding reachable commits in commit graph"), oids->nr);
726         for (i = 0; i < oids->nr; i++) {
727                 display_progress(progress, i + 1);
728                 commit = lookup_commit(the_repository, &oids->list[i]);
729
730                 if (commit && !parse_commit(commit))
731                         add_missing_parents(oids, commit);
732         }
733         stop_progress(&progress);
734
735         if (report_progress)
736                 progress = start_delayed_progress(
737                         _("Clearing commit marks in commit graph"), oids->nr);
738         for (i = 0; i < oids->nr; i++) {
739                 display_progress(progress, i + 1);
740                 commit = lookup_commit(the_repository, &oids->list[i]);
741
742                 if (commit)
743                         commit->object.flags &= ~UNINTERESTING;
744         }
745         stop_progress(&progress);
746 }
747
748 static void compute_generation_numbers(struct packed_commit_list* commits,
749                                        int report_progress)
750 {
751         int i;
752         struct commit_list *list = NULL;
753         struct progress *progress = NULL;
754
755         if (report_progress)
756                 progress = start_progress(
757                         _("Computing commit graph generation numbers"),
758                         commits->nr);
759         for (i = 0; i < commits->nr; i++) {
760                 display_progress(progress, i + 1);
761                 if (commits->list[i]->generation != GENERATION_NUMBER_INFINITY &&
762                     commits->list[i]->generation != GENERATION_NUMBER_ZERO)
763                         continue;
764
765                 commit_list_insert(commits->list[i], &list);
766                 while (list) {
767                         struct commit *current = list->item;
768                         struct commit_list *parent;
769                         int all_parents_computed = 1;
770                         uint32_t max_generation = 0;
771
772                         for (parent = current->parents; parent; parent = parent->next) {
773                                 if (parent->item->generation == GENERATION_NUMBER_INFINITY ||
774                                     parent->item->generation == GENERATION_NUMBER_ZERO) {
775                                         all_parents_computed = 0;
776                                         commit_list_insert(parent->item, &list);
777                                         break;
778                                 } else if (parent->item->generation > max_generation) {
779                                         max_generation = parent->item->generation;
780                                 }
781                         }
782
783                         if (all_parents_computed) {
784                                 current->generation = max_generation + 1;
785                                 pop_commit(&list);
786
787                                 if (current->generation > GENERATION_NUMBER_MAX)
788                                         current->generation = GENERATION_NUMBER_MAX;
789                         }
790                 }
791         }
792         stop_progress(&progress);
793 }
794
795 static int add_ref_to_list(const char *refname,
796                            const struct object_id *oid,
797                            int flags, void *cb_data)
798 {
799         struct string_list *list = (struct string_list *)cb_data;
800
801         string_list_append(list, oid_to_hex(oid));
802         return 0;
803 }
804
805 void write_commit_graph_reachable(const char *obj_dir, int append,
806                                   int report_progress)
807 {
808         struct string_list list = STRING_LIST_INIT_DUP;
809
810         for_each_ref(add_ref_to_list, &list);
811         write_commit_graph(obj_dir, NULL, &list, append, report_progress);
812
813         string_list_clear(&list, 0);
814 }
815
816 void write_commit_graph(const char *obj_dir,
817                         struct string_list *pack_indexes,
818                         struct string_list *commit_hex,
819                         int append, int report_progress)
820 {
821         struct packed_oid_list oids;
822         struct packed_commit_list commits;
823         struct hashfile *f;
824         uint32_t i, count_distinct = 0;
825         char *graph_name;
826         struct lock_file lk = LOCK_INIT;
827         uint32_t chunk_ids[5];
828         uint64_t chunk_offsets[5];
829         int num_chunks;
830         int num_extra_edges;
831         struct commit_list *parent;
832         struct progress *progress = NULL;
833         const unsigned hashsz = the_hash_algo->rawsz;
834         uint64_t progress_cnt = 0;
835         struct strbuf progress_title = STRBUF_INIT;
836         unsigned long approx_nr_objects;
837
838         if (!commit_graph_compatible(the_repository))
839                 return;
840
841         oids.nr = 0;
842         approx_nr_objects = approximate_object_count();
843         oids.alloc = approx_nr_objects / 32;
844         oids.progress = NULL;
845         oids.progress_done = 0;
846
847         if (append) {
848                 prepare_commit_graph_one(the_repository, obj_dir);
849                 if (the_repository->objects->commit_graph)
850                         oids.alloc += the_repository->objects->commit_graph->num_commits;
851         }
852
853         if (oids.alloc < 1024)
854                 oids.alloc = 1024;
855         ALLOC_ARRAY(oids.list, oids.alloc);
856
857         if (append && the_repository->objects->commit_graph) {
858                 struct commit_graph *commit_graph =
859                         the_repository->objects->commit_graph;
860                 for (i = 0; i < commit_graph->num_commits; i++) {
861                         const unsigned char *hash = commit_graph->chunk_oid_lookup +
862                                 commit_graph->hash_len * i;
863                         hashcpy(oids.list[oids.nr++].hash, hash);
864                 }
865         }
866
867         if (pack_indexes) {
868                 struct strbuf packname = STRBUF_INIT;
869                 int dirlen;
870                 strbuf_addf(&packname, "%s/pack/", obj_dir);
871                 dirlen = packname.len;
872                 if (report_progress) {
873                         strbuf_addf(&progress_title,
874                                     Q_("Finding commits for commit graph in %d pack",
875                                        "Finding commits for commit graph in %d packs",
876                                        pack_indexes->nr),
877                                     pack_indexes->nr);
878                         oids.progress = start_delayed_progress(progress_title.buf, 0);
879                         oids.progress_done = 0;
880                 }
881                 for (i = 0; i < pack_indexes->nr; i++) {
882                         struct packed_git *p;
883                         strbuf_setlen(&packname, dirlen);
884                         strbuf_addstr(&packname, pack_indexes->items[i].string);
885                         p = add_packed_git(packname.buf, packname.len, 1);
886                         if (!p)
887                                 die(_("error adding pack %s"), packname.buf);
888                         if (open_pack_index(p))
889                                 die(_("error opening index for %s"), packname.buf);
890                         for_each_object_in_pack(p, add_packed_commits, &oids,
891                                                 FOR_EACH_OBJECT_PACK_ORDER);
892                         close_pack(p);
893                         free(p);
894                 }
895                 stop_progress(&oids.progress);
896                 strbuf_reset(&progress_title);
897                 strbuf_release(&packname);
898         }
899
900         if (commit_hex) {
901                 if (report_progress) {
902                         strbuf_addf(&progress_title,
903                                     Q_("Finding commits for commit graph from %d ref",
904                                        "Finding commits for commit graph from %d refs",
905                                        commit_hex->nr),
906                                     commit_hex->nr);
907                         progress = start_delayed_progress(progress_title.buf,
908                                                           commit_hex->nr);
909                 }
910                 for (i = 0; i < commit_hex->nr; i++) {
911                         const char *end;
912                         struct object_id oid;
913                         struct commit *result;
914
915                         display_progress(progress, i + 1);
916                         if (commit_hex->items[i].string &&
917                             parse_oid_hex(commit_hex->items[i].string, &oid, &end))
918                                 continue;
919
920                         result = lookup_commit_reference_gently(the_repository, &oid, 1);
921
922                         if (result) {
923                                 ALLOC_GROW(oids.list, oids.nr + 1, oids.alloc);
924                                 oidcpy(&oids.list[oids.nr], &(result->object.oid));
925                                 oids.nr++;
926                         }
927                 }
928                 stop_progress(&progress);
929                 strbuf_reset(&progress_title);
930         }
931
932         if (!pack_indexes && !commit_hex) {
933                 if (report_progress)
934                         oids.progress = start_delayed_progress(
935                                 _("Finding commits for commit graph among packed objects"),
936                                 approx_nr_objects);
937                 for_each_packed_object(add_packed_commits, &oids,
938                                        FOR_EACH_OBJECT_PACK_ORDER);
939                 if (oids.progress_done < approx_nr_objects)
940                         display_progress(oids.progress, approx_nr_objects);
941                 stop_progress(&oids.progress);
942         }
943
944         close_reachable(&oids, report_progress);
945
946         if (report_progress)
947                 progress = start_delayed_progress(
948                         _("Counting distinct commits in commit graph"),
949                         oids.nr);
950         display_progress(progress, 0); /* TODO: Measure QSORT() progress */
951         QSORT(oids.list, oids.nr, commit_compare);
952         count_distinct = 1;
953         for (i = 1; i < oids.nr; i++) {
954                 display_progress(progress, i + 1);
955                 if (!oideq(&oids.list[i - 1], &oids.list[i]))
956                         count_distinct++;
957         }
958         stop_progress(&progress);
959
960         if (count_distinct >= GRAPH_EDGE_LAST_MASK)
961                 die(_("the commit graph format cannot write %d commits"), count_distinct);
962
963         commits.nr = 0;
964         commits.alloc = count_distinct;
965         ALLOC_ARRAY(commits.list, commits.alloc);
966
967         num_extra_edges = 0;
968         if (report_progress)
969                 progress = start_delayed_progress(
970                         _("Finding extra edges in commit graph"),
971                         oids.nr);
972         for (i = 0; i < oids.nr; i++) {
973                 int num_parents = 0;
974                 display_progress(progress, i + 1);
975                 if (i > 0 && oideq(&oids.list[i - 1], &oids.list[i]))
976                         continue;
977
978                 commits.list[commits.nr] = lookup_commit(the_repository, &oids.list[i]);
979                 parse_commit(commits.list[commits.nr]);
980
981                 for (parent = commits.list[commits.nr]->parents;
982                      parent; parent = parent->next)
983                         num_parents++;
984
985                 if (num_parents > 2)
986                         num_extra_edges += num_parents - 1;
987
988                 commits.nr++;
989         }
990         num_chunks = num_extra_edges ? 4 : 3;
991         stop_progress(&progress);
992
993         if (commits.nr >= GRAPH_EDGE_LAST_MASK)
994                 die(_("too many commits to write graph"));
995
996         compute_generation_numbers(&commits, report_progress);
997
998         graph_name = get_commit_graph_filename(obj_dir);
999         if (safe_create_leading_directories(graph_name)) {
1000                 UNLEAK(graph_name);
1001                 die_errno(_("unable to create leading directories of %s"),
1002                           graph_name);
1003         }
1004
1005         hold_lock_file_for_update(&lk, graph_name, LOCK_DIE_ON_ERROR);
1006         f = hashfd(lk.tempfile->fd, lk.tempfile->filename.buf);
1007
1008         hashwrite_be32(f, GRAPH_SIGNATURE);
1009
1010         hashwrite_u8(f, GRAPH_VERSION);
1011         hashwrite_u8(f, oid_version());
1012         hashwrite_u8(f, num_chunks);
1013         hashwrite_u8(f, 0); /* unused padding byte */
1014
1015         chunk_ids[0] = GRAPH_CHUNKID_OIDFANOUT;
1016         chunk_ids[1] = GRAPH_CHUNKID_OIDLOOKUP;
1017         chunk_ids[2] = GRAPH_CHUNKID_DATA;
1018         if (num_extra_edges)
1019                 chunk_ids[3] = GRAPH_CHUNKID_EXTRAEDGES;
1020         else
1021                 chunk_ids[3] = 0;
1022         chunk_ids[4] = 0;
1023
1024         chunk_offsets[0] = 8 + (num_chunks + 1) * GRAPH_CHUNKLOOKUP_WIDTH;
1025         chunk_offsets[1] = chunk_offsets[0] + GRAPH_FANOUT_SIZE;
1026         chunk_offsets[2] = chunk_offsets[1] + hashsz * commits.nr;
1027         chunk_offsets[3] = chunk_offsets[2] + (hashsz + 16) * commits.nr;
1028         chunk_offsets[4] = chunk_offsets[3] + 4 * num_extra_edges;
1029
1030         for (i = 0; i <= num_chunks; i++) {
1031                 uint32_t chunk_write[3];
1032
1033                 chunk_write[0] = htonl(chunk_ids[i]);
1034                 chunk_write[1] = htonl(chunk_offsets[i] >> 32);
1035                 chunk_write[2] = htonl(chunk_offsets[i] & 0xffffffff);
1036                 hashwrite(f, chunk_write, 12);
1037         }
1038
1039         if (report_progress) {
1040                 strbuf_addf(&progress_title,
1041                             Q_("Writing out commit graph in %d pass",
1042                                "Writing out commit graph in %d passes",
1043                                num_chunks),
1044                             num_chunks);
1045                 progress = start_delayed_progress(
1046                         progress_title.buf,
1047                         num_chunks * commits.nr);
1048         }
1049         write_graph_chunk_fanout(f, commits.list, commits.nr, progress, &progress_cnt);
1050         write_graph_chunk_oids(f, hashsz, commits.list, commits.nr, progress, &progress_cnt);
1051         write_graph_chunk_data(f, hashsz, commits.list, commits.nr, progress, &progress_cnt);
1052         if (num_extra_edges)
1053                 write_graph_chunk_extra_edges(f, commits.list, commits.nr, progress, &progress_cnt);
1054         stop_progress(&progress);
1055         strbuf_release(&progress_title);
1056
1057         close_commit_graph(the_repository);
1058         finalize_hashfile(f, NULL, CSUM_HASH_IN_STREAM | CSUM_FSYNC);
1059         commit_lock_file(&lk);
1060
1061         free(graph_name);
1062         free(commits.list);
1063         free(oids.list);
1064 }
1065
1066 #define VERIFY_COMMIT_GRAPH_ERROR_HASH 2
1067 static int verify_commit_graph_error;
1068
1069 static void graph_report(const char *fmt, ...)
1070 {
1071         va_list ap;
1072
1073         verify_commit_graph_error = 1;
1074         va_start(ap, fmt);
1075         vfprintf(stderr, fmt, ap);
1076         fprintf(stderr, "\n");
1077         va_end(ap);
1078 }
1079
1080 #define GENERATION_ZERO_EXISTS 1
1081 #define GENERATION_NUMBER_EXISTS 2
1082
1083 int verify_commit_graph(struct repository *r, struct commit_graph *g)
1084 {
1085         uint32_t i, cur_fanout_pos = 0;
1086         struct object_id prev_oid, cur_oid, checksum;
1087         int generation_zero = 0;
1088         struct hashfile *f;
1089         int devnull;
1090         struct progress *progress = NULL;
1091
1092         if (!g) {
1093                 graph_report("no commit-graph file loaded");
1094                 return 1;
1095         }
1096
1097         verify_commit_graph_error = 0;
1098
1099         if (!g->chunk_oid_fanout)
1100                 graph_report("commit-graph is missing the OID Fanout chunk");
1101         if (!g->chunk_oid_lookup)
1102                 graph_report("commit-graph is missing the OID Lookup chunk");
1103         if (!g->chunk_commit_data)
1104                 graph_report("commit-graph is missing the Commit Data chunk");
1105
1106         if (verify_commit_graph_error)
1107                 return verify_commit_graph_error;
1108
1109         devnull = open("/dev/null", O_WRONLY);
1110         f = hashfd(devnull, NULL);
1111         hashwrite(f, g->data, g->data_len - g->hash_len);
1112         finalize_hashfile(f, checksum.hash, CSUM_CLOSE);
1113         if (!hasheq(checksum.hash, g->data + g->data_len - g->hash_len)) {
1114                 graph_report(_("the commit-graph file has incorrect checksum and is likely corrupt"));
1115                 verify_commit_graph_error = VERIFY_COMMIT_GRAPH_ERROR_HASH;
1116         }
1117
1118         for (i = 0; i < g->num_commits; i++) {
1119                 struct commit *graph_commit;
1120
1121                 hashcpy(cur_oid.hash, g->chunk_oid_lookup + g->hash_len * i);
1122
1123                 if (i && oidcmp(&prev_oid, &cur_oid) >= 0)
1124                         graph_report("commit-graph has incorrect OID order: %s then %s",
1125                                      oid_to_hex(&prev_oid),
1126                                      oid_to_hex(&cur_oid));
1127
1128                 oidcpy(&prev_oid, &cur_oid);
1129
1130                 while (cur_oid.hash[0] > cur_fanout_pos) {
1131                         uint32_t fanout_value = get_be32(g->chunk_oid_fanout + cur_fanout_pos);
1132
1133                         if (i != fanout_value)
1134                                 graph_report("commit-graph has incorrect fanout value: fanout[%d] = %u != %u",
1135                                              cur_fanout_pos, fanout_value, i);
1136                         cur_fanout_pos++;
1137                 }
1138
1139                 graph_commit = lookup_commit(r, &cur_oid);
1140                 if (!parse_commit_in_graph_one(r, g, graph_commit))
1141                         graph_report("failed to parse %s from commit-graph",
1142                                      oid_to_hex(&cur_oid));
1143         }
1144
1145         while (cur_fanout_pos < 256) {
1146                 uint32_t fanout_value = get_be32(g->chunk_oid_fanout + cur_fanout_pos);
1147
1148                 if (g->num_commits != fanout_value)
1149                         graph_report("commit-graph has incorrect fanout value: fanout[%d] = %u != %u",
1150                                      cur_fanout_pos, fanout_value, i);
1151
1152                 cur_fanout_pos++;
1153         }
1154
1155         if (verify_commit_graph_error & ~VERIFY_COMMIT_GRAPH_ERROR_HASH)
1156                 return verify_commit_graph_error;
1157
1158         progress = start_progress(_("Verifying commits in commit graph"),
1159                                   g->num_commits);
1160         for (i = 0; i < g->num_commits; i++) {
1161                 struct commit *graph_commit, *odb_commit;
1162                 struct commit_list *graph_parents, *odb_parents;
1163                 uint32_t max_generation = 0;
1164
1165                 display_progress(progress, i + 1);
1166                 hashcpy(cur_oid.hash, g->chunk_oid_lookup + g->hash_len * i);
1167
1168                 graph_commit = lookup_commit(r, &cur_oid);
1169                 odb_commit = (struct commit *)create_object(r, cur_oid.hash, alloc_commit_node(r));
1170                 if (parse_commit_internal(odb_commit, 0, 0)) {
1171                         graph_report("failed to parse %s from object database",
1172                                      oid_to_hex(&cur_oid));
1173                         continue;
1174                 }
1175
1176                 if (!oideq(&get_commit_tree_in_graph_one(r, g, graph_commit)->object.oid,
1177                            get_commit_tree_oid(odb_commit)))
1178                         graph_report("root tree OID for commit %s in commit-graph is %s != %s",
1179                                      oid_to_hex(&cur_oid),
1180                                      oid_to_hex(get_commit_tree_oid(graph_commit)),
1181                                      oid_to_hex(get_commit_tree_oid(odb_commit)));
1182
1183                 graph_parents = graph_commit->parents;
1184                 odb_parents = odb_commit->parents;
1185
1186                 while (graph_parents) {
1187                         if (odb_parents == NULL) {
1188                                 graph_report("commit-graph parent list for commit %s is too long",
1189                                              oid_to_hex(&cur_oid));
1190                                 break;
1191                         }
1192
1193                         if (!oideq(&graph_parents->item->object.oid, &odb_parents->item->object.oid))
1194                                 graph_report("commit-graph parent for %s is %s != %s",
1195                                              oid_to_hex(&cur_oid),
1196                                              oid_to_hex(&graph_parents->item->object.oid),
1197                                              oid_to_hex(&odb_parents->item->object.oid));
1198
1199                         if (graph_parents->item->generation > max_generation)
1200                                 max_generation = graph_parents->item->generation;
1201
1202                         graph_parents = graph_parents->next;
1203                         odb_parents = odb_parents->next;
1204                 }
1205
1206                 if (odb_parents != NULL)
1207                         graph_report("commit-graph parent list for commit %s terminates early",
1208                                      oid_to_hex(&cur_oid));
1209
1210                 if (!graph_commit->generation) {
1211                         if (generation_zero == GENERATION_NUMBER_EXISTS)
1212                                 graph_report("commit-graph has generation number zero for commit %s, but non-zero elsewhere",
1213                                              oid_to_hex(&cur_oid));
1214                         generation_zero = GENERATION_ZERO_EXISTS;
1215                 } else if (generation_zero == GENERATION_ZERO_EXISTS)
1216                         graph_report("commit-graph has non-zero generation number for commit %s, but zero elsewhere",
1217                                      oid_to_hex(&cur_oid));
1218
1219                 if (generation_zero == GENERATION_ZERO_EXISTS)
1220                         continue;
1221
1222                 /*
1223                  * If one of our parents has generation GENERATION_NUMBER_MAX, then
1224                  * our generation is also GENERATION_NUMBER_MAX. Decrement to avoid
1225                  * extra logic in the following condition.
1226                  */
1227                 if (max_generation == GENERATION_NUMBER_MAX)
1228                         max_generation--;
1229
1230                 if (graph_commit->generation != max_generation + 1)
1231                         graph_report("commit-graph generation for commit %s is %u != %u",
1232                                      oid_to_hex(&cur_oid),
1233                                      graph_commit->generation,
1234                                      max_generation + 1);
1235
1236                 if (graph_commit->date != odb_commit->date)
1237                         graph_report("commit date for commit %s in commit-graph is %"PRItime" != %"PRItime,
1238                                      oid_to_hex(&cur_oid),
1239                                      graph_commit->date,
1240                                      odb_commit->date);
1241         }
1242         stop_progress(&progress);
1243
1244         return verify_commit_graph_error;
1245 }
1246
1247 void free_commit_graph(struct commit_graph *g)
1248 {
1249         if (!g)
1250                 return;
1251         if (g->graph_fd >= 0) {
1252                 munmap((void *)g->data, g->data_len);
1253                 g->data = NULL;
1254                 close(g->graph_fd);
1255         }
1256         free(g);
1257 }