Skip to content

Commit 5af82f7

Browse files
committed
Merge branch 'tb/pseudo-merge-bugfixes' into seen
* tb/pseudo-merge-bugfixes: pack-bitmap: prevent pattern leak on pseudo-merge re-assignment pack-bitmap: reject pseudo-merge "sampleRate" of 0 pack-bitmap: parse commits in `find_pseudo_merge_group_for_ref()` pack-bitmap: fix pseudo-merge lookup for shared commits pack-bitmap: fix inverted binary search in `pseudo_merge_at()` pack-bitmap-write: sort pseudo-merge commit lookup table in pack order t5333: demonstrate various pseudo-merge bugs t/helper: add 'test-tool bitmap write' subcommand
2 parents d1c7b6d + 0cc702d commit 5af82f7

File tree

5 files changed

+396
-10
lines changed

5 files changed

+396
-10
lines changed

pack-bitmap-write.c

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -819,6 +819,20 @@ static void write_selected_commits_v1(struct bitmap_writer *writer,
819819
}
820820
}
821821

822+
static int pseudo_merge_commit_pos_cmp(const void *_va, const void *_vb,
823+
void *_data)
824+
{
825+
struct bitmap_writer *writer = _data;
826+
uint32_t pos_a = find_object_pos(writer, _va, NULL);
827+
uint32_t pos_b = find_object_pos(writer, _vb, NULL);
828+
829+
if (pos_a < pos_b)
830+
return -1;
831+
if (pos_a > pos_b)
832+
return 1;
833+
return 0;
834+
}
835+
822836
static void write_pseudo_merges(struct bitmap_writer *writer,
823837
struct hashfile *f)
824838
{
@@ -863,7 +877,7 @@ static void write_pseudo_merges(struct bitmap_writer *writer,
863877

864878
next_ext = st_add(hashfile_total(f),
865879
st_mult(kh_size(writer->pseudo_merge_commits),
866-
sizeof(uint64_t)));
880+
sizeof(uint32_t) + sizeof(uint64_t)));
867881

868882
table_start = hashfile_total(f);
869883

@@ -876,7 +890,12 @@ static void write_pseudo_merges(struct bitmap_writer *writer,
876890
oid_array_append(&commits, &kh_key(writer->pseudo_merge_commits, i));
877891
}
878892

879-
oid_array_sort(&commits);
893+
/*
894+
* Sort the commits by their bit position so that the lookup
895+
* table can be binary searched by the reader (see
896+
* find_pseudo_merge()).
897+
*/
898+
QSORT_S(commits.oid, commits.nr, pseudo_merge_commit_pos_cmp, writer);
880899

881900
/* write lookup table (non-extended) */
882901
for (i = 0; i < commits.nr; i++) {

pseudo-merge.c

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,10 @@ static int pseudo_merge_config(const char *var, const char *value,
150150
if (!strcmp(key, "pattern")) {
151151
struct strbuf re = STRBUF_INIT;
152152

153-
free(group->pattern);
153+
if (group->pattern) {
154+
regfree(group->pattern);
155+
free(group->pattern);
156+
}
154157
if (*value != '^')
155158
strbuf_addch(&re, '^');
156159
strbuf_addstr(&re, value);
@@ -169,8 +172,8 @@ static int pseudo_merge_config(const char *var, const char *value,
169172
}
170173
} else if (!strcmp(key, "samplerate")) {
171174
group->sample_rate = git_config_double(var, value, ctx->kvi);
172-
if (!(0 <= group->sample_rate && group->sample_rate <= 1)) {
173-
warning(_("%s must be between 0 and 1, using default"), var);
175+
if (!(0 < group->sample_rate && group->sample_rate <= 1)) {
176+
warning(_("%s must be between 0 (exclusive) and 1, using default"), var);
174177
group->sample_rate = DEFAULT_PSEUDO_MERGE_SAMPLE_RATE;
175178
}
176179
} else if (!strcmp(key, "threshold")) {
@@ -236,6 +239,8 @@ static int find_pseudo_merge_group_for_ref(const struct reference *ref, void *_d
236239
c = lookup_commit(the_repository, maybe_peeled);
237240
if (!c)
238241
return 0;
242+
if (repo_parse_commit(the_repository, c))
243+
return 0;
239244
if (!packlist_find(writer->to_pack, maybe_peeled))
240245
return 0;
241246

@@ -559,9 +564,9 @@ static struct pseudo_merge *pseudo_merge_at(const struct pseudo_merge_map *pm,
559564
if (got == want)
560565
return use_pseudo_merge(pm, &pm->v[mi]);
561566
else if (got < want)
562-
hi = mi;
563-
else
564567
lo = mi + 1;
568+
else
569+
hi = mi;
565570
}
566571

567572
warning(_("could not find pseudo-merge for commit %s at offset %"PRIuMAX),
@@ -600,7 +605,7 @@ static int nth_pseudo_merge_ext(const struct pseudo_merge_map *pm,
600605
return error(_("out-of-bounds read: (%"PRIuMAX" >= %"PRIuMAX")"),
601606
(uintmax_t)ofs, (uintmax_t)pm->map_size);
602607

603-
read_pseudo_merge_commit_at(merge, pm->map + ofs);
608+
merge->pseudo_merge_ofs = ofs;
604609

605610
return 0;
606611
}
@@ -671,7 +676,7 @@ int apply_pseudo_merges_for_commit(const struct pseudo_merge_map *pm,
671676
off_t ofs = merge_commit.pseudo_merge_ofs & ~((uint64_t)1<<63);
672677
uint32_t i;
673678

674-
if (pseudo_merge_ext_at(pm, &ext, ofs) < -1) {
679+
if (pseudo_merge_ext_at(pm, &ext, ofs) < 0) {
675680
warning(_("could not read extended pseudo-merge table "
676681
"for commit %s"),
677682
oid_to_hex(&commit->object.oid));

t/helper/test-bitmap.c

Lines changed: 109 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,10 @@
22

33
#include "test-tool.h"
44
#include "git-compat-util.h"
5+
#include "hex.h"
6+
#include "odb.h"
57
#include "pack-bitmap.h"
8+
#include "pseudo-merge.h"
69
#include "setup.h"
710

811
static int bitmap_list_commits(void)
@@ -35,6 +38,108 @@ static int bitmap_dump_pseudo_merge_objects(uint32_t n)
3538
return test_bitmap_pseudo_merge_objects(the_repository, n);
3639
}
3740

41+
struct bitmap_writer_data {
42+
struct packing_data packed;
43+
struct pack_idx_entry **index;
44+
uint32_t nr;
45+
};
46+
47+
static int add_packed_object(const struct object_id *oid,
48+
struct packed_git *pack,
49+
uint32_t pos,
50+
void *_data)
51+
{
52+
struct bitmap_writer_data *data = _data;
53+
struct object_entry *entry;
54+
struct object_info oi = OBJECT_INFO_INIT;
55+
enum object_type type;
56+
57+
oi.typep = &type;
58+
59+
entry = packlist_alloc(&data->packed, oid);
60+
entry->idx.offset = nth_packed_object_offset(pack, pos);
61+
if (packed_object_info(pack, entry->idx.offset, &oi) < 0)
62+
die("could not get type of object %s",
63+
oid_to_hex(oid));
64+
oe_set_type(entry, type);
65+
oe_set_in_pack(&data->packed, entry, pack);
66+
data->index[data->nr++] = &entry->idx;
67+
68+
return 0;
69+
}
70+
71+
static int idx_oid_cmp(const void *va, const void *vb)
72+
{
73+
const struct pack_idx_entry *a = *(const struct pack_idx_entry **)va;
74+
const struct pack_idx_entry *b = *(const struct pack_idx_entry **)vb;
75+
76+
return oidcmp(&a->oid, &b->oid);
77+
}
78+
79+
static int bitmap_write(const char *basename)
80+
{
81+
struct packed_git *p = NULL;
82+
struct bitmap_writer_data data = { 0 };
83+
struct bitmap_writer writer;
84+
struct strbuf buf = STRBUF_INIT;
85+
86+
prepare_repo_settings(the_repository);
87+
repo_for_each_pack(the_repository, p) {
88+
if (!strcmp(pack_basename(p), basename))
89+
break;
90+
}
91+
92+
if (!p)
93+
die("could not find pack '%s'", basename);
94+
95+
if (open_pack_index(p))
96+
die("cannot open pack index for '%s'", p->pack_name);
97+
98+
prepare_packing_data(the_repository, &data.packed);
99+
ALLOC_ARRAY(data.index, p->num_objects);
100+
101+
for_each_object_in_pack(p, add_packed_object, &data,
102+
ODB_FOR_EACH_OBJECT_PACK_ORDER);
103+
104+
bitmap_writer_init(&writer, the_repository, &data.packed, NULL);
105+
bitmap_writer_build_type_index(&writer, data.index);
106+
107+
while (strbuf_getline_lf(&buf, stdin) != EOF) {
108+
struct object_id oid;
109+
struct commit *c;
110+
111+
if (get_oid_hex(buf.buf, &oid))
112+
die("invalid OID: %s", buf.buf);
113+
114+
c = lookup_commit(the_repository, &oid);
115+
if (!c || repo_parse_commit(the_repository, c))
116+
die("could not parse commit %s", buf.buf);
117+
118+
bitmap_writer_push_commit(&writer, c, false);
119+
}
120+
121+
select_pseudo_merges(&writer);
122+
if (bitmap_writer_build(&writer) < 0)
123+
die("failed to build bitmaps");
124+
125+
bitmap_writer_set_checksum(&writer, p->hash);
126+
127+
QSORT(data.index, p->num_objects, idx_oid_cmp);
128+
129+
strbuf_reset(&buf);
130+
strbuf_addstr(&buf, p->pack_name);
131+
strbuf_strip_suffix(&buf, ".pack");
132+
strbuf_addstr(&buf, ".bitmap");
133+
bitmap_writer_finish(&writer, data.index, buf.buf, 0);
134+
135+
bitmap_writer_free(&writer);
136+
strbuf_release(&buf);
137+
free(data.index);
138+
clear_packing_data(&data.packed);
139+
140+
return 0;
141+
}
142+
38143
int cmd__bitmap(int argc, const char **argv)
39144
{
40145
setup_git_directory(the_repository);
@@ -51,13 +156,16 @@ int cmd__bitmap(int argc, const char **argv)
51156
return bitmap_dump_pseudo_merge_commits(atoi(argv[2]));
52157
if (argc == 3 && !strcmp(argv[1], "dump-pseudo-merge-objects"))
53158
return bitmap_dump_pseudo_merge_objects(atoi(argv[2]));
159+
if (argc == 3 && !strcmp(argv[1], "write"))
160+
return bitmap_write(argv[2]);
54161

55162
usage("\ttest-tool bitmap list-commits\n"
56163
"\ttest-tool bitmap list-commits-with-offset\n"
57164
"\ttest-tool bitmap dump-hashes\n"
58165
"\ttest-tool bitmap dump-pseudo-merges\n"
59166
"\ttest-tool bitmap dump-pseudo-merge-commits <n>\n"
60-
"\ttest-tool bitmap dump-pseudo-merge-objects <n>");
167+
"\ttest-tool bitmap dump-pseudo-merge-objects <n>\n"
168+
"\ttest-tool bitmap write <pack-basename> < <commit-list>");
61169

62170
return -1;
63171
}

t/t5310-pack-bitmaps.sh

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -648,4 +648,28 @@ test_expect_success 'truncated bitmap fails gracefully (lookup table)' '
648648
test_grep corrupted.bitmap.index stderr
649649
'
650650

651+
test_expect_success 'test-tool bitmap write' '
652+
git init bitmap-write-helper &&
653+
test_when_finished "rm -fr bitmap-write-helper" &&
654+
(
655+
cd bitmap-write-helper &&
656+
657+
test_commit_bulk 64 &&
658+
git repack -ad &&
659+
660+
pack="$(ls .git/objects/pack/pack-*.pack)" &&
661+
662+
git rev-parse HEAD >commits &&
663+
test-tool bitmap write "$(basename $pack)" <commits &&
664+
665+
test-tool bitmap list-commits | sort >actual &&
666+
sort commits >expect &&
667+
test_cmp expect actual &&
668+
669+
git rev-list --count --objects --use-bitmap-index HEAD >actual &&
670+
git rev-list --count --objects HEAD >expect &&
671+
test_cmp expect actual
672+
)
673+
'
674+
651675
test_done

0 commit comments

Comments
 (0)