Skip to content

Commit ddee370

Browse files
ttaylorrgitster
authored andcommitted
builtin/repack.c: add cruft packs to MIDX during geometric repack
When using cruft packs, the following race can occur when a geometric repack that writes a MIDX bitmap takes place afterwords: - First, create an unreachable object and do an all-into-one cruft repack which stores that object in the repository's cruft pack. - Then make that object reachable. - Finally, do a geometric repack and write a MIDX bitmap. Assuming that we are sufficiently unlucky as to select a commit from the MIDX which reaches that object for bitmapping, then the `git multi-pack-index` process will complain that that object is missing. The reason is because we don't include cruft packs in the MIDX when doing a geometric repack. Since the "make that object reachable" doesn't necessarily mean that we'll create a new copy of that object in one of the packs that will get rolled up as part of a geometric repack, it's possible that the MIDX won't see any copies of that now-reachable object. Of course, it's desirable to avoid including cruft packs in the MIDX because it causes the MIDX to store a bunch of objects which are likely to get thrown away. But excluding that pack does open us up to the above race. This patch demonstrates the bug, and resolves it by including cruft packs in the MIDX even when doing a geometric repack. Signed-off-by: Taylor Blau <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 72263ff commit ddee370

File tree

2 files changed

+46
-3
lines changed

2 files changed

+46
-3
lines changed

builtin/repack.c

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#define PACK_CRUFT 4
2424

2525
#define DELETE_PACK 1
26+
#define CRUFT_PACK 2
2627

2728
static int pack_everything;
2829
static int delta_base_offset = 1;
@@ -159,10 +160,15 @@ static void collect_pack_filenames(struct string_list *fname_nonkept_list,
159160
fname = xmemdupz(e->d_name, len);
160161

161162
if ((extra_keep->nr > 0 && i < extra_keep->nr) ||
162-
(file_exists(mkpath("%s/%s.keep", packdir, fname))))
163+
(file_exists(mkpath("%s/%s.keep", packdir, fname)))) {
163164
string_list_append_nodup(fname_kept_list, fname);
164-
else
165-
string_list_append_nodup(fname_nonkept_list, fname);
165+
} else {
166+
struct string_list_item *item;
167+
item = string_list_append_nodup(fname_nonkept_list,
168+
fname);
169+
if (file_exists(mkpath("%s/%s.mtimes", packdir, fname)))
170+
item->util = (void*)(uintptr_t)CRUFT_PACK;
171+
}
166172
}
167173
closedir(dir);
168174
}
@@ -564,6 +570,17 @@ static void midx_included_packs(struct string_list *include,
564570

565571
string_list_insert(include, strbuf_detach(&buf, NULL));
566572
}
573+
574+
for_each_string_list_item(item, existing_nonkept_packs) {
575+
if (!((uintptr_t)item->util & CRUFT_PACK)) {
576+
/*
577+
* no need to check DELETE_PACK, since we're not
578+
* doing an ALL_INTO_ONE repack
579+
*/
580+
continue;
581+
}
582+
string_list_insert(include, xstrfmt("%s.idx", item->string));
583+
}
567584
} else {
568585
for_each_string_list_item(item, existing_nonkept_packs) {
569586
if ((uintptr_t)item->util & DELETE_PACK)

t/t5329-pack-objects-cruft.sh

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -648,4 +648,30 @@ test_expect_success 'cruft --local drops unreachable objects' '
648648
)
649649
'
650650

651+
test_expect_success 'MIDX bitmaps tolerate reachable cruft objects' '
652+
git init repo &&
653+
test_when_finished "rm -fr repo" &&
654+
(
655+
cd repo &&
656+
657+
test_commit reachable &&
658+
test_commit cruft &&
659+
unreachable="$(git rev-parse cruft)" &&
660+
661+
git reset --hard $unreachable^ &&
662+
git tag -d cruft &&
663+
git reflog expire --all --expire=all &&
664+
665+
git repack --cruft -d &&
666+
667+
# resurrect the unreachable object via a new commit. the
668+
# new commit will get selected for a bitmap, but be
669+
# missing one of its parents from the selected packs.
670+
git reset --hard $unreachable &&
671+
test_commit resurrect &&
672+
673+
git repack --write-midx --write-bitmap-index --geometric=2 -d
674+
)
675+
'
676+
651677
test_done

0 commit comments

Comments
 (0)