repack: teach MIDX retention about geometric rollups

When writing an incremental MIDX, existing_packs_retain_midx_packs()
marks packs in the existing MIDX chain as retained. This keeps them from
being deleted by the later existing_packs deletion pass, since retained
MIDX layers may still refer to those packs.

Geometric repacks need a narrower rule. Packs below the split are rolled
up into the newly-written pack, and should remain eligible for deletion
even if the old MIDX chain mentions them. Packs above the split were
marked as retained by the previous commit.

Teach existing_packs_retain_midx_packs() to skip packs which are part of
the geometric rollup. This does not change the current caller's behavior,
since geometric repacks do not yet use the existing_packs deletion path.

Signed-off-by: Taylor Blau <me@ttaylorr.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
seen
Taylor Blau 2026-06-26 15:02:23 -04:00 committed by Junio C Hamano
parent 3e38d04bd4
commit 5ff781e9fa
3 changed files with 44 additions and 4 deletions

View File

@ -576,7 +576,7 @@ int cmd_repack(int argc,

if (delete_redundant && pack_everything & ALL_INTO_ONE) {
if (write_midx == REPACK_WRITE_MIDX_INCREMENTAL)
existing_packs_retain_midx_packs(&existing);
existing_packs_retain_midx_packs(&existing, &geometry);
existing_packs_mark_for_deletion(&existing, &names);
}


View File

@ -292,6 +292,39 @@ void existing_packs_mark_for_deletion(struct existing_packs *existing,
&existing->cruft_packs);
}

static int pack_geometry_contains_pack(struct packed_git **packs,
uint32_t packs_nr,
const char *base)
{
struct strbuf buf = STRBUF_INIT;
uint32_t i;

for (i = 0; i < packs_nr; i++) {
strbuf_reset(&buf);
strbuf_addstr(&buf, pack_basename(packs[i]));
strbuf_strip_suffix(&buf, ".pack");

if (!strcmp(buf.buf, base)) {
strbuf_release(&buf);
return 1;
}
}

strbuf_release(&buf);
return 0;
}

static int pack_geometry_contains_rollup(const struct pack_geometry *geometry,
const char *base)
{
if (!geometry || !geometry->split_factor)
return 0;

return pack_geometry_contains_pack(geometry->pack, geometry->split, base) ||
pack_geometry_contains_pack(geometry->promisor_pack,
geometry->promisor_split, base);
}

/*
* Mark every pack that is referenced by the existing MIDX chain as
* retained, so that a subsequent call to
@ -300,9 +333,12 @@ void existing_packs_mark_for_deletion(struct existing_packs *existing,
* This is used when writing an incremental MIDX layer on top of an
* existing chain: retained layers continue to reference the same
* packs on disk, so those packs must not be unlinked even if the
* freshly-written pack supersedes them.
* freshly-written pack supersedes them. When doing a geometric repack,
* packs below the split are rewritten into the new MIDX tip and should
* remain eligible for deletion.
*/
void existing_packs_retain_midx_packs(struct existing_packs *existing)
void existing_packs_retain_midx_packs(struct existing_packs *existing,
const struct pack_geometry *geometry)
{
struct string_list_item *item;
struct strbuf buf = STRBUF_INIT;
@ -315,6 +351,9 @@ void existing_packs_retain_midx_packs(struct existing_packs *existing)
strbuf_strip_suffix(&buf, ".pack");
strbuf_strip_suffix(&buf, ".idx");

if (pack_geometry_contains_rollup(geometry, buf.buf))
continue;

found = string_list_lookup(&existing->non_kept_packs, buf.buf);
if (found)
existing_packs_mark_retained(found);

View File

@ -87,7 +87,8 @@ void existing_packs_retain_from_geometry(struct existing_packs *existing,
const struct pack_geometry *geometry);
void existing_packs_mark_for_deletion(struct existing_packs *existing,
struct string_list *names);
void existing_packs_retain_midx_packs(struct existing_packs *existing);
void existing_packs_retain_midx_packs(struct existing_packs *existing,
const struct pack_geometry *geometry);
void existing_packs_remove_redundant(struct existing_packs *existing,
const char *packdir,
bool wrote_incremental_midx);