Merge branch 'tb/midx-repack-ignore-cruft-packs' into maint-2.38

"git multi-pack-index repack/expire" used to repack unreachable
cruft into a new pack, which have been corrected.
cf. <63a1c3d4-eff3-af10-4263-058c88e74594@github.com>

* tb/midx-repack-ignore-cruft-packs:
  midx.c: avoid cruft packs with non-zero `repack --batch-size`
  midx.c: remove unnecessary loop condition
  midx.c: replace `xcalloc()` with `CALLOC_ARRAY()`
  midx.c: avoid cruft packs with `repack --batch-size=0`
  midx.c: prevent `expire` from removing the cruft pack
  Documentation/git-multi-pack-index.txt: clarify expire behavior
  Documentation/git-multi-pack-index.txt: fix typo
This commit is contained in:
Junio C Hamano 2022-10-27 15:24:11 -07:00
commit a9514e3b95
3 changed files with 107 additions and 6 deletions

View file

@ -70,9 +70,10 @@ verify::
Verify the contents of the MIDX file.
expire::
Delete the pack-files that are tracked by the MIDX file, but
have no objects referenced by the MIDX. Rewrite the MIDX file
afterward to remove all references to these pack-files.
Delete the pack-files that are tracked by the MIDX file, but
have no objects referenced by the MIDX (with the exception of
`.keep` packs and cruft packs). Rewrite the MIDX file afterward
to remove all references to these pack-files.
repack::
Create a new pack-file containing objects in small pack-files

12
midx.c
View file

@ -1839,7 +1839,7 @@ int expire_midx_packs(struct repository *r, const char *object_dir, unsigned fla
if (prepare_midx_pack(r, m, i))
continue;
if (m->packs[i]->pack_keep)
if (m->packs[i]->pack_keep || m->packs[i]->is_cruft)
continue;
pack_name = xstrdup(m->packs[i]->pack_name);
@ -1895,6 +1895,8 @@ static int fill_included_packs_all(struct repository *r,
continue;
if (!pack_kept_objects && m->packs[i]->pack_keep)
continue;
if (m->packs[i]->is_cruft)
continue;
include_pack[i] = 1;
count++;
@ -1910,9 +1912,11 @@ static int fill_included_packs_batch(struct repository *r,
{
uint32_t i, packs_to_repack;
size_t total_size;
struct repack_info *pack_info = xcalloc(m->num_packs, sizeof(struct repack_info));
struct repack_info *pack_info;
int pack_kept_objects = 0;
CALLOC_ARRAY(pack_info, m->num_packs);
repo_config_get_bool(r, "repack.packkeptobjects", &pack_kept_objects);
for (i = 0; i < m->num_packs; i++) {
@ -1924,7 +1928,7 @@ static int fill_included_packs_batch(struct repository *r,
pack_info[i].mtime = m->packs[i]->mtime;
}
for (i = 0; batch_size && i < m->num_objects; i++) {
for (i = 0; i < m->num_objects; i++) {
uint32_t pack_int_id = nth_midxed_pack_int_id(m, i);
pack_info[pack_int_id].referenced_objects++;
}
@ -1942,6 +1946,8 @@ static int fill_included_packs_batch(struct repository *r,
continue;
if (!pack_kept_objects && p->pack_keep)
continue;
if (p->is_cruft)
continue;
if (open_pack_index(p) || !p->num_objects)
continue;

View file

@ -784,6 +784,70 @@ test_expect_success 'repack creates a new pack' '
)
'
test_expect_success 'repack (all) ignores cruft pack' '
git init repo &&
test_when_finished "rm -fr repo" &&
(
cd repo &&
test_commit base &&
test_commit --no-tag unreachable &&
git reset --hard base &&
git reflog expire --all --expire=all &&
git repack --cruft -d &&
git multi-pack-index write &&
find $objdir/pack | sort >before &&
git multi-pack-index repack --batch-size=0 &&
find $objdir/pack | sort >after &&
test_cmp before after
)
'
test_expect_success 'repack (--batch-size) ignores cruft pack' '
git init repo &&
test_when_finished "rm -fr repo" &&
(
cd repo &&
test_commit_bulk 5 &&
test_commit --no-tag unreachable &&
git reset --hard HEAD^ &&
git reflog expire --all --expire=all &&
git repack --cruft -d &&
test_commit four &&
find $objdir/pack -type f -name "*.pack" | sort >before &&
git repack -d &&
find $objdir/pack -type f -name "*.pack" | sort >after &&
pack="$(comm -13 before after)" &&
test_file_size "$pack" >sz &&
# Set --batch-size to twice the size of the pack created
# in the previous step, since this is enough to
# accommodate it and the cruft pack.
#
# This means that the MIDX machinery *could* combine the
# new and cruft packs together.
#
# We ensure that it does not below.
batch="$((($(cat sz) * 2)))" &&
git multi-pack-index write &&
find $objdir/pack | sort >before &&
git multi-pack-index repack --batch-size=$batch &&
find $objdir/pack | sort >after &&
test_cmp before after
)
'
test_expect_success 'expire removes repacked packs' '
(
cd dup &&
@ -847,6 +911,36 @@ test_expect_success 'expire respects .keep files' '
)
'
test_expect_success 'expiring unreferenced cruft pack retains pack' '
git init repo &&
test_when_finished "rm -fr repo" &&
(
cd repo &&
test_commit base &&
test_commit --no-tag unreachable &&
unreachable=$(git rev-parse HEAD) &&
git reset --hard base &&
git reflog expire --all --expire=all &&
git repack --cruft -d &&
mtimes="$(ls $objdir/pack/pack-*.mtimes)" &&
echo "base..$unreachable" >in &&
pack="$(git pack-objects --revs --delta-base-offset \
$objdir/pack/pack <in)" &&
# Preferring the contents of "$pack" will leave the
# cruft pack unreferenced (ie., none of the objects
# contained in the cruft pack will have their MIDX copy
# selected from the cruft pack).
git multi-pack-index write --preferred-pack="pack-$pack.pack" &&
git multi-pack-index expire &&
test_path_is_file "$mtimes"
)
'
test_expect_success 'repack --batch-size=0 repacks everything' '
cp -r dup dup2 &&
(