Merge branch 'tb/pack-path-walk-bitmap-delta-islands' into seen

The pack-objects command now supports using reachability bitmaps and
delta-islands concurrently with the `--path-walk` option, allowing
faster packaging by falling back to path-walk when bitmaps cannot
fully satisfy the request.

* tb/pack-path-walk-bitmap-delta-islands:
  SQUASH???
  pack-objects: support `--delta-islands` with `--path-walk`
  pack-objects: extract `record_tree_depth()` helper
  pack-objects: support reachability bitmaps with `--path-walk`
  t/perf: drop p5311's lookup-table permutation
This commit is contained in:
Junio C Hamano
2026-06-18 13:39:43 -07:00
5 changed files with 134 additions and 31 deletions
+7 -5
View File
@@ -402,11 +402,13 @@ will be automatically changed to version `1`.
of filenames that cause collisions in Git's default name-hash
algorithm.
+
Incompatible with `--delta-islands`. The `--use-bitmap-index` option is
ignored in the presence of `--path-walk`. The `--path-walk` option
supports the `--filter=<spec>` forms `blob:none`, `blob:limit=<n>`,
`tree:0`, `object:type=<type>`, and `sparse:<oid>`. These supported filter
types can be combined with the `combine:<spec>+<spec>` form.
When `--use-bitmap-index` is specified with `--path-walk`, a successful
bitmap traversal is used for object enumeration, with path-walk
remaining as the fallback traversal when the bitmap cannot satisfy the
request. The `--path-walk` option supports the `--filter=<spec>` forms
`blob:none`, `blob:limit=<n>`, `tree:0`, `object:type=<type>`, and
`sparse:<oid>`. These supported filter types can be combined with the
`combine:<spec>+<spec>` form.
DELTA ISLANDS
+50 -18
View File
@@ -2744,6 +2744,22 @@ static inline void oe_set_tree_depth(struct packing_data *pack,
pack->tree_depth[e - pack->objects] = tree_depth;
}
static void record_tree_depth(const struct object_id *oid, const char *name)
{
const char *p;
unsigned depth;
struct object_entry *ent;
/* the empty string is a root tree, which is depth 0 */
depth = *name ? 1 : 0;
for (p = strchr(name, '/'); p; p = strchr(p + 1, '/'))
depth++;
ent = packlist_find(&to_pack, oid);
if (ent && depth > oe_tree_depth(&to_pack, ent))
oe_set_tree_depth(&to_pack, ent, depth);
}
/*
* Return the size of the object without doing any delta
* reconstruction (so non-deltas are true object sizes, but deltas
@@ -4406,20 +4422,8 @@ static void show_object(struct object *obj, const char *name,
add_preferred_base_object(name);
add_object_entry(&obj->oid, obj->type, name, 0);
if (use_delta_islands) {
const char *p;
unsigned depth;
struct object_entry *ent;
/* the empty string is a root tree, which is depth 0 */
depth = *name ? 1 : 0;
for (p = strchr(name, '/'); p; p = strchr(p + 1, '/'))
depth++;
ent = packlist_find(&to_pack, &obj->oid);
if (ent && depth > oe_tree_depth(&to_pack, ent))
oe_set_tree_depth(&to_pack, ent, depth);
}
if (use_delta_islands)
record_tree_depth(&obj->oid, name);
}
static void show_object__ma_allow_any(struct object *obj, const char *name, void *data)
@@ -4763,6 +4767,31 @@ static int add_objects_by_path(const char *path,
continue;
add_object_entry(oid, type, path, exclude);
if (type == OBJ_COMMIT) {
struct commit *commit;
if (!write_bitmap_index && !use_delta_islands)
continue;
commit = lookup_commit(the_repository, oid);
if (!commit)
die(_("could not find commit %s"), oid_to_hex(oid));
if (write_bitmap_index)
index_commit_for_bitmap(commit);
/*
* Skip island propagation for boundary commits.
* The regular traversal's show_commit() is only
* called for interesting commits; matching that
* here keeps path-walk from doing extra work that
* would only be a no-op anyway (boundary commits
* are not in island_marks).
*/
if (use_delta_islands && !exclude)
propagate_island_marks(the_repository, commit);
} else if (type == OBJ_TREE && use_delta_islands) {
record_tree_depth(oid, path);
}
}
oe_end = to_pack.nr_objects;
@@ -4795,6 +4824,13 @@ static int get_object_list_path_walk(struct rev_info *revs)
info.path_fn = add_objects_by_path;
info.path_fn_data = &processed;
/*
* Path-walk needs boundary commits to discover thin-pack bases, but
* bitmap traversal does not understand the boundary state. Set it
* here so any prior bitmap attempt sees the usual non-boundary walk.
*/
revs->boundary = 1;
/*
* Allow the --[no-]sparse option to be interesting here, if only
* for testing purposes. Paths with no interesting objects will not
@@ -5218,8 +5254,6 @@ int cmd_pack_objects(int argc,
const char *option = NULL;
if (!path_walk_filter_compatible(&filter_options))
option = "--filter";
else if (use_delta_islands)
option = "--delta-islands";
if (option) {
warning(_("cannot use %s with %s"),
@@ -5228,9 +5262,7 @@ int cmd_pack_objects(int argc,
}
}
if (path_walk) {
strvec_push(&rp, "--boundary");
strvec_push(&rp, "--objects");
use_bitmap_index = 0;
} else if (thin) {
use_internal_rev_list = 1;
strvec_push(&rp, shallow
+12 -8
View File
@@ -4,16 +4,18 @@ test_description='performance of fetches from bitmapped packs'
. ./perf-lib.sh
test_fetch_bitmaps () {
argv=$1
export argv
test_expect_success 'setup test directory' '
rm -fr * .git
'
test_perf_default_repo
test_expect_success 'create bitmapped server repo' '
test_expect_success "create bitmapped server repo ${argv:+($argv)}" '
git config pack.writebitmaps true &&
git config pack.writeBitmapLookupTable '"$1"' &&
git repack -ad
git repack -ad $argv
'
# simulate a fetch from a repository that last fetched N days ago, for
@@ -21,7 +23,7 @@ test_fetch_bitmaps () {
# and assume the first entry in the chain that is N days older than the current
# HEAD is where the HEAD would have been then.
for days in 1 2 4 8 16 32 64 128; do
title=$(printf '%10s' "($days days)")
title=$(printf '%10s' "($days days${argv:+, $argv})")
test_expect_success "setup revs from $days days ago" '
now=$(git log -1 --format=%ct HEAD) &&
then=$(($now - ($days * 86400))) &&
@@ -32,7 +34,7 @@ test_fetch_bitmaps () {
} >revs
'
test_perf "server $title (lookup=$1)" '
test_perf "server $title" '
git pack-objects --stdout --revs \
--thin --delta-base-offset \
<revs >tmp.pack
@@ -42,13 +44,15 @@ test_fetch_bitmaps () {
test_file_size tmp.pack
'
test_perf "client $title (lookup=$1)" '
test_perf "client $title" '
git index-pack --stdin --fix-thin <tmp.pack
'
done
}
test_fetch_bitmaps true
test_fetch_bitmaps false
for argv in '' --path-walk
do
test_fetch_bitmaps $argv || return 1
done
test_done
+36
View File
@@ -577,6 +577,42 @@ test_bitmap_cases
sane_unset GIT_TEST_PACK_USE_BITMAP_BOUNDARY_TRAVERSAL
test_expect_success 'path-walk repack can write and use bitmap indexes' '
test_when_finished "rm -rf path-walk-bitmap" &&
git init path-walk-bitmap &&
(
cd path-walk-bitmap &&
test_commit first &&
test_commit second &&
test_commit third &&
git repack -a -d -b --path-walk &&
git rev-list --test-bitmap --use-bitmap-index HEAD &&
git rev-parse HEAD >in &&
git rev-list --objects --no-object-names HEAD >expect.raw &&
sort expect.raw >expect &&
for reuse in true false
do
: >trace.txt &&
GIT_TRACE2_EVENT="$(pwd)/trace.txt" \
git -c pack.allowPackReuse=$reuse pack-objects \
--stdout --revs --path-walk --use-bitmap-index \
<in >out.pack &&
test_grep "\"category\":\"bitmap\",\"key\":\"bitmap/hits\"" trace.txt &&
git index-pack out.pack &&
list_packed_objects out.idx >actual.raw &&
sort actual.raw >actual &&
test_cmp expect actual || return 1
done
)
'
test_expect_success 'incremental repack fails when bitmaps are requested' '
test_commit more-1 &&
test_must_fail git repack -d 2>err &&
+29
View File
@@ -53,6 +53,35 @@ test_expect_success 'separate islands disallows delta' '
! is_delta_base $two $one
'
test_expect_success 'path-walk island repack respects islands' '
GIT_TRACE2_EVENT="$(pwd)/trace.path-walk-islands" \
git -c "pack.island=refs/heads/(.*)" repack -adfi \
--path-walk 2>err &&
test_region pack-objects path-walk trace.path-walk-islands &&
test_grep ! "cannot use --delta-islands with --path-walk" err &&
! is_delta_base $one $two &&
! is_delta_base $two $one
'
test_expect_success 'path-walk island bitmap repack respects islands' '
GIT_TRACE2_EVENT="$(pwd)/trace.path-walk-island-bitmap" \
git -c "pack.island=refs/heads/(.*)" repack -a -d -f -i -b \
--path-walk 2>err &&
test_region pack-objects path-walk trace.path-walk-island-bitmap &&
test_path_is_file .git/objects/pack/*.bitmap &&
git rev-list --test-bitmap --use-bitmap-index one &&
test_grep ! "cannot use --delta-islands with --path-walk" err &&
! is_delta_base $one $two &&
! is_delta_base $two $one
'
test_expect_success 'path-walk same island allows delta' '
GIT_TRACE2_EVENT="$(pwd)/trace.path-walk-same-island" \
git -c "pack.island=refs/heads" repack -adfi --path-walk &&
test_region pack-objects path-walk trace.path-walk-same-island &&
is_delta_base $one $two
'
test_expect_success 'same island allows delta' '
git -c "pack.island=refs/heads" repack -adfi &&
is_delta_base $one $two