| #!/bin/sh |
| |
| test_description='pseudo-merge bitmaps' |
| |
| GIT_TEST_MULTI_PACK_INDEX_WRITE_BITMAP=0 |
| |
| . ./test-lib.sh |
| |
| test_pseudo_merges () { |
| test-tool bitmap dump-pseudo-merges |
| } |
| |
| test_pseudo_merge_commits () { |
| test-tool bitmap dump-pseudo-merge-commits "$1" |
| } |
| |
| test_pseudo_merges_satisfied () { |
| test_trace2_data bitmap pseudo_merges_satisfied "$1" |
| } |
| |
| test_pseudo_merges_cascades () { |
| test_trace2_data bitmap pseudo_merges_cascades "$1" |
| } |
| |
| test_pseudo_merges_reused () { |
| test_trace2_data pack-bitmap-write building_bitmaps_pseudo_merge_reused "$1" |
| } |
| |
| tag_everything () { |
| git rev-list --all --no-object-names >in && |
| perl -lne ' |
| print "create refs/tags/" . $. . " " . $1 if /([0-9a-f]+)/ |
| ' <in | git update-ref --stdin |
| } |
| |
| test_expect_success 'setup' ' |
| test_commit_bulk 512 && |
| tag_everything |
| ' |
| |
| test_expect_success 'bitmap traversal without pseudo-merges' ' |
| git repack -adb && |
| |
| git rev-list --count --all --objects >expect && |
| |
| : >trace2.txt && |
| GIT_TRACE2_EVENT=$PWD/trace2.txt \ |
| git rev-list --count --all --objects --use-bitmap-index >actual && |
| |
| test_pseudo_merges_satisfied 0 <trace2.txt && |
| test_pseudo_merges_cascades 0 <trace2.txt && |
| test_pseudo_merges >merges && |
| test_must_be_empty merges && |
| test_cmp expect actual |
| ' |
| |
| test_expect_success 'pseudo-merges accurately represent their objects' ' |
| test_config bitmapPseudoMerge.test.pattern "refs/tags/" && |
| test_config bitmapPseudoMerge.test.maxMerges 8 && |
| test_config bitmapPseudoMerge.test.stableThreshold never && |
| |
| git repack -adb && |
| |
| test_pseudo_merges >merges && |
| test_line_count = 8 merges && |
| |
| for i in $(test_seq 0 $(($(wc -l <merges)-1))) |
| do |
| test-tool bitmap dump-pseudo-merge-commits $i >commits && |
| |
| git rev-list --objects --no-object-names --stdin <commits >expect.raw && |
| test-tool bitmap dump-pseudo-merge-objects $i >actual.raw && |
| |
| sort -u <expect.raw >expect && |
| sort -u <actual.raw >actual && |
| |
| test_cmp expect actual || return 1 |
| done |
| ' |
| |
| test_expect_success 'bitmap traversal with pseudo-merges' ' |
| : >trace2.txt && |
| GIT_TRACE2_EVENT=$PWD/trace2.txt \ |
| git rev-list --count --all --objects --use-bitmap-index >actual && |
| git rev-list --count --all --objects >expect && |
| |
| test_pseudo_merges_satisfied 8 <trace2.txt && |
| test_pseudo_merges_cascades 1 <trace2.txt && |
| test_cmp expect actual |
| ' |
| |
| test_expect_success 'stale bitmap traversal with pseudo-merges' ' |
| test_commit other && |
| |
| : >trace2.txt && |
| GIT_TRACE2_EVENT=$PWD/trace2.txt \ |
| git rev-list --count --all --objects --use-bitmap-index >actual && |
| git rev-list --count --all --objects >expect && |
| |
| test_pseudo_merges_satisfied 8 <trace2.txt && |
| test_pseudo_merges_cascades 1 <trace2.txt && |
| test_cmp expect actual |
| ' |
| |
| test_expect_success 'bitmapPseudoMerge.sampleRate adjusts commit selection rate' ' |
| test_config bitmapPseudoMerge.test.pattern "refs/tags/" && |
| test_config bitmapPseudoMerge.test.maxMerges 1 && |
| test_config bitmapPseudoMerge.test.stableThreshold never && |
| |
| commits_nr=$(git rev-list --all --count) && |
| |
| for rate in 1.0 0.5 0.25 |
| do |
| git -c bitmapPseudoMerge.test.sampleRate=$rate repack -adb && |
| |
| test_pseudo_merges >merges && |
| test_line_count = 1 merges && |
| test_pseudo_merge_commits 0 >commits && |
| |
| test-tool bitmap list-commits >bitmaps && |
| bitmaps_nr="$(wc -l <bitmaps)" && |
| |
| perl -MPOSIX -e "print ceil(\$ARGV[0]*(\$ARGV[1]-\$ARGV[2]))" \ |
| "$rate" "$commits_nr" "$bitmaps_nr" >expect && |
| |
| test $(cat expect) -eq $(wc -l <commits) || return 1 |
| done |
| ' |
| |
| test_expect_success 'bitmapPseudoMerge.threshold excludes newer commits' ' |
| git init pseudo-merge-threshold && |
| ( |
| cd pseudo-merge-threshold && |
| |
| new="1672549200" && # 2023-01-01 |
| old="1641013200" && # 2022-01-01 |
| |
| GIT_COMMITTER_DATE="$new +0000" && |
| export GIT_COMMITTER_DATE && |
| test_commit_bulk --message="new" --notick 128 && |
| |
| GIT_COMMITTER_DATE="$old +0000" && |
| export GIT_COMMITTER_DATE && |
| test_commit_bulk --message="old" --notick 128 && |
| |
| tag_everything && |
| |
| git \ |
| -c bitmapPseudoMerge.test.pattern="refs/tags/" \ |
| -c bitmapPseudoMerge.test.maxMerges=1 \ |
| -c bitmapPseudoMerge.test.threshold=$(($new - 1)) \ |
| -c bitmapPseudoMerge.test.stableThreshold=never \ |
| repack -adb && |
| |
| test_pseudo_merges >merges && |
| test_line_count = 1 merges && |
| |
| test_pseudo_merge_commits 0 >oids && |
| git cat-file --batch <oids >commits && |
| |
| test $(wc -l <oids) = $(grep -c "^committer.*$old +0000$" commits) |
| ) |
| ' |
| |
| test_expect_success 'bitmapPseudoMerge.stableThreshold creates stable groups' ' |
| ( |
| cd pseudo-merge-threshold && |
| |
| new="1672549200" && # 2023-01-01 |
| mid="1654059600" && # 2022-06-01 |
| old="1641013200" && # 2022-01-01 |
| |
| GIT_COMMITTER_DATE="$mid +0000" && |
| export GIT_COMMITTER_DATE && |
| test_commit_bulk --message="mid" --notick 128 && |
| |
| git for-each-ref --format="delete %(refname)" refs/tags >in && |
| git update-ref --stdin <in && |
| |
| tag_everything && |
| |
| git \ |
| -c bitmapPseudoMerge.test.pattern="refs/tags/" \ |
| -c bitmapPseudoMerge.test.maxMerges=1 \ |
| -c bitmapPseudoMerge.test.threshold=$(($new - 1)) \ |
| -c bitmapPseudoMerge.test.stableThreshold=$(($mid - 1)) \ |
| -c bitmapPseudoMerge.test.stableSize=10 \ |
| repack -adb && |
| |
| test_pseudo_merges >merges && |
| merges_nr="$(wc -l <merges)" && |
| |
| for i in $(test_seq $(($merges_nr - 1))) |
| do |
| test_pseudo_merge_commits 0 >oids && |
| git cat-file --batch <oids >commits && |
| |
| expect="$(grep -c "^committer.*$old +0000$" commits)" && |
| actual="$(wc -l <oids)" && |
| |
| test $expect = $actual || return 1 |
| done && |
| |
| test_pseudo_merge_commits $(($merges_nr - 1)) >oids && |
| git cat-file --batch <oids >commits && |
| test $(wc -l <oids) = $(grep -c "^committer.*$mid +0000$" commits) |
| ) |
| ' |
| |
| test_expect_success 'out of order thresholds are rejected' ' |
| test_must_fail git \ |
| -c bitmapPseudoMerge.test.pattern="refs/*" \ |
| -c bitmapPseudoMerge.test.threshold=1.month.ago \ |
| -c bitmapPseudoMerge.test.stableThreshold=1.week.ago \ |
| repack -adb 2>err && |
| |
| cat >expect <<-EOF && |
| fatal: pseudo-merge group ${SQ}test${SQ} has unstable threshold before stable one |
| EOF |
| |
| test_cmp expect err |
| ' |
| |
| test_expect_success 'pseudo-merge pattern with capture groups' ' |
| git init pseudo-merge-captures && |
| ( |
| cd pseudo-merge-captures && |
| |
| test_commit_bulk 128 && |
| tag_everything && |
| |
| for r in $(test_seq 8) |
| do |
| test_commit_bulk 16 && |
| |
| git rev-list HEAD~16.. >in && |
| |
| perl -lne "print \"create refs/remotes/$r/tags/\$. \$_\"" <in | |
| git update-ref --stdin || return 1 |
| done && |
| |
| git \ |
| -c bitmapPseudoMerge.tags.pattern="refs/remotes/([0-9]+)/tags/" \ |
| -c bitmapPseudoMerge.tags.maxMerges=1 \ |
| repack -adb && |
| |
| git for-each-ref --format="%(objectname) %(refname)" >refs && |
| |
| test_pseudo_merges >merges && |
| for m in $(test_seq 0 $(($(wc -l <merges) - 1))) |
| do |
| test_pseudo_merge_commits $m >oids && |
| grep -f oids refs | |
| perl -lne "print \$1 if /refs\/remotes\/([0-9]+)/" | |
| sort -u || return 1 |
| done >remotes && |
| |
| test $(wc -l <remotes) -eq $(sort -u <remotes | wc -l) |
| ) |
| ' |
| |
| test_expect_success 'pseudo-merge overlap setup' ' |
| git init pseudo-merge-overlap && |
| ( |
| cd pseudo-merge-overlap && |
| |
| test_commit_bulk 256 && |
| tag_everything && |
| |
| git \ |
| -c bitmapPseudoMerge.all.pattern="refs/" \ |
| -c bitmapPseudoMerge.all.maxMerges=1 \ |
| -c bitmapPseudoMerge.all.stableThreshold=never \ |
| -c bitmapPseudoMerge.tags.pattern="refs/tags/" \ |
| -c bitmapPseudoMerge.tags.maxMerges=1 \ |
| -c bitmapPseudoMerge.tags.stableThreshold=never \ |
| repack -adb |
| ) |
| ' |
| |
| test_expect_success 'pseudo-merge overlap generates overlapping groups' ' |
| ( |
| cd pseudo-merge-overlap && |
| |
| test_pseudo_merges >merges && |
| test_line_count = 2 merges && |
| |
| test_pseudo_merge_commits 0 >commits-0.raw && |
| test_pseudo_merge_commits 1 >commits-1.raw && |
| |
| sort commits-0.raw >commits-0 && |
| sort commits-1.raw >commits-1 && |
| |
| comm -12 commits-0 commits-1 >overlap && |
| |
| test_line_count -gt 0 overlap |
| ) |
| ' |
| |
| test_expect_success 'pseudo-merge overlap traversal' ' |
| ( |
| cd pseudo-merge-overlap && |
| |
| : >trace2.txt && |
| GIT_TRACE2_EVENT=$PWD/trace2.txt \ |
| git rev-list --count --all --objects --use-bitmap-index >actual && |
| git rev-list --count --all --objects >expect && |
| |
| test_pseudo_merges_satisfied 2 <trace2.txt && |
| test_pseudo_merges_cascades 1 <trace2.txt && |
| test_cmp expect actual |
| ) |
| ' |
| |
| test_expect_success 'pseudo-merge overlap stale traversal' ' |
| ( |
| cd pseudo-merge-overlap && |
| |
| test_commit other && |
| |
| : >trace2.txt && |
| GIT_TRACE2_EVENT=$PWD/trace2.txt \ |
| git rev-list --count --all --objects --use-bitmap-index >actual && |
| git rev-list --count --all --objects >expect && |
| |
| test_pseudo_merges_satisfied 2 <trace2.txt && |
| test_pseudo_merges_cascades 1 <trace2.txt && |
| test_cmp expect actual |
| ) |
| ' |
| |
| test_expect_success 'pseudo-merge reuse' ' |
| git init pseudo-merge-reuse && |
| ( |
| cd pseudo-merge-reuse && |
| |
| stable="1641013200" && # 2022-01-01 |
| unstable="1672549200" && # 2023-01-01 |
| |
| GIT_COMMITTER_DATE="$stable +0000" && |
| export GIT_COMMITTER_DATE && |
| test_commit_bulk --notick 128 && |
| GIT_COMMITTER_DATE="$unstable +0000" && |
| export GIT_COMMITTER_DATE && |
| test_commit_bulk --notick 128 && |
| |
| tag_everything && |
| |
| git \ |
| -c bitmapPseudoMerge.test.pattern="refs/tags/" \ |
| -c bitmapPseudoMerge.test.maxMerges=1 \ |
| -c bitmapPseudoMerge.test.threshold=now \ |
| -c bitmapPseudoMerge.test.stableThreshold=$(($unstable - 1)) \ |
| -c bitmapPseudoMerge.test.stableSize=512 \ |
| repack -adb && |
| |
| test_pseudo_merges >merges && |
| test_line_count = 2 merges && |
| |
| test_pseudo_merge_commits 0 >stable-oids.before && |
| test_pseudo_merge_commits 1 >unstable-oids.before && |
| |
| : >trace2.txt && |
| GIT_TRACE2_EVENT=$PWD/trace2.txt git \ |
| -c bitmapPseudoMerge.test.pattern="refs/tags/" \ |
| -c bitmapPseudoMerge.test.maxMerges=2 \ |
| -c bitmapPseudoMerge.test.threshold=now \ |
| -c bitmapPseudoMerge.test.stableThreshold=$(($unstable - 1)) \ |
| -c bitmapPseudoMerge.test.stableSize=512 \ |
| repack -adb && |
| |
| test_pseudo_merges_reused 1 <trace2.txt && |
| |
| test_pseudo_merges >merges && |
| test_line_count = 3 merges && |
| |
| test_pseudo_merge_commits 0 >stable-oids.after && |
| for i in 1 2 |
| do |
| test_pseudo_merge_commits $i || return 1 |
| done >unstable-oids.after && |
| |
| sort -u <stable-oids.before >expect && |
| sort -u <stable-oids.after >actual && |
| test_cmp expect actual && |
| |
| sort -u <unstable-oids.before >expect && |
| sort -u <unstable-oids.after >actual && |
| test_cmp expect actual |
| ) |
| ' |
| |
| test_expect_success 'empty pseudo-merge group' ' |
| git init pseudo-merge-empty-group && |
| ( |
| cd pseudo-merge-empty-group && |
| |
| # Ensure that a pseudo-merge group with no unstable |
| # commits does not generate an empty pseudo-merge |
| # bitmap. |
| git config bitmapPseudoMerge.empty.pattern refs/ && |
| |
| test_commit base && |
| git repack -adb && |
| |
| test-tool bitmap dump-pseudo-merges >merges && |
| test_line_count = 1 merges && |
| |
| test 0 -eq "$(grep -c commits=0 <merges)" |
| ) |
| ' |
| |
| test_expect_success 'pseudo-merge closure' ' |
| git init pseudo-merge-closure && |
| ( |
| cd pseudo-merge-closure && |
| |
| test_commit A && |
| git repack -d && |
| |
| test_commit B && |
| |
| # Note that the contents of A is packed, but B is not. A |
| # (and the objects reachable from it) are thus visible |
| # to the MIDX, but the same is not true for B and its |
| # objects. |
| # |
| # Ensure that we do not attempt to create a pseudo-merge |
| # for B, depsite it matching the below pseudo-merge |
| # group pattern, as doing so would result in a failure |
| # to write a non-closed bitmap. |
| git config bitmapPseudoMerge.test.pattern refs/ && |
| git config bitmapPseudoMerge.test.threshold now && |
| |
| git multi-pack-index write --bitmap && |
| |
| test-tool bitmap dump-pseudo-merges >pseudo-merges && |
| test_line_count = 1 pseudo-merges && |
| |
| git rev-parse A >expect && |
| |
| test-tool bitmap list-commits >actual && |
| test_cmp expect actual && |
| test-tool bitmap dump-pseudo-merge-commits 0 >actual && |
| test_cmp expect actual |
| ) |
| ' |
| |
| test_done |