Skip to content

Commit 955747b

Browse files
ttaylorrgitster
authored andcommitted
pseudo-merge: implement support for reading pseudo-merge commits
Implement the basic API for reading pseudo-merge bitmaps, which consists of four basic functions: - pseudo_merge_bitmap() - use_pseudo_merge() - apply_pseudo_merges_for_commit() - cascade_pseudo_merges() These functions are all documented in pseudo-merge.h, but their rough descriptions are as follows: - pseudo_merge_bitmap() reads and inflates the objects EWAH bitmap for a given pseudo-merge - use_pseudo_merge() does the same as pseudo_merge_bitmap(), but on the commits EWAH bitmap, not the objects bitmap - apply_pseudo_merges_for_commit() applies all satisfied pseudo-merge commits for a given result set, and cascades any yet-unsatisfied pseudo-merges if any were applied in the previous step - cascade_pseudo_merges() applies all pseudo-merges which are satisfied but have not been previously applied, repeating this process until no more pseudo-merges can be applied The core of the API is the latter two functions, which are responsible for applying pseudo-merges during the object traversal implemented in the pack-bitmap machinery. The other two functions (pseudo_merge_bitmap(), and use_pseudo_merge()) are low-level ways to interact with the pseudo-merge machinery, which will be useful in future commits. Signed-off-by: Taylor Blau <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 7c0fae8 commit 955747b

File tree

2 files changed

+279
-0
lines changed

2 files changed

+279
-0
lines changed

pseudo-merge.c

Lines changed: 235 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#include "commit.h"
1111
#include "alloc.h"
1212
#include "progress.h"
13+
#include "hex.h"
1314

1415
#define DEFAULT_PSEUDO_MERGE_DECAY 1.0
1516
#define DEFAULT_PSEUDO_MERGE_MAX_MERGES 64
@@ -464,3 +465,237 @@ void free_pseudo_merge_map(struct pseudo_merge_map *pm)
464465
}
465466
free(pm->v);
466467
}
468+
469+
struct pseudo_merge_commit_ext {
470+
uint32_t nr;
471+
const unsigned char *ptr;
472+
};
473+
474+
static int pseudo_merge_ext_at(const struct pseudo_merge_map *pm,
475+
struct pseudo_merge_commit_ext *ext, size_t at)
476+
{
477+
if (at >= pm->map_size)
478+
return error(_("extended pseudo-merge read out-of-bounds "
479+
"(%"PRIuMAX" >= %"PRIuMAX")"),
480+
(uintmax_t)at, (uintmax_t)pm->map_size);
481+
if (at + 4 >= pm->map_size)
482+
return error(_("extended pseudo-merge entry is too short "
483+
"(%"PRIuMAX" >= %"PRIuMAX")"),
484+
(uintmax_t)(at + 4), (uintmax_t)pm->map_size);
485+
486+
ext->nr = get_be32(pm->map + at);
487+
ext->ptr = pm->map + at + sizeof(uint32_t);
488+
489+
return 0;
490+
}
491+
492+
struct ewah_bitmap *pseudo_merge_bitmap(const struct pseudo_merge_map *pm,
493+
struct pseudo_merge *merge)
494+
{
495+
if (!merge->loaded_commits)
496+
BUG("cannot use unloaded pseudo-merge bitmap");
497+
498+
if (!merge->loaded_bitmap) {
499+
size_t at = merge->bitmap_at;
500+
501+
merge->bitmap = read_bitmap(pm->map, pm->map_size, &at);
502+
merge->loaded_bitmap = 1;
503+
}
504+
505+
return merge->bitmap;
506+
}
507+
508+
struct pseudo_merge *use_pseudo_merge(const struct pseudo_merge_map *pm,
509+
struct pseudo_merge *merge)
510+
{
511+
if (!merge->loaded_commits) {
512+
size_t pos = merge->at;
513+
514+
merge->commits = read_bitmap(pm->map, pm->map_size, &pos);
515+
merge->bitmap_at = pos;
516+
merge->loaded_commits = 1;
517+
}
518+
return merge;
519+
}
520+
521+
static struct pseudo_merge *pseudo_merge_at(const struct pseudo_merge_map *pm,
522+
struct object_id *oid,
523+
size_t want)
524+
{
525+
size_t lo = 0;
526+
size_t hi = pm->nr;
527+
528+
while (lo < hi) {
529+
size_t mi = lo + (hi - lo) / 2;
530+
size_t got = pm->v[mi].at;
531+
532+
if (got == want)
533+
return use_pseudo_merge(pm, &pm->v[mi]);
534+
else if (got < want)
535+
hi = mi;
536+
else
537+
lo = mi + 1;
538+
}
539+
540+
warning(_("could not find pseudo-merge for commit %s at offset %"PRIuMAX),
541+
oid_to_hex(oid), (uintmax_t)want);
542+
543+
return NULL;
544+
}
545+
546+
struct pseudo_merge_commit {
547+
uint32_t commit_pos;
548+
uint64_t pseudo_merge_ofs;
549+
};
550+
551+
#define PSEUDO_MERGE_COMMIT_RAWSZ (sizeof(uint32_t)+sizeof(uint64_t))
552+
553+
static void read_pseudo_merge_commit_at(struct pseudo_merge_commit *merge,
554+
const unsigned char *at)
555+
{
556+
merge->commit_pos = get_be32(at);
557+
merge->pseudo_merge_ofs = get_be64(at + sizeof(uint32_t));
558+
}
559+
560+
static int nth_pseudo_merge_ext(const struct pseudo_merge_map *pm,
561+
struct pseudo_merge_commit_ext *ext,
562+
struct pseudo_merge_commit *merge,
563+
uint32_t n)
564+
{
565+
size_t ofs;
566+
567+
if (n >= ext->nr)
568+
return error(_("extended pseudo-merge lookup out-of-bounds "
569+
"(%"PRIu32" >= %"PRIu32")"), n, ext->nr);
570+
571+
ofs = get_be64(ext->ptr + st_mult(n, sizeof(uint64_t)));
572+
if (ofs >= pm->map_size)
573+
return error(_("out-of-bounds read: (%"PRIuMAX" >= %"PRIuMAX")"),
574+
(uintmax_t)ofs, (uintmax_t)pm->map_size);
575+
576+
read_pseudo_merge_commit_at(merge, pm->map + ofs);
577+
578+
return 0;
579+
}
580+
581+
static unsigned apply_pseudo_merge(const struct pseudo_merge_map *pm,
582+
struct pseudo_merge *merge,
583+
struct bitmap *result,
584+
struct bitmap *roots)
585+
{
586+
if (merge->satisfied)
587+
return 0;
588+
589+
if (!ewah_bitmap_is_subset(merge->commits, roots ? roots : result))
590+
return 0;
591+
592+
bitmap_or_ewah(result, pseudo_merge_bitmap(pm, merge));
593+
if (roots)
594+
bitmap_or_ewah(roots, pseudo_merge_bitmap(pm, merge));
595+
merge->satisfied = 1;
596+
597+
return 1;
598+
}
599+
600+
static int pseudo_merge_commit_cmp(const void *va, const void *vb)
601+
{
602+
struct pseudo_merge_commit merge;
603+
uint32_t key = *(uint32_t*)va;
604+
605+
read_pseudo_merge_commit_at(&merge, vb);
606+
607+
if (key < merge.commit_pos)
608+
return -1;
609+
if (key > merge.commit_pos)
610+
return 1;
611+
return 0;
612+
}
613+
614+
static struct pseudo_merge_commit *find_pseudo_merge(const struct pseudo_merge_map *pm,
615+
uint32_t pos)
616+
{
617+
if (!pm->commits_nr)
618+
return NULL;
619+
620+
return bsearch(&pos, pm->commits, pm->commits_nr,
621+
PSEUDO_MERGE_COMMIT_RAWSZ, pseudo_merge_commit_cmp);
622+
}
623+
624+
int apply_pseudo_merges_for_commit(const struct pseudo_merge_map *pm,
625+
struct bitmap *result,
626+
struct commit *commit, uint32_t commit_pos)
627+
{
628+
struct pseudo_merge *merge;
629+
struct pseudo_merge_commit *merge_commit;
630+
int ret = 0;
631+
632+
merge_commit = find_pseudo_merge(pm, commit_pos);
633+
if (!merge_commit)
634+
return 0;
635+
636+
if (merge_commit->pseudo_merge_ofs & ((uint64_t)1<<63)) {
637+
struct pseudo_merge_commit_ext ext = { 0 };
638+
off_t ofs = merge_commit->pseudo_merge_ofs & ~((uint64_t)1<<63);
639+
uint32_t i;
640+
641+
if (pseudo_merge_ext_at(pm, &ext, ofs) < -1) {
642+
warning(_("could not read extended pseudo-merge table "
643+
"for commit %s"),
644+
oid_to_hex(&commit->object.oid));
645+
return ret;
646+
}
647+
648+
for (i = 0; i < ext.nr; i++) {
649+
if (nth_pseudo_merge_ext(pm, &ext, merge_commit, i) < 0)
650+
return ret;
651+
652+
merge = pseudo_merge_at(pm, &commit->object.oid,
653+
merge_commit->pseudo_merge_ofs);
654+
655+
if (!merge)
656+
return ret;
657+
658+
if (apply_pseudo_merge(pm, merge, result, NULL))
659+
ret++;
660+
}
661+
} else {
662+
merge = pseudo_merge_at(pm, &commit->object.oid,
663+
merge_commit->pseudo_merge_ofs);
664+
665+
if (!merge)
666+
return ret;
667+
668+
if (apply_pseudo_merge(pm, merge, result, NULL))
669+
ret++;
670+
}
671+
672+
if (ret)
673+
cascade_pseudo_merges(pm, result, NULL);
674+
675+
return ret;
676+
}
677+
678+
int cascade_pseudo_merges(const struct pseudo_merge_map *pm,
679+
struct bitmap *result,
680+
struct bitmap *roots)
681+
{
682+
unsigned any_satisfied;
683+
int ret = 0;
684+
685+
do {
686+
struct pseudo_merge *merge;
687+
uint32_t i;
688+
689+
any_satisfied = 0;
690+
691+
for (i = 0; i < pm->nr; i++) {
692+
merge = use_pseudo_merge(pm, &pm->v[i]);
693+
if (apply_pseudo_merge(pm, merge, result, roots)) {
694+
any_satisfied |= 1;
695+
ret++;
696+
}
697+
}
698+
} while (any_satisfied);
699+
700+
return ret;
701+
}

pseudo-merge.h

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,4 +162,48 @@ struct pseudo_merge {
162162
*/
163163
void free_pseudo_merge_map(struct pseudo_merge_map *pm);
164164

165+
/*
166+
* Loads the bitmap corresponding to the given pseudo-merge from the
167+
* map, if it has not already been loaded.
168+
*/
169+
struct ewah_bitmap *pseudo_merge_bitmap(const struct pseudo_merge_map *pm,
170+
struct pseudo_merge *merge);
171+
172+
/*
173+
* Loads the pseudo-merge and its commits bitmap from the given
174+
* pseudo-merge map, if it has not already been loaded.
175+
*/
176+
struct pseudo_merge *use_pseudo_merge(const struct pseudo_merge_map *pm,
177+
struct pseudo_merge *merge);
178+
179+
/*
180+
* Applies pseudo-merge(s) containing the given commit to the bitmap
181+
* "result".
182+
*
183+
* If any pseudo-merge(s) were satisfied, returns the number
184+
* satisfied, otherwise returns 0. If any were satisfied, the
185+
* remaining unsatisfied pseudo-merges are cascaded (see below).
186+
*/
187+
int apply_pseudo_merges_for_commit(const struct pseudo_merge_map *pm,
188+
struct bitmap *result,
189+
struct commit *commit, uint32_t commit_pos);
190+
191+
/*
192+
* Applies pseudo-merge(s) which are satisfied according to the
193+
* current bitmap in result (or roots, see below). If any
194+
* pseudo-merges were satisfied, repeat the process over unsatisfied
195+
* pseudo-merge commits until no more pseudo-merges are satisfied.
196+
*
197+
* Result is the bitmap to which the pseudo-merge(s) are applied.
198+
* Roots (if given) is a bitmap of the traversal tip(s) for either
199+
* side of a reachability traversal.
200+
*
201+
* Roots may given instead of a populated results bitmap at the
202+
* beginning of a traversal on either side where the reachability
203+
* closure over tips is not yet known.
204+
*/
205+
int cascade_pseudo_merges(const struct pseudo_merge_map *pm,
206+
struct bitmap *result,
207+
struct bitmap *roots);
208+
165209
#endif

0 commit comments

Comments
 (0)