Raw
1 #define USE_THE_REPOSITORY_VARIABLE
2 #define DISABLE_SIGN_COMPARE_WARNINGS
3
4 #include "git-compat-util.h"
5 #include "pseudo-merge.h"
6 #include "date.h"
7 #include "oid-array.h"
8 #include "strbuf.h"
9 #include "config.h"
10 #include "string-list.h"
11 #include "refs.h"
12 #include "pack-bitmap.h"
13 #include "commit.h"
14 #include "alloc.h"
15 #include "progress.h"
16 #include "hex.h"
17
18 #define DEFAULT_PSEUDO_MERGE_DECAY 1.0
19 #define DEFAULT_PSEUDO_MERGE_MAX_MERGES 64
20 #define DEFAULT_PSEUDO_MERGE_SAMPLE_RATE 1
21 #define DEFAULT_PSEUDO_MERGE_THRESHOLD approxidate("1.week.ago")
22 #define DEFAULT_PSEUDO_MERGE_STABLE_THRESHOLD approxidate("1.month.ago")
23 #define DEFAULT_PSEUDO_MERGE_STABLE_SIZE 512
24
25 static double gitexp(double base, int exp)
26 {
27 double result = 1;
28 while (1) {
29 if (exp % 2)
30 result *= base;
31 exp >>= 1;
32 if (!exp)
33 break;
34 base *= base;
35 }
36 return result;
37 }
38
39 static uint32_t pseudo_merge_group_size(const struct pseudo_merge_group *group,
40 const struct pseudo_merge_matches *matches,
41 uint32_t i)
42 {
43 double C = 0.0f;
44 uint32_t n;
45
46 /*
47 * The size of pseudo-merge groups decays according to a power series,
48 * which looks like:
49 *
50 * f(n) = C * n^-k
51 *
52 * , where 'n' is the n-th pseudo-merge group, 'f(n)' is its size, 'k'
53 * is the decay rate, and 'C' is a scaling value.
54 *
55 * The value of C depends on the number of groups, decay rate, and total
56 * number of commits. It is computed such that if there are M and N
57 * total groups and commits, respectively, that:
58 *
59 * N = f(0) + f(1) + ... f(M-1)
60 *
61 * Rearranging to isolate C, we get:
62 *
63 * N = \sum_{n=1}^M C / n^k
64 *
65 * N / C = \sum_{n=1}^M n^-k
66 *
67 * C = N / \sum_{n=1}^M n^-k
68 *
69 * For example, if we have a decay rate of 'k' being equal to 1.5, 'N'
70 * total commits equal to 10,000, and 'M' being equal to 6 groups, then
71 * the (rounded) group sizes are:
72 *
73 * { 5469, 1934, 1053, 684, 489, 372 }
74 *
75 * increasing the number of total groups, say to 10, scales the group
76 * sizes appropriately:
77 *
78 * { 5012, 1772, 964, 626, 448, 341, 271, 221, 186, 158 }
79 */
80 for (n = 0; n < group->max_merges; n++)
81 C += 1.0 / gitexp(n + 1, group->decay);
82 C = matches->unstable_nr / C;
83
84 return (uint32_t)((C / gitexp(i + 1, group->decay)) + 0.5);
85 }
86
87 static void pseudo_merge_group_init(struct pseudo_merge_group *group)
88 {
89 memset(group, 0, sizeof(struct pseudo_merge_group));
90
91 strmap_init_with_options(&group->matches, NULL, 1);
92
93 group->decay = DEFAULT_PSEUDO_MERGE_DECAY;
94 group->max_merges = DEFAULT_PSEUDO_MERGE_MAX_MERGES;
95 group->sample_rate = DEFAULT_PSEUDO_MERGE_SAMPLE_RATE;
96 group->threshold = DEFAULT_PSEUDO_MERGE_THRESHOLD;
97 group->stable_threshold = DEFAULT_PSEUDO_MERGE_STABLE_THRESHOLD;
98 group->stable_size = DEFAULT_PSEUDO_MERGE_STABLE_SIZE;
99 }
100
101 void pseudo_merge_group_release(struct pseudo_merge_group *group)
102 {
103 struct hashmap_iter iter;
104 struct strmap_entry *e;
105
106 regfree(group->pattern);
107 free(group->pattern);
108
109 strmap_for_each_entry(&group->matches, &iter, e) {
110 struct pseudo_merge_matches *matches = e->value;
111 free(matches->stable);
112 free(matches->unstable);
113 free(matches);
114 }
115 strmap_clear(&group->matches, 0);
116
117 free(group->merges);
118 }
119
120 static int pseudo_merge_config(const char *var, const char *value,
121 const struct config_context *ctx,
122 void *cb_data)
123 {
124 struct string_list *list = cb_data;
125 struct string_list_item *item;
126 struct pseudo_merge_group *group;
127 struct strbuf buf = STRBUF_INIT;
128 const char *sub, *key;
129 size_t sub_len;
130 int ret = 0;
131
132 if (parse_config_key(var, "bitmappseudomerge", &sub, &sub_len, &key))
133 goto done;
134
135 if (!sub_len)
136 goto done;
137
138 strbuf_add(&buf, sub, sub_len);
139
140 item = string_list_lookup(list, buf.buf);
141 if (!item) {
142 item = string_list_insert(list, buf.buf);
143
144 item->util = xmalloc(sizeof(struct pseudo_merge_group));
145 pseudo_merge_group_init(item->util);
146 }
147
148 group = item->util;
149
150 if (!strcmp(key, "pattern")) {
151 struct strbuf re = STRBUF_INIT;
152
153 if (group->pattern) {
154 regfree(group->pattern);
155 free(group->pattern);
156 }
157 if (*value != '^')
158 strbuf_addch(&re, '^');
159 strbuf_addstr(&re, value);
160
161 group->pattern = xcalloc(1, sizeof(regex_t));
162 if (regcomp(group->pattern, re.buf, REG_EXTENDED))
163 die(_("failed to load pseudo-merge regex for %s: '%s'"),
164 sub, re.buf);
165
166 strbuf_release(&re);
167 } else if (!strcmp(key, "decay")) {
168 group->decay = git_config_double(var, value, ctx->kvi);
169 if (group->decay < 0) {
170 warning(_("%s must be non-negative, using default"), var);
171 group->decay = DEFAULT_PSEUDO_MERGE_DECAY;
172 }
173 } else if (!strcmp(key, "samplerate")) {
174 group->sample_rate = git_config_double(var, value, ctx->kvi);
175 if (!(0 < group->sample_rate && group->sample_rate <= 1)) {
176 warning(_("%s must be between 0 (exclusive) and 1, using default"), var);
177 group->sample_rate = DEFAULT_PSEUDO_MERGE_SAMPLE_RATE;
178 }
179 } else if (!strcmp(key, "threshold")) {
180 if (git_config_expiry_date(&group->threshold, var, value)) {
181 ret = -1;
182 goto done;
183 }
184 } else if (!strcmp(key, "maxmerges")) {
185 group->max_merges = git_config_int(var, value, ctx->kvi);
186 if (group->max_merges < 0) {
187 warning(_("%s must be non-negative, using default"), var);
188 group->max_merges = DEFAULT_PSEUDO_MERGE_MAX_MERGES;
189 }
190 } else if (!strcmp(key, "stablethreshold")) {
191 if (git_config_expiry_date(&group->stable_threshold, var, value)) {
192 ret = -1;
193 goto done;
194 }
195 } else if (!strcmp(key, "stablesize")) {
196 group->stable_size = git_config_int(var, value, ctx->kvi);
197 if (group->stable_size <= 0) {
198 warning(_("%s must be positive, using default"), var);
199 group->stable_size = DEFAULT_PSEUDO_MERGE_STABLE_SIZE;
200 }
201 }
202
203 done:
204 strbuf_release(&buf);
205
206 return ret;
207 }
208
209 void load_pseudo_merges_from_config(struct repository *r,
210 struct string_list *list)
211 {
212 struct string_list_item *item;
213
214 repo_config(r, pseudo_merge_config, list);
215
216 for_each_string_list_item(item, list) {
217 struct pseudo_merge_group *group = item->util;
218 if (!group->pattern)
219 die(_("pseudo-merge group '%s' missing required pattern"),
220 item->string);
221 if (group->threshold < group->stable_threshold)
222 die(_("pseudo-merge group '%s' has unstable threshold "
223 "before stable one"), item->string);
224 }
225 }
226
227 static int find_pseudo_merge_group_for_ref(const struct reference *ref, void *_data)
228 {
229 struct bitmap_writer *writer = _data;
230 const struct object_id *maybe_peeled = ref->oid;
231 struct object_id peeled;
232 struct commit *c;
233 uint32_t i;
234 int has_bitmap;
235
236 if (!reference_get_peeled_oid(the_repository, ref, &peeled))
237 maybe_peeled = &peeled;
238
239 c = lookup_commit(the_repository, maybe_peeled);
240 if (!c)
241 return 0;
242 if (repo_parse_commit(the_repository, c))
243 return 0;
244 if (!packlist_find(writer->to_pack, maybe_peeled))
245 return 0;
246
247 has_bitmap = bitmap_writer_has_bitmapped_object_id(writer, maybe_peeled);
248
249 for (i = 0; i < writer->pseudo_merge_groups.nr; i++) {
250 struct pseudo_merge_group *group;
251 struct pseudo_merge_matches *matches;
252 struct strbuf group_name = STRBUF_INIT;
253 regmatch_t captures[16];
254 size_t j;
255
256 group = writer->pseudo_merge_groups.items[i].util;
257 if (regexec(group->pattern, ref->name, ARRAY_SIZE(captures),
258 captures, 0))
259 continue;
260
261 if (captures[ARRAY_SIZE(captures) - 1].rm_so != -1)
262 warning(_("pseudo-merge regex from config has too many capture "
263 "groups (max=%"PRIuMAX")"),
264 (uintmax_t)ARRAY_SIZE(captures) - 2);
265
266 for (j = !!group->pattern->re_nsub; j < ARRAY_SIZE(captures); j++) {
267 regmatch_t *match = &captures[j];
268 if (match->rm_so == -1)
269 continue;
270
271 if (group_name.len)
272 strbuf_addch(&group_name, '-');
273
274 strbuf_add(&group_name, ref->name + match->rm_so,
275 match->rm_eo - match->rm_so);
276 }
277
278 matches = strmap_get(&group->matches, group_name.buf);
279 if (!matches) {
280 matches = xcalloc(1, sizeof(*matches));
281 strmap_put(&group->matches, group_name.buf,
282 matches);
283 }
284
285 if (c->date <= group->stable_threshold) {
286 ALLOC_GROW(matches->stable, matches->stable_nr + 1,
287 matches->stable_alloc);
288 matches->stable[matches->stable_nr++] = c;
289 } else if (c->date <= group->threshold && !has_bitmap) {
290 ALLOC_GROW(matches->unstable, matches->unstable_nr + 1,
291 matches->unstable_alloc);
292 matches->unstable[matches->unstable_nr++] = c;
293 }
294
295 strbuf_release(&group_name);
296 }
297
298 return 0;
299 }
300
301 static struct commit *push_pseudo_merge(struct pseudo_merge_group *group)
302 {
303 struct commit *merge;
304
305 ALLOC_GROW(group->merges, group->merges_nr + 1, group->merges_alloc);
306
307 merge = alloc_commit_node(the_repository);
308 merge->object.parsed = 1;
309 merge->object.flags |= BITMAP_PSEUDO_MERGE;
310
311 group->merges[group->merges_nr++] = merge;
312
313 return merge;
314 }
315
316 static struct pseudo_merge_commit_idx *pseudo_merge_idx(kh_oid_map_t *pseudo_merge_commits,
317 const struct object_id *oid)
318
319 {
320 struct pseudo_merge_commit_idx *pmc;
321 int hash_ret;
322 khiter_t hash_pos = kh_put_oid_map(pseudo_merge_commits, *oid,
323 &hash_ret);
324
325 if (hash_ret) {
326 CALLOC_ARRAY(pmc, 1);
327 kh_value(pseudo_merge_commits, hash_pos) = pmc;
328 } else {
329 pmc = kh_value(pseudo_merge_commits, hash_pos);
330 }
331
332 return pmc;
333 }
334
335 #define MIN_PSEUDO_MERGE_SIZE 8
336
337 static void select_pseudo_merges_1(struct bitmap_writer *writer,
338 struct pseudo_merge_group *group,
339 struct pseudo_merge_matches *matches)
340 {
341 uint32_t i, j;
342 uint32_t stable_merges_nr;
343
344 if (!matches->stable_nr && !matches->unstable_nr)
345 return; /* all tips in this group already have bitmaps */
346
347 stable_merges_nr = matches->stable_nr / group->stable_size;
348 if (matches->stable_nr % group->stable_size)
349 stable_merges_nr++;
350
351 /* make stable_merges_nr pseudo merges for stable commits */
352 for (i = 0, j = 0; i < stable_merges_nr; i++) {
353 struct commit *merge;
354 struct commit_list **p;
355
356 merge = push_pseudo_merge(group);
357 p = &merge->parents;
358
359 /*
360 * For each pseudo-merge created above, add parents to the
361 * allocated commit node from the stable set of commits
362 * (un-bitmapped, newer than the stable threshold).
363 */
364 do {
365 struct commit *c;
366 struct pseudo_merge_commit_idx *pmc;
367
368 if (j >= matches->stable_nr)
369 break;
370
371 c = matches->stable[j++];
372 /*
373 * Here and below, make sure that we keep our mapping of
374 * commits -> pseudo-merge(s) which include the key'd
375 * commit up-to-date.
376 */
377 pmc = pseudo_merge_idx(writer->pseudo_merge_commits,
378 &c->object.oid);
379
380 ALLOC_GROW(pmc->pseudo_merge, pmc->nr + 1, pmc->alloc);
381
382 pmc->pseudo_merge[pmc->nr++] = writer->pseudo_merges_nr;
383 p = commit_list_append(c, p);
384 } while (j % group->stable_size);
385
386 if (merge->parents) {
387 bitmap_writer_push_commit(writer, merge, 1);
388 writer->pseudo_merges_nr++;
389 }
390 }
391
392 /* make up to group->max_merges pseudo merges for unstable commits */
393 for (i = 0, j = 0; i < group->max_merges; i++) {
394 struct commit *merge;
395 struct commit_list **p;
396 uint32_t size, end;
397
398 merge = push_pseudo_merge(group);
399 p = &merge->parents;
400
401 size = pseudo_merge_group_size(group, matches, i);
402 end = size < MIN_PSEUDO_MERGE_SIZE ? matches->unstable_nr : j + size;
403
404 /*
405 * For each pseudo-merge commit created above, add parents to
406 * the allocated commit node from the unstable set of commits
407 * (newer than the stable threshold).
408 *
409 * Account for the sample rate, since not every candidate from
410 * the set of stable commits will be included as a pseudo-merge
411 * parent.
412 */
413 for (; j < end && j < matches->unstable_nr; j++) {
414 struct commit *c = matches->unstable[j];
415 struct pseudo_merge_commit_idx *pmc;
416
417 if (j % (uint32_t)(1.0 / group->sample_rate))
418 continue;
419
420 pmc = pseudo_merge_idx(writer->pseudo_merge_commits,
421 &c->object.oid);
422
423 ALLOC_GROW(pmc->pseudo_merge, pmc->nr + 1, pmc->alloc);
424
425 pmc->pseudo_merge[pmc->nr++] = writer->pseudo_merges_nr;
426 p = commit_list_append(c, p);
427 }
428
429 if (merge->parents) {
430 bitmap_writer_push_commit(writer, merge, 1);
431 writer->pseudo_merges_nr++; }
432 if (end >= matches->unstable_nr)
433 break;
434 }
435 }
436
437 static int commit_date_cmp(const void *va, const void *vb)
438 {
439 timestamp_t a = (*(const struct commit **)va)->date;
440 timestamp_t b = (*(const struct commit **)vb)->date;
441
442 if (a < b)
443 return -1;
444 else if (a > b)
445 return 1;
446 return 0;
447 }
448
449 static void sort_pseudo_merge_matches(struct pseudo_merge_matches *matches)
450 {
451 QSORT(matches->stable, matches->stable_nr, commit_date_cmp);
452 QSORT(matches->unstable, matches->unstable_nr, commit_date_cmp);
453 }
454
455 void select_pseudo_merges(struct bitmap_writer *writer)
456 {
457 struct progress *progress = NULL;
458 uint32_t i;
459
460 if (!writer->pseudo_merge_groups.nr)
461 return;
462
463 if (writer->show_progress)
464 progress = start_progress(the_repository,
465 "Selecting pseudo-merge commits",
466 writer->pseudo_merge_groups.nr);
467
468 refs_for_each_ref(get_main_ref_store(the_repository),
469 find_pseudo_merge_group_for_ref, writer);
470
471 for (i = 0; i < writer->pseudo_merge_groups.nr; i++) {
472 struct pseudo_merge_group *group;
473 struct hashmap_iter iter;
474 struct strmap_entry *e;
475
476 group = writer->pseudo_merge_groups.items[i].util;
477 strmap_for_each_entry(&group->matches, &iter, e) {
478 struct pseudo_merge_matches *matches = e->value;
479
480 sort_pseudo_merge_matches(matches);
481
482 select_pseudo_merges_1(writer, group, matches);
483 }
484
485 display_progress(progress, i + 1);
486 }
487
488 stop_progress(&progress);
489 }
490
491 void free_pseudo_merge_map(struct pseudo_merge_map *pm)
492 {
493 uint32_t i;
494 for (i = 0; i < pm->nr; i++) {
495 ewah_pool_free(pm->v[i].commits);
496 ewah_pool_free(pm->v[i].bitmap);
497 }
498 free(pm->v);
499 }
500
501 struct pseudo_merge_commit_ext {
502 uint32_t nr;
503 const unsigned char *ptr;
504 };
505
506 static int pseudo_merge_ext_at(const struct pseudo_merge_map *pm,
507 struct pseudo_merge_commit_ext *ext, size_t at)
508 {
509 if (at >= pm->map_size)
510 return error(_("extended pseudo-merge read out-of-bounds "
511 "(%"PRIuMAX" >= %"PRIuMAX")"),
512 (uintmax_t)at, (uintmax_t)pm->map_size);
513 if (at + 4 >= pm->map_size)
514 return error(_("extended pseudo-merge entry is too short "
515 "(%"PRIuMAX" >= %"PRIuMAX")"),
516 (uintmax_t)(at + 4), (uintmax_t)pm->map_size);
517
518 ext->nr = get_be32(pm->map + at);
519 ext->ptr = pm->map + at + sizeof(uint32_t);
520
521 return 0;
522 }
523
524 struct ewah_bitmap *pseudo_merge_bitmap(const struct pseudo_merge_map *pm,
525 struct pseudo_merge *merge)
526 {
527 if (!merge->loaded_commits)
528 BUG("cannot use unloaded pseudo-merge bitmap");
529
530 if (!merge->loaded_bitmap) {
531 size_t at = merge->bitmap_at;
532
533 merge->bitmap = read_bitmap(pm->map, pm->map_size, &at);
534 merge->loaded_bitmap = 1;
535 }
536
537 return merge->bitmap;
538 }
539
540 struct pseudo_merge *use_pseudo_merge(const struct pseudo_merge_map *pm,
541 struct pseudo_merge *merge)
542 {
543 if (!merge->loaded_commits) {
544 size_t pos = merge->at;
545
546 merge->commits = read_bitmap(pm->map, pm->map_size, &pos);
547 merge->bitmap_at = pos;
548 merge->loaded_commits = 1;
549 }
550 return merge;
551 }
552
553 static struct pseudo_merge *pseudo_merge_at(const struct pseudo_merge_map *pm,
554 struct object_id *oid,
555 size_t want)
556 {
557 size_t lo = 0;
558 size_t hi = pm->nr;
559
560 while (lo < hi) {
561 size_t mi = lo + (hi - lo) / 2;
562 size_t got = pm->v[mi].at;
563
564 if (got == want)
565 return use_pseudo_merge(pm, &pm->v[mi]);
566 else if (got < want)
567 lo = mi + 1;
568 else
569 hi = mi;
570 }
571
572 warning(_("could not find pseudo-merge for commit %s at offset %"PRIuMAX),
573 oid_to_hex(oid), (uintmax_t)want);
574
575 return NULL;
576 }
577
578 struct pseudo_merge_commit {
579 uint32_t commit_pos;
580 uint64_t pseudo_merge_ofs;
581 };
582
583 #define PSEUDO_MERGE_COMMIT_RAWSZ (sizeof(uint32_t)+sizeof(uint64_t))
584
585 static void read_pseudo_merge_commit_at(struct pseudo_merge_commit *merge,
586 const unsigned char *at)
587 {
588 merge->commit_pos = get_be32(at);
589 merge->pseudo_merge_ofs = get_be64(at + sizeof(uint32_t));
590 }
591
592 static int nth_pseudo_merge_ext(const struct pseudo_merge_map *pm,
593 struct pseudo_merge_commit_ext *ext,
594 struct pseudo_merge_commit *merge,
595 uint32_t n)
596 {
597 size_t ofs;
598
599 if (n >= ext->nr)
600 return error(_("extended pseudo-merge lookup out-of-bounds "
601 "(%"PRIu32" >= %"PRIu32")"), n, ext->nr);
602
603 ofs = get_be64(ext->ptr + st_mult(n, sizeof(uint64_t)));
604 if (ofs >= pm->map_size)
605 return error(_("out-of-bounds read: (%"PRIuMAX" >= %"PRIuMAX")"),
606 (uintmax_t)ofs, (uintmax_t)pm->map_size);
607
608 merge->pseudo_merge_ofs = ofs;
609
610 return 0;
611 }
612
613 static unsigned apply_pseudo_merge(const struct pseudo_merge_map *pm,
614 struct pseudo_merge *merge,
615 struct bitmap *result,
616 struct bitmap *roots)
617 {
618 if (merge->satisfied)
619 return 0;
620
621 if (!ewah_bitmap_is_subset(merge->commits, roots ? roots : result))
622 return 0;
623
624 bitmap_or_ewah(result, pseudo_merge_bitmap(pm, merge));
625 if (roots)
626 bitmap_or_ewah(roots, pseudo_merge_bitmap(pm, merge));
627 merge->satisfied = 1;
628
629 return 1;
630 }
631
632 static int pseudo_merge_commit_cmp(const void *va, const void *vb)
633 {
634 struct pseudo_merge_commit merge;
635 uint32_t key = *(uint32_t*)va;
636
637 read_pseudo_merge_commit_at(&merge, vb);
638
639 if (key < merge.commit_pos)
640 return -1;
641 if (key > merge.commit_pos)
642 return 1;
643 return 0;
644 }
645
646 static int find_pseudo_merge(const struct pseudo_merge_map *pm, uint32_t pos,
647 struct pseudo_merge_commit *out)
648 {
649 const unsigned char *at;
650
651 if (!pm->commits_nr)
652 return 0;
653
654 at = bsearch(&pos, pm->commits, pm->commits_nr,
655 PSEUDO_MERGE_COMMIT_RAWSZ, pseudo_merge_commit_cmp);
656 if (!at)
657 return 0;
658
659 read_pseudo_merge_commit_at(out, at);
660 return 1;
661 }
662
663 int apply_pseudo_merges_for_commit(const struct pseudo_merge_map *pm,
664 struct bitmap *result,
665 struct commit *commit, uint32_t commit_pos)
666 {
667 struct pseudo_merge *merge;
668 struct pseudo_merge_commit merge_commit;
669 int ret = 0;
670
671 if (!find_pseudo_merge(pm, commit_pos, &merge_commit))
672 return 0;
673
674 if (merge_commit.pseudo_merge_ofs & ((uint64_t)1<<63)) {
675 struct pseudo_merge_commit_ext ext = { 0 };
676 off_t ofs = merge_commit.pseudo_merge_ofs & ~((uint64_t)1<<63);
677 uint32_t i;
678
679 if (pseudo_merge_ext_at(pm, &ext, ofs) < 0) {
680 warning(_("could not read extended pseudo-merge table "
681 "for commit %s"),
682 oid_to_hex(&commit->object.oid));
683 return ret;
684 }
685
686 for (i = 0; i < ext.nr; i++) {
687 if (nth_pseudo_merge_ext(pm, &ext, &merge_commit, i) < 0)
688 return ret;
689
690 merge = pseudo_merge_at(pm, &commit->object.oid,
691 merge_commit.pseudo_merge_ofs);
692
693 if (!merge)
694 return ret;
695
696 if (apply_pseudo_merge(pm, merge, result, NULL))
697 ret++;
698 }
699 } else {
700 merge = pseudo_merge_at(pm, &commit->object.oid,
701 merge_commit.pseudo_merge_ofs);
702
703 if (!merge)
704 return ret;
705
706 if (apply_pseudo_merge(pm, merge, result, NULL))
707 ret++;
708 }
709
710 if (ret)
711 cascade_pseudo_merges(pm, result, NULL);
712
713 return ret;
714 }
715
716 int cascade_pseudo_merges(const struct pseudo_merge_map *pm,
717 struct bitmap *result,
718 struct bitmap *roots)
719 {
720 unsigned any_satisfied;
721 int ret = 0;
722
723 do {
724 struct pseudo_merge *merge;
725 uint32_t i;
726
727 any_satisfied = 0;
728
729 for (i = 0; i < pm->nr; i++) {
730 merge = use_pseudo_merge(pm, &pm->v[i]);
731 if (apply_pseudo_merge(pm, merge, result, roots)) {
732 any_satisfied |= 1;
733 ret++;
734 }
735 }
736 } while (any_satisfied);
737
738 return ret;
739 }
740
741 struct pseudo_merge *pseudo_merge_for_parents(const struct pseudo_merge_map *pm,
742 struct bitmap *parents)
743 {
744 struct pseudo_merge *match = NULL;
745 size_t i;
746
747 if (!pm->nr)
748 return NULL;
749
750 /*
751 * NOTE: this loop is quadratic in the worst-case (where no
752 * matching pseudo-merge bitmaps are found), but in practice
753 * this is OK for a few reasons:
754 *
755 * - Rejecting pseudo-merge bitmaps that do not match the
756 * given commit is done quickly (i.e. `bitmap_equals_ewah()`
757 * returns early when we know the two bitmaps aren't equal.
758 *
759 * - Already matched pseudo-merge bitmaps (which we track with
760 * the `->satisfied` bit here) are skipped as potential
761 * candidates.
762 *
763 * - The number of pseudo-merges should be small (in the
764 * hundreds for most repositories).
765 *
766 * If in the future this semi-quadratic behavior does become a
767 * problem, another approach would be to keep track of which
768 * pseudo-merges are still "viable" after enumerating the
769 * pseudo-merge commit's parents:
770 *
771 * - A pseudo-merge bitmap becomes non-viable when the bit(s)
772 * corresponding to one or more parent(s) of the given
773 * commit are not set in a candidate pseudo-merge's commits
774 * bitmap.
775 *
776 * - After processing all bits, enumerate the remaining set of
777 * viable pseudo-merge bitmaps, and check that their
778 * popcount() matches the number of parents in the given
779 * commit.
780 */
781 for (i = 0; i < pm->nr; i++) {
782 struct pseudo_merge *candidate = use_pseudo_merge(pm, &pm->v[i]);
783 if (!candidate || candidate->satisfied)
784 continue;
785 if (!bitmap_equals_ewah(parents, candidate->commits))
786 continue;
787
788 match = candidate;
789 match->satisfied = 1;
790 break;
791 }
792
793 return match;
794 }