t5326: test multi-pack bitmap behavior

This patch introduces a new test, t5326, which tests the basic functionality of multi-pack bitmaps. Some trivial behavior is tested, such as: - Whether bitmaps can be generated with more than one pack. - Whether clones can be served with all objects in the bitmap. - Whether follow-up fetches can be served with some objects outside of the server's bitmap These use lib-bitmap's tests (which in turn were pulled from t5310), and we cover cases where the MIDX represents both a single pack and multiple packs. In addition, some non-trivial and MIDX-specific behavior is tested, too, including: - Whether multi-pack bitmaps behave correctly with respect to the pack-reuse machinery when the base for some object is selected from a different pack than the delta. - Whether multi-pack bitmaps correctly respect the pack.preferBitmapTips configuration. Signed-off-by: Taylor Blau <me@ttaylorr.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Taylor Blau committed Aug 31, 2021 at 16:52 UTC c51f5a6437c62c5b231a4632896becd545c7e620
1 file changed +286
t/t5326-multi-pack-bitmaps.sh new
+286
@@ -0,0 +1,286 @@
1 +#!/bin/sh
2 +
3 +test_description='exercise basic multi-pack bitmap functionality'
4 +. ./test-lib.sh
5 +. "${TEST_DIRECTORY}/lib-bitmap.sh"
6 +
7 +# We'll be writing our own midx and bitmaps, so avoid getting confused by the
8 +# automatic ones.
9 +GIT_TEST_MULTI_PACK_INDEX=0
10 +GIT_TEST_MULTI_PACK_INDEX_WRITE_BITMAP=0
11 +
12 +objdir=.git/objects
13 +midx=$objdir/pack/multi-pack-index
14 +
15 +# midx_pack_source <obj>
16 +midx_pack_source () {
17 + test-tool read-midx --show-objects .git/objects | grep "^$1 " | cut -f2
18 +}
19 +
20 +setup_bitmap_history
21 +
22 +test_expect_success 'enable core.multiPackIndex' '
23 + git config core.multiPackIndex true
24 +'
25 +
26 +test_expect_success 'create single-pack midx with bitmaps' '
27 + git repack -ad &&
28 + git multi-pack-index write --bitmap &&
29 + test_path_is_file $midx &&
30 + test_path_is_file $midx-$(midx_checksum $objdir).bitmap &&
31 + test_path_is_file $midx-$(midx_checksum $objdir).rev
32 +'
33 +
34 +basic_bitmap_tests
35 +
36 +test_expect_success 'create new additional packs' '
37 + for i in $(test_seq 1 16)
38 + do
39 + test_commit "$i" &&
40 + git repack -d || return 1
41 + done &&
42 +
43 + git checkout -b other2 HEAD~8 &&
44 + for i in $(test_seq 1 8)
45 + do
46 + test_commit "side-$i" &&
47 + git repack -d || return 1
48 + done &&
49 + git checkout second
50 +'
51 +
52 +test_expect_success 'create multi-pack midx with bitmaps' '
53 + git multi-pack-index write --bitmap &&
54 +
55 + ls $objdir/pack/pack-*.pack >packs &&
56 + test_line_count = 25 packs &&
57 +
58 + test_path_is_file $midx &&
59 + test_path_is_file $midx-$(midx_checksum $objdir).bitmap &&
60 + test_path_is_file $midx-$(midx_checksum $objdir).rev
61 +'
62 +
63 +basic_bitmap_tests
64 +
65 +test_expect_success '--no-bitmap is respected when bitmaps exist' '
66 + git multi-pack-index write --bitmap &&
67 +
68 + test_commit respect--no-bitmap &&
69 + git repack -d &&
70 +
71 + test_path_is_file $midx &&
72 + test_path_is_file $midx-$(midx_checksum $objdir).bitmap &&
73 + test_path_is_file $midx-$(midx_checksum $objdir).rev &&
74 +
75 + git multi-pack-index write --no-bitmap &&
76 +
77 + test_path_is_file $midx &&
78 + test_path_is_missing $midx-$(midx_checksum $objdir).bitmap &&
79 + test_path_is_missing $midx-$(midx_checksum $objdir).rev
80 +'
81 +
82 +test_expect_success 'setup midx with base from later pack' '
83 + # Write a and b so that "a" is a delta on top of base "b", since Git
84 + # prefers to delete contents out of a base rather than add to a shorter
85 + # object.
86 + test_seq 1 128 >a &&
87 + test_seq 1 130 >b &&
88 +
89 + git add a b &&
90 + git commit -m "initial commit" &&
91 +
92 + a=$(git rev-parse HEAD:a) &&
93 + b=$(git rev-parse HEAD:b) &&
94 +
95 + # In the first pack, "a" is stored as a delta to "b".
96 + p1=$(git pack-objects .git/objects/pack/pack <<-EOF
97 + $a
98 + $b
99 + EOF
100 + ) &&
101 +
102 + # In the second pack, "a" is missing, and "b" is not a delta nor base to
103 + # any other object.
104 + p2=$(git pack-objects .git/objects/pack/pack <<-EOF
105 + $b
106 + $(git rev-parse HEAD)
107 + $(git rev-parse HEAD^{tree})
108 + EOF
109 + ) &&
110 +
111 + git prune-packed &&
112 + # Use the second pack as the preferred source, so that "b" occurs
113 + # earlier in the MIDX object order, rendering "a" unusable for pack
114 + # reuse.
115 + git multi-pack-index write --bitmap --preferred-pack=pack-$p2.idx &&
116 +
117 + have_delta $a $b &&
118 + test $(midx_pack_source $a) != $(midx_pack_source $b)
119 +'
120 +
121 +rev_list_tests 'full bitmap with backwards delta'
122 +
123 +test_expect_success 'clone with bitmaps enabled' '
124 + git clone --no-local --bare . clone-reverse-delta.git &&
125 + test_when_finished "rm -fr clone-reverse-delta.git" &&
126 +
127 + git rev-parse HEAD >expect &&
128 + git --git-dir=clone-reverse-delta.git rev-parse HEAD >actual &&
129 + test_cmp expect actual
130 +'
131 +
132 +bitmap_reuse_tests() {
133 + from=$1
134 + to=$2
135 +
136 + test_expect_success "setup pack reuse tests ($from -> $to)" '
137 + rm -fr repo &&
138 + git init repo &&
139 + (
140 + cd repo &&
141 + test_commit_bulk 16 &&
142 + git tag old-tip &&
143 +
144 + git config core.multiPackIndex true &&
145 + if test "MIDX" = "$from"
146 + then
147 + git repack -Ad &&
148 + git multi-pack-index write --bitmap
149 + else
150 + git repack -Adb
151 + fi
152 + )
153 + '
154 +
155 + test_expect_success "build bitmap from existing ($from -> $to)" '
156 + (
157 + cd repo &&
158 + test_commit_bulk --id=further 16 &&
159 + git tag new-tip &&
160 +
161 + if test "MIDX" = "$to"
162 + then
163 + git repack -d &&
164 + git multi-pack-index write --bitmap
165 + else
166 + git repack -Adb
167 + fi
168 + )
169 + '
170 +
171 + test_expect_success "verify resulting bitmaps ($from -> $to)" '
172 + (
173 + cd repo &&
174 + git for-each-ref &&
175 + git rev-list --test-bitmap refs/tags/old-tip &&
176 + git rev-list --test-bitmap refs/tags/new-tip
177 + )
178 + '
179 +}
180 +
181 +bitmap_reuse_tests 'pack' 'MIDX'
182 +bitmap_reuse_tests 'MIDX' 'pack'
183 +bitmap_reuse_tests 'MIDX' 'MIDX'
184 +
185 +test_expect_success 'missing object closure fails gracefully' '
186 + rm -fr repo &&
187 + git init repo &&
188 + test_when_finished "rm -fr repo" &&
189 + (
190 + cd repo &&
191 +
192 + test_commit loose &&
193 + test_commit packed &&
194 +
195 + # Do not pass "--revs"; we want a pack without the "loose"
196 + # commit.
197 + git pack-objects $objdir/pack/pack <<-EOF &&
198 + $(git rev-parse packed)
199 + EOF
200 +
201 + test_must_fail git multi-pack-index write --bitmap 2>err &&
202 + grep "doesn.t have full closure" err &&
203 + test_path_is_missing $midx
204 + )
205 +'
206 +
207 +test_expect_success 'setup partial bitmaps' '
208 + test_commit packed &&
209 + git repack &&
210 + test_commit loose &&
211 + git multi-pack-index write --bitmap 2>err &&
212 + test_path_is_file $midx &&
213 + test_path_is_file $midx-$(midx_checksum $objdir).bitmap &&
214 + test_path_is_file $midx-$(midx_checksum $objdir).rev
215 +'
216 +
217 +basic_bitmap_tests HEAD~
218 +
219 +test_expect_success 'removing a MIDX clears stale bitmaps' '
220 + rm -fr repo &&
221 + git init repo &&
222 + test_when_finished "rm -fr repo" &&
223 + (
224 + cd repo &&
225 + test_commit base &&
226 + git repack &&
227 + git multi-pack-index write --bitmap &&
228 +
229 + # Write a MIDX and bitmap; remove the MIDX but leave the bitmap.
230 + stale_bitmap=$midx-$(midx_checksum $objdir).bitmap &&
231 + stale_rev=$midx-$(midx_checksum $objdir).rev &&
232 + rm $midx &&
233 +
234 + # Then write a new MIDX.
235 + test_commit new &&
236 + git repack &&
237 + git multi-pack-index write --bitmap &&
238 +
239 + test_path_is_file $midx &&
240 + test_path_is_file $midx-$(midx_checksum $objdir).bitmap &&
241 + test_path_is_file $midx-$(midx_checksum $objdir).rev &&
242 + test_path_is_missing $stale_bitmap &&
243 + test_path_is_missing $stale_rev
244 + )
245 +'
246 +
247 +test_expect_success 'pack.preferBitmapTips' '
248 + git init repo &&
249 + test_when_finished "rm -fr repo" &&
250 + (
251 + cd repo &&
252 +
253 + test_commit_bulk --message="%s" 103 &&
254 +
255 + git log --format="%H" >commits.raw &&
256 + sort <commits.raw >commits &&
257 +
258 + git log --format="create refs/tags/%s %H" HEAD >refs &&
259 + git update-ref --stdin <refs &&
260 +
261 + git multi-pack-index write --bitmap &&
262 + test_path_is_file $midx &&
263 + test_path_is_file $midx-$(midx_checksum $objdir).bitmap &&
264 + test_path_is_file $midx-$(midx_checksum $objdir).rev &&
265 +
266 + test-tool bitmap list-commits | sort >bitmaps &&
267 + comm -13 bitmaps commits >before &&
268 + test_line_count = 1 before &&
269 +
270 + perl -ne "printf(\"create refs/tags/include/%d \", $.); print" \
271 + <before | git update-ref --stdin &&
272 +
273 + rm -fr $midx-$(midx_checksum $objdir).bitmap &&
274 + rm -fr $midx-$(midx_checksum $objdir).rev &&
275 + rm -fr $midx &&
276 +
277 + git -c pack.preferBitmapTips=refs/tags/include \
278 + multi-pack-index write --bitmap &&
279 + test-tool bitmap list-commits | sort >bitmaps &&
280 + comm -13 bitmaps commits >after &&
281 +
282 + ! test_cmp before after
283 + )
284 +'
285 +
286 +test_done