Raw
1 #!/bin/sh
2
3 test_description='git log for a path with Bloom filters'
4 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
5 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
6
7 . ./test-lib.sh
8 . "$TEST_DIRECTORY"/lib-chunk.sh
9
10 GIT_TEST_COMMIT_GRAPH=0
11 GIT_TEST_COMMIT_GRAPH_CHANGED_PATHS=0
12
13 test_expect_success 'setup test - repo, commits, commit graph, log outputs' '
14 git init &&
15 mkdir A A/B A/B/C &&
16 test_commit c1 A/file1 &&
17 test_commit c2 A/B/file2 &&
18 test_commit c3 A/B/C/file3 &&
19 test_commit c4 A/file1 &&
20 test_commit c5 A/B/file2 &&
21 test_commit c6 A/B/C/file3 &&
22 test_commit c7 A/file1 &&
23 test_commit c8 A/B/file2 &&
24 test_commit c9 A/B/C/file3 &&
25 test_commit c10 file_to_be_deleted &&
26 git checkout -b side HEAD~4 &&
27 test_commit side-1 file4 &&
28 git checkout main &&
29 git merge side &&
30 test_commit c11 file5 &&
31 mv file5 file5_renamed &&
32 git add file5_renamed &&
33 git commit -m "rename" &&
34 rm file_to_be_deleted &&
35 git add . &&
36 git commit -m "file removed" &&
37 git commit --allow-empty -m "empty" &&
38 git commit-graph write --reachable --changed-paths &&
39
40 test_oid_cache <<-EOF
41 oid_version sha1:1
42 oid_version sha256:2
43 EOF
44 '
45
46 graph_read_expect () {
47 NUM_CHUNKS=6
48 cat >expect <<- EOF
49 header: 43475048 1 $(test_oid oid_version) $NUM_CHUNKS 0
50 num_commits: $1
51 chunks: oid_fanout oid_lookup commit_metadata generation_data bloom_indexes bloom_data
52 options: bloom(1,10,7) read_generation_data
53 EOF
54 test-tool read-graph >actual &&
55 test_cmp expect actual
56 }
57
58 test_expect_success 'commit-graph write wrote out the bloom chunks' '
59 graph_read_expect 16
60 '
61
62 # Turn off any inherited trace2 settings for this test.
63 sane_unset GIT_TRACE2 GIT_TRACE2_PERF GIT_TRACE2_EVENT
64 sane_unset GIT_TRACE2_PERF_BRIEF
65 sane_unset GIT_TRACE2_CONFIG_PARAMS
66
67 setup () {
68 rm -f "$TRASH_DIRECTORY/trace.perf" &&
69 eval git -c core.commitGraph=false log --pretty="format:%s" "$1" >log_wo_bloom &&
70 eval "GIT_TRACE2_PERF=\"$TRASH_DIRECTORY/trace.perf\"" \
71 git -c core.commitGraph=true log --pretty="format:%s" "$1" >log_w_bloom
72 }
73
74 test_bloom_filters_used () {
75 log_args=$1
76 bloom_trace_prefix="statistics:{\"filter_not_present\":${2:-0},\"maybe\""
77 setup "$log_args" &&
78 grep -q "$bloom_trace_prefix" "$TRASH_DIRECTORY/trace.perf" &&
79 test_cmp log_wo_bloom log_w_bloom &&
80 test_path_is_file "$TRASH_DIRECTORY/trace.perf"
81 }
82
83 test_bloom_filters_not_used () {
84 log_args=$1
85 setup "$log_args" &&
86
87 if grep -q "statistics:{\"filter_not_present\":" "$TRASH_DIRECTORY/trace.perf"
88 then
89 # if the Bloom filter system is initialized, ensure that no
90 # filters were used
91 data="statistics:{"
92 # unusable filters (e.g., those computed with a
93 # different value of commitGraph.changedPathsVersion)
94 # are counted in the filter_not_present bucket, so any
95 # value is OK there.
96 data="$data\"filter_not_present\":[0-9][0-9]*,"
97 data="$data\"maybe\":0,"
98 data="$data\"definitely_not\":0,"
99 data="$data\"false_positive\":0}"
100
101 grep -q "$data" "$TRASH_DIRECTORY/trace.perf"
102 fi &&
103 test_cmp log_wo_bloom log_w_bloom
104 }
105
106 for path in A A/B A/B/C A/file1 A/B/file2 A/B/C/file3 file4 file5 file5_renamed file_to_be_deleted
107 do
108 for option in "" \
109 "--all" \
110 "--full-history" \
111 "--full-history --simplify-merges" \
112 "--simplify-merges" \
113 "--simplify-by-decoration" \
114 "--follow" \
115 "--first-parent" \
116 "--topo-order" \
117 "--date-order" \
118 "--author-date-order" \
119 "--ancestry-path side..main"
120 do
121 test_expect_success "git log option: $option for path: $path" '
122 test_bloom_filters_used "$option -- $path" &&
123 test_config commitgraph.readChangedPaths false &&
124 test_bloom_filters_not_used "$option -- $path"
125 '
126 done
127 done
128
129 test_expect_success 'git log -- folder works with and without the trailing slash' '
130 test_bloom_filters_used "-- A" &&
131 test_bloom_filters_used "-- A/"
132 '
133
134 test_expect_success 'git log for path that does not exist. ' '
135 test_bloom_filters_used "-- path_does_not_exist"
136 '
137
138 test_expect_success 'git log with --walk-reflogs does not use Bloom filters' '
139 test_bloom_filters_not_used "--walk-reflogs -- A"
140 '
141
142 test_expect_success 'git log -- "." pathspec at root does not use Bloom filters' '
143 test_bloom_filters_not_used "-- ."
144 '
145
146 test_expect_success 'git log with wildcard that resolves to a single path uses Bloom filters' '
147 test_bloom_filters_used "-- *4" &&
148 test_bloom_filters_used "-- *renamed"
149 '
150
151 test_expect_success 'git log with multiple literal paths uses Bloom filter' '
152 test_bloom_filters_used "-- file4 A/file1" &&
153 test_bloom_filters_used "-- *" &&
154 test_bloom_filters_used "-- file*"
155 '
156
157 test_expect_success 'git log with paths all contain non-wildcard part uses Bloom filter' '
158 test_bloom_filters_used "-- A/\* file4" &&
159 test_bloom_filters_used "-- A/file\*" &&
160 test_bloom_filters_used "-- * A/\*"
161 '
162
163 test_expect_success 'git log with path only contains wildcard part does not use Bloom filter' '
164 test_bloom_filters_not_used "-- file\*" &&
165 test_bloom_filters_not_used "-- file\* A/\*" &&
166 test_bloom_filters_not_used "-- file\* *" &&
167 test_bloom_filters_not_used "-- \*"
168 '
169
170 test_expect_success 'git log with path contains various magic signatures' '
171 cd A &&
172 test_bloom_filters_used "-- \:\(top\)B" &&
173 cd .. &&
174
175 test_bloom_filters_used "-- \:\(glob\)A/\*\*/C" &&
176 test_bloom_filters_not_used "-- \:\(icase\)FILE4" &&
177 test_bloom_filters_not_used "-- \:\(exclude\)A/B/C" &&
178
179 test_when_finished "rm -f .gitattributes" &&
180 cat >.gitattributes <<-EOF &&
181 A/file1 text
182 A/B/file2 -text
183 EOF
184 test_bloom_filters_used "-- \:\(attr\:text\)A"
185 '
186
187 test_expect_success 'setup - add commit-graph to the chain without Bloom filters' '
188 test_commit c14 A/anotherFile2 &&
189 test_commit c15 A/B/anotherFile2 &&
190 test_commit c16 A/B/C/anotherFile2 &&
191 git commit-graph write --reachable --split --no-changed-paths &&
192 test_line_count = 2 .git/objects/info/commit-graphs/commit-graph-chain
193 '
194
195 test_expect_success 'use Bloom filters even if the latest graph does not have Bloom filters' '
196 # Ensure that the number of empty filters is equal to the number of
197 # filters in the latest graph layer to prove that they are loaded (and
198 # ignored).
199 test_bloom_filters_used "-- A/B" 3
200 '
201
202 test_expect_success 'setup - add commit-graph to the chain with Bloom filters' '
203 test_commit c17 A/anotherFile3 &&
204 git commit-graph write --reachable --changed-paths --split &&
205 test_line_count = 3 .git/objects/info/commit-graphs/commit-graph-chain
206 '
207
208 test_bloom_filters_used_when_some_filters_are_missing () {
209 log_args=$1
210 bloom_trace_prefix="statistics:{\"filter_not_present\":3,\"maybe\":6,\"definitely_not\":10"
211 setup "$log_args" &&
212 grep -q "$bloom_trace_prefix" "$TRASH_DIRECTORY/trace.perf" &&
213 test_cmp log_wo_bloom log_w_bloom
214 }
215
216 test_expect_success 'Use Bloom filters if they exist in the latest but not all commit graphs in the chain.' '
217 test_bloom_filters_used_when_some_filters_are_missing "-- A/B"
218 '
219
220 test_expect_success 'persist filter settings' '
221 test_when_finished rm -rf .git/objects/info/commit-graph* &&
222 rm -rf .git/objects/info/commit-graph* &&
223 GIT_TRACE2_EVENT="$(pwd)/trace2.txt" \
224 GIT_TEST_BLOOM_SETTINGS_NUM_HASHES=9 \
225 GIT_TEST_BLOOM_SETTINGS_BITS_PER_ENTRY=15 \
226 git commit-graph write --reachable --changed-paths &&
227 grep "{\"hash_version\":1,\"num_hashes\":9,\"bits_per_entry\":15,\"max_changed_paths\":512" trace2.txt &&
228 GIT_TRACE2_EVENT="$(pwd)/trace2-auto.txt" \
229 git commit-graph write --reachable --changed-paths &&
230 grep "{\"hash_version\":1,\"num_hashes\":9,\"bits_per_entry\":15,\"max_changed_paths\":512" trace2-auto.txt
231 '
232
233 test_max_changed_paths () {
234 grep "\"max_changed_paths\":$1" $2
235 }
236
237 test_filter_not_computed () {
238 grep "\"key\":\"filter-not-computed\",\"value\":\"$1\"" $2
239 }
240
241 test_filter_computed () {
242 grep "\"key\":\"filter-computed\",\"value\":\"$1\"" $2
243 }
244
245 test_filter_trunc_empty () {
246 grep "\"key\":\"filter-trunc-empty\",\"value\":\"$1\"" $2
247 }
248
249 test_filter_trunc_large () {
250 grep "\"key\":\"filter-trunc-large\",\"value\":\"$1\"" $2
251 }
252
253 test_filter_upgraded () {
254 grep "\"key\":\"filter-upgraded\",\"value\":\"$1\"" $2
255 }
256
257 test_expect_success 'correctly report changes over limit' '
258 git init limits &&
259 (
260 cd limits &&
261 mkdir d &&
262 mkdir d/e &&
263
264 for i in $(test_seq 1 2)
265 do
266 printf $i >d/file$i.txt &&
267 printf $i >d/e/file$i.txt || return 1
268 done &&
269
270 mkdir mode &&
271 printf bash >mode/script.sh &&
272
273 mkdir foo &&
274 touch foo/bar &&
275 touch foo.txt &&
276
277 git add d foo foo.txt mode &&
278 git commit -m "files" &&
279
280 # Commit has 7 file and 4 directory adds
281 GIT_TEST_BLOOM_SETTINGS_MAX_CHANGED_PATHS=10 \
282 GIT_TRACE2_EVENT="$(pwd)/trace" \
283 git commit-graph write --reachable --changed-paths &&
284 test_max_changed_paths 10 trace &&
285 test_filter_computed 1 trace &&
286 test_filter_trunc_large 1 trace &&
287
288 for path in $(git ls-tree -r --name-only HEAD)
289 do
290 git -c commitGraph.readChangedPaths=false log \
291 -- $path >expect &&
292 git log -- $path >actual &&
293 test_cmp expect actual || return 1
294 done &&
295
296 # Make a variety of path changes
297 printf new1 >d/e/file1.txt &&
298 printf new2 >d/file2.txt &&
299 rm d/e/file2.txt &&
300 rm -r foo &&
301 printf text >foo &&
302 mkdir f &&
303 printf new1 >f/file1.txt &&
304
305 # including a mode-only change (counts as modified)
306 git update-index --chmod=+x mode/script.sh &&
307
308 git add foo d f &&
309 git commit -m "complicated" &&
310
311 # start from scratch and rebuild
312 rm -f .git/objects/info/commit-graph &&
313 GIT_TEST_BLOOM_SETTINGS_MAX_CHANGED_PATHS=10 \
314 GIT_TRACE2_EVENT="$(pwd)/trace-edit" \
315 git commit-graph write --reachable --changed-paths &&
316 test_max_changed_paths 10 trace-edit &&
317 test_filter_computed 2 trace-edit &&
318 test_filter_trunc_large 2 trace-edit &&
319
320 for path in $(git ls-tree -r --name-only HEAD)
321 do
322 git -c commitGraph.readChangedPaths=false log \
323 -- $path >expect &&
324 git log -- $path >actual &&
325 test_cmp expect actual || return 1
326 done &&
327
328 # start from scratch and rebuild
329 rm -f .git/objects/info/commit-graph &&
330 GIT_TEST_BLOOM_SETTINGS_MAX_CHANGED_PATHS=11 \
331 GIT_TRACE2_EVENT="$(pwd)/trace-update" \
332 git commit-graph write --reachable --changed-paths &&
333 test_max_changed_paths 11 trace-update &&
334 test_filter_computed 2 trace-update &&
335 test_filter_trunc_large 0 trace-update &&
336
337 for path in $(git ls-tree -r --name-only HEAD)
338 do
339 git -c commitGraph.readChangedPaths=false log \
340 -- $path >expect &&
341 git log -- $path >actual &&
342 test_cmp expect actual || return 1
343 done
344 )
345 '
346
347 test_expect_success 'correctly report commits with no changed paths' '
348 git init empty &&
349 test_when_finished "rm -fr empty" &&
350 (
351 cd empty &&
352
353 git commit --allow-empty -m "initial commit" &&
354
355 GIT_TRACE2_EVENT="$(pwd)/trace.event" \
356 git commit-graph write --reachable --changed-paths &&
357 test_filter_computed 1 trace.event &&
358 test_filter_not_computed 0 trace.event &&
359 test_filter_trunc_empty 1 trace.event &&
360 test_filter_trunc_large 0 trace.event
361 )
362 '
363
364 test_expect_success 'Bloom generation is limited by --max-new-filters' '
365 (
366 cd limits &&
367 test_commit c2 filter &&
368 test_commit c3 filter &&
369 test_commit c4 no-filter &&
370
371 rm -f trace.event &&
372 GIT_TRACE2_EVENT="$(pwd)/trace.event" \
373 git commit-graph write --reachable --split=replace \
374 --changed-paths --max-new-filters=2 &&
375
376 test_filter_computed 2 trace.event &&
377 test_filter_not_computed 3 trace.event &&
378 test_filter_trunc_empty 0 trace.event &&
379 test_filter_trunc_large 0 trace.event
380 )
381 '
382
383 test_expect_success 'Bloom generation backfills previously-skipped filters' '
384 # Check specifying commitGraph.maxNewFilters over "git config" works.
385 test_config -C limits commitGraph.maxNewFilters 1 &&
386 (
387 cd limits &&
388
389 rm -f trace.event &&
390 GIT_TRACE2_EVENT="$(pwd)/trace.event" \
391 git commit-graph write --reachable --changed-paths \
392 --split=replace &&
393 test_filter_computed 1 trace.event &&
394 test_filter_not_computed 4 trace.event &&
395 test_filter_trunc_empty 0 trace.event &&
396 test_filter_trunc_large 0 trace.event
397 )
398 '
399
400 test_expect_success '--max-new-filters overrides configuration' '
401 git init override &&
402 test_when_finished "rm -fr override" &&
403 test_config -C override commitGraph.maxNewFilters 2 &&
404 (
405 cd override &&
406 test_commit one &&
407 test_commit two &&
408
409 rm -f trace.event &&
410 GIT_TRACE2_EVENT="$(pwd)/trace.event" \
411 git commit-graph write --reachable --changed-paths \
412 --max-new-filters=1 &&
413 test_filter_computed 1 trace.event &&
414 test_filter_not_computed 1 trace.event &&
415 test_filter_trunc_empty 0 trace.event &&
416 test_filter_trunc_large 0 trace.event
417 )
418 '
419
420 test_expect_success 'Bloom generation backfills empty commits' '
421 git init empty &&
422 test_when_finished "rm -fr empty" &&
423 (
424 cd empty &&
425 for i in $(test_seq 1 6)
426 do
427 git commit --allow-empty -m "$i" || return 1
428 done &&
429
430 # Generate Bloom filters for empty commits 1-6, two at a time.
431 for i in $(test_seq 1 3)
432 do
433 rm -f trace.event &&
434 GIT_TRACE2_EVENT="$(pwd)/trace.event" \
435 git commit-graph write --reachable \
436 --changed-paths --max-new-filters=2 &&
437 test_filter_computed 2 trace.event &&
438 test_filter_not_computed 4 trace.event &&
439 test_filter_trunc_empty 2 trace.event &&
440 test_filter_trunc_large 0 trace.event || return 1
441 done &&
442
443 # Finally, make sure that once all commits have filters, that
444 # none are subsequently recomputed.
445 rm -f trace.event &&
446 GIT_TRACE2_EVENT="$(pwd)/trace.event" \
447 git commit-graph write --reachable \
448 --changed-paths --max-new-filters=2 &&
449 test_filter_computed 0 trace.event &&
450 test_filter_not_computed 6 trace.event &&
451 test_filter_trunc_empty 0 trace.event &&
452 test_filter_trunc_large 0 trace.event
453 )
454 '
455
456 graph=.git/objects/info/commit-graph
457 graphdir=.git/objects/info/commit-graphs
458 chain=$graphdir/commit-graph-chain
459
460 test_expect_success 'setup for mixed Bloom setting tests' '
461 repo=mixed-bloom-settings &&
462
463 git init $repo &&
464 for i in one two three
465 do
466 test_commit -C $repo $i file || return 1
467 done
468 '
469
470 test_expect_success 'ensure Bloom filters with incompatible settings are ignored' '
471 # Compute Bloom filters with "unusual" settings.
472 git -C $repo rev-parse one >in &&
473 GIT_TEST_BLOOM_SETTINGS_NUM_HASHES=3 git -C $repo commit-graph write \
474 --stdin-commits --changed-paths --split <in &&
475 layer=$(head -n 1 $repo/$chain) &&
476
477 # A commit-graph layer without Bloom filters "hides" the layers
478 # below ...
479 git -C $repo rev-parse two >in &&
480 git -C $repo commit-graph write --stdin-commits --no-changed-paths \
481 --split=no-merge <in &&
482
483 # Another commit-graph layer that has Bloom filters, but with
484 # standard settings, and is thus incompatible with the base
485 # layer written above.
486 git -C $repo rev-parse HEAD >in &&
487 git -C $repo commit-graph write --stdin-commits --changed-paths \
488 --split=no-merge <in &&
489
490 test_line_count = 3 $repo/$chain &&
491
492 # Ensure that incompatible Bloom filters are ignored.
493 git -C $repo -c core.commitGraph=false log --oneline --no-decorate -- file \
494 >expect 2>err &&
495 git -C $repo log --oneline --no-decorate -- file >actual 2>err &&
496 test_cmp expect actual &&
497 grep "disabling Bloom filters for commit-graph layer .$layer." err
498 '
499
500 test_expect_success 'merge graph layers with incompatible Bloom settings' '
501 # Ensure that incompatible Bloom filters are ignored when
502 # merging existing layers.
503 >trace2.txt &&
504 GIT_TRACE2_EVENT="$(pwd)/trace2.txt" \
505 git -C $repo commit-graph write --reachable --changed-paths 2>err &&
506 grep "disabling Bloom filters for commit-graph layer .$layer." err &&
507 grep "{\"hash_version\":1,\"num_hashes\":7,\"bits_per_entry\":10,\"max_changed_paths\":512" trace2.txt &&
508
509 test_path_is_file $repo/$graph &&
510 test_dir_is_empty $repo/$graphdir &&
511
512 git -C $repo -c core.commitGraph=false log --oneline --no-decorate -- \
513 file >expect &&
514 trace_out="$(pwd)/trace.perf" &&
515 GIT_TRACE2_PERF="$trace_out" \
516 git -C $repo log --oneline --no-decorate -- file >actual 2>err &&
517
518 test_cmp expect actual &&
519 grep "statistics:{\"filter_not_present\":0," trace.perf &&
520 test_must_be_empty err
521 '
522
523 # chosen to be the same under all Unicode normalization forms
524 CENT=$(printf "\302\242")
525
526 test_expect_success 'ensure Bloom filter with incompatible versions are ignored' '
527 rm "$repo/$graph" &&
528
529 git -C $repo log --oneline --no-decorate -- $CENT >expect &&
530
531 # Compute v1 Bloom filters for commits at the bottom.
532 git -C $repo rev-parse HEAD^ >in &&
533 git -C $repo commit-graph write --stdin-commits --changed-paths \
534 --split <in &&
535
536 # Compute v2 Bloomfilters for the rest of the commits at the top.
537 git -C $repo rev-parse HEAD >in &&
538 git -C $repo -c commitGraph.changedPathsVersion=2 commit-graph write \
539 --stdin-commits --changed-paths --split=no-merge <in &&
540
541 test_line_count = 2 $repo/$chain &&
542
543 git -C $repo log --oneline --no-decorate -- $CENT >actual 2>err &&
544 test_cmp expect actual &&
545
546 layer="$(head -n 1 $repo/$chain)" &&
547 cat >expect.err <<-EOF &&
548 warning: disabling Bloom filters for commit-graph layer $SQ$layer$SQ due to incompatible settings
549 EOF
550 test_cmp expect.err err &&
551
552 # Merge the two layers with incompatible bloom filter versions,
553 # ensuring that the v2 filters are used.
554 >trace2.txt &&
555 GIT_TRACE2_EVENT="$(pwd)/trace2.txt" \
556 git -C $repo -c commitGraph.changedPathsVersion=2 commit-graph write --reachable --changed-paths 2>err &&
557 grep "disabling Bloom filters for commit-graph layer .$layer." err &&
558 grep "{\"hash_version\":2,\"num_hashes\":7,\"bits_per_entry\":10,\"max_changed_paths\":512" trace2.txt
559 '
560
561 get_first_changed_path_filter () {
562 test-tool read-graph bloom-filters >filters.dat &&
563 head -n 1 filters.dat
564 }
565
566 test_expect_success 'set up repo with high bit path, version 1 changed-path' '
567 git init highbit1 &&
568 test_commit -C highbit1 c1 "$CENT" &&
569 git -C highbit1 commit-graph write --reachable --changed-paths
570 '
571
572 test_expect_success 'setup check value of version 1 changed-path' '
573 (
574 cd highbit1 &&
575 echo "52a9" >expect &&
576 get_first_changed_path_filter >actual
577 )
578 '
579
580 # expect will not match actual if char is unsigned by default. Write the test
581 # in this way, so that a user running this test script can still see if the two
582 # files match. (It will appear as an ordinary success if they match, and a skip
583 # if not.)
584 if test_cmp highbit1/expect highbit1/actual
585 then
586 test_set_prereq SIGNED_CHAR_BY_DEFAULT
587 fi
588 test_expect_success SIGNED_CHAR_BY_DEFAULT 'check value of version 1 changed-path' '
589 # Only the prereq matters for this test.
590 true
591 '
592
593 test_expect_success 'setup make another commit' '
594 # "git log" does not use Bloom filters for root commits - see how, in
595 # revision.c, rev_compare_tree() (the only code path that eventually calls
596 # get_bloom_filter()) is only called by try_to_simplify_commit() when the commit
597 # has one parent. Therefore, make another commit so that we perform the tests on
598 # a non-root commit.
599 test_commit -C highbit1 anotherc1 "another$CENT"
600 '
601
602 test_expect_success 'version 1 changed-path used when version 1 requested' '
603 (
604 cd highbit1 &&
605 test_bloom_filters_used "-- another$CENT"
606 )
607 '
608
609 test_expect_success 'version 1 changed-path not used when version 2 requested' '
610 (
611 cd highbit1 &&
612 git config --add commitGraph.changedPathsVersion 2 &&
613 test_bloom_filters_not_used "-- another$CENT"
614 )
615 '
616
617 test_expect_success 'version 1 changed-path used when autodetect requested' '
618 (
619 cd highbit1 &&
620 git config --add commitGraph.changedPathsVersion -1 &&
621 test_bloom_filters_used "-- another$CENT"
622 )
623 '
624
625 test_expect_success 'when writing another commit graph, preserve existing version 1 of changed-path' '
626 test_commit -C highbit1 c1double "$CENT$CENT" &&
627 git -C highbit1 commit-graph write --reachable --changed-paths &&
628 (
629 cd highbit1 &&
630 git config --add commitGraph.changedPathsVersion -1 &&
631 echo "options: bloom(1,10,7) read_generation_data" >expect &&
632 test-tool read-graph >full &&
633 grep options full >actual &&
634 test_cmp expect actual
635 )
636 '
637
638 test_expect_success 'set up repo with high bit path, version 2 changed-path' '
639 git init highbit2 &&
640 git -C highbit2 config --add commitGraph.changedPathsVersion 2 &&
641 test_commit -C highbit2 c2 "$CENT" &&
642 git -C highbit2 commit-graph write --reachable --changed-paths
643 '
644
645 test_expect_success 'check value of version 2 changed-path' '
646 (
647 cd highbit2 &&
648 echo "c01f" >expect &&
649 get_first_changed_path_filter >actual &&
650 test_cmp expect actual
651 )
652 '
653
654 test_expect_success 'setup make another commit' '
655 # "git log" does not use Bloom filters for root commits - see how, in
656 # revision.c, rev_compare_tree() (the only code path that eventually calls
657 # get_bloom_filter()) is only called by try_to_simplify_commit() when the commit
658 # has one parent. Therefore, make another commit so that we perform the tests on
659 # a non-root commit.
660 test_commit -C highbit2 anotherc2 "another$CENT"
661 '
662
663 test_expect_success 'version 2 changed-path used when version 2 requested' '
664 (
665 cd highbit2 &&
666 test_bloom_filters_used "-- another$CENT"
667 )
668 '
669
670 test_expect_success 'version 2 changed-path not used when version 1 requested' '
671 (
672 cd highbit2 &&
673 git config --add commitGraph.changedPathsVersion 1 &&
674 test_bloom_filters_not_used "-- another$CENT"
675 )
676 '
677
678 test_expect_success 'version 2 changed-path used when autodetect requested' '
679 (
680 cd highbit2 &&
681 git config --add commitGraph.changedPathsVersion -1 &&
682 test_bloom_filters_used "-- another$CENT"
683 )
684 '
685
686 test_expect_success 'when writing another commit graph, preserve existing version 2 of changed-path' '
687 test_commit -C highbit2 c2double "$CENT$CENT" &&
688 git -C highbit2 commit-graph write --reachable --changed-paths &&
689 (
690 cd highbit2 &&
691 git config --add commitGraph.changedPathsVersion -1 &&
692 echo "options: bloom(2,10,7) read_generation_data" >expect &&
693 test-tool read-graph >full &&
694 grep options full >actual &&
695 test_cmp expect actual
696 )
697 '
698
699 test_expect_success 'when writing commit graph, do not reuse changed-path of another version' '
700 git init doublewrite &&
701 test_commit -C doublewrite c "$CENT" &&
702
703 git -C doublewrite config --add commitGraph.changedPathsVersion 1 &&
704 >trace2.txt &&
705 GIT_TRACE2_EVENT="$(pwd)/trace2.txt" \
706 git -C doublewrite commit-graph write --reachable --changed-paths &&
707 test_filter_computed 1 trace2.txt &&
708 test_filter_upgraded 0 trace2.txt &&
709
710 git -C doublewrite commit-graph write --reachable --changed-paths &&
711 for v in -2 3
712 do
713 git -C doublewrite config --add commitGraph.changedPathsVersion $v &&
714 git -C doublewrite commit-graph write --reachable --changed-paths 2>err &&
715 cat >expect <<-EOF &&
716 warning: attempting to write a commit-graph, but ${SQ}commitGraph.changedPathsVersion${SQ} ($v) is not supported
717 EOF
718 test_cmp expect err || return 1
719 done &&
720
721 git -C doublewrite config --add commitGraph.changedPathsVersion 2 &&
722 >trace2.txt &&
723 GIT_TRACE2_EVENT="$(pwd)/trace2.txt" \
724 git -C doublewrite commit-graph write --reachable --changed-paths &&
725 test_filter_computed 1 trace2.txt &&
726 test_filter_upgraded 0 trace2.txt &&
727
728 (
729 cd doublewrite &&
730 echo "c01f" >expect &&
731 get_first_changed_path_filter >actual &&
732 test_cmp expect actual
733 )
734 '
735
736 test_expect_success 'when writing commit graph, reuse changed-path of another version where possible' '
737 git init upgrade &&
738
739 test_commit -C upgrade base no-high-bits &&
740
741 git -C upgrade config --add commitGraph.changedPathsVersion 1 &&
742 >trace2.txt &&
743 GIT_TRACE2_EVENT="$(pwd)/trace2.txt" \
744 git -C upgrade commit-graph write --reachable --changed-paths &&
745 test_filter_computed 1 trace2.txt &&
746 test_filter_upgraded 0 trace2.txt &&
747
748 git -C upgrade config --add commitGraph.changedPathsVersion 2 &&
749 >trace2.txt &&
750 GIT_TRACE2_EVENT="$(pwd)/trace2.txt" \
751 git -C upgrade commit-graph write --reachable --changed-paths &&
752 test_filter_computed 0 trace2.txt &&
753 test_filter_upgraded 1 trace2.txt
754 '
755
756 corrupt_graph () {
757 test_when_finished "rm -rf $graph" &&
758 git commit-graph write --reachable --changed-paths &&
759 corrupt_chunk_file $graph "$@"
760 }
761
762 check_corrupt_graph () {
763 corrupt_graph "$@" &&
764 git -c core.commitGraph=false log -- A/B/file2 >expect.out &&
765 git -c core.commitGraph=true log -- A/B/file2 >out 2>err &&
766 test_cmp expect.out out
767 }
768
769 test_expect_success PERL_TEST_HELPERS 'Bloom reader notices too-small data chunk' '
770 check_corrupt_graph BDAT clear 00000000 &&
771 echo "warning: ignoring too-small changed-path chunk" \
772 "(4 < 12) in commit-graph file" >expect.err &&
773 test_cmp expect.err err
774 '
775
776 test_expect_success PERL_TEST_HELPERS 'Bloom reader notices out-of-bounds filter offsets' '
777 check_corrupt_graph BIDX 12 FFFFFFFF &&
778 # use grep to avoid depending on exact chunk size
779 grep "warning: ignoring out-of-range offset (4294967295) for changed-path filter at pos 3 of .git/objects/info/commit-graph" err
780 '
781
782 test_expect_success PERL_TEST_HELPERS 'Bloom reader notices too-small index chunk' '
783 # replace the index with a single entry, making most
784 # lookups out-of-bounds
785 check_corrupt_graph BIDX clear 00000000 &&
786 echo "warning: commit-graph changed-path index chunk" \
787 "is too small" >expect.err &&
788 test_cmp expect.err err
789 '
790
791 test_expect_success PERL_TEST_HELPERS 'Bloom reader notices out-of-order index offsets' '
792 # we do not know any real offsets, but we can pick
793 # something plausible; we should not get to the point of
794 # actually reading from the bogus offsets anyway.
795 corrupt_graph BIDX 4 0000000c00000005 &&
796 echo "warning: ignoring decreasing changed-path index offsets" \
797 "(12 > 5) for positions 1 and 2 of .git/objects/info/commit-graph" >expect.err &&
798 git -c core.commitGraph=false log -- A/B/file2 >expect.out &&
799 git -c core.commitGraph=true log -- A/B/file2 >out 2>err &&
800 test_cmp expect.out out &&
801 test_cmp expect.err err
802 '
803
804 test_done