Merge branch 'jk/for-each-ref-multi-key-sort-fix'
[git] / t / perf / p5303-many-packs.sh
1 #!/bin/sh
2
3 test_description='performance with large numbers of packs'
4 . ./perf-lib.sh
5
6 test_perf_large_repo
7
8 # A real many-pack situation would probably come from having a lot of pushes
9 # over time. We don't know how big each push would be, but we can fake it by
10 # just walking the first-parent chain and having every 5 commits be their own
11 # "push". This isn't _entirely_ accurate, as real pushes would have some
12 # duplicate objects due to thin-pack fixing, but it's a reasonable
13 # approximation.
14 #
15 # And then all of the rest of the objects can go in a single packfile that
16 # represents the state before any of those pushes (actually, we'll generate
17 # that first because in such a setup it would be the oldest pack, and we sort
18 # the packs by reverse mtime inside git).
19 repack_into_n () {
20         rm -rf staging &&
21         mkdir staging &&
22
23         git rev-list --first-parent HEAD |
24         sed -n '1~5p' |
25         head -n "$1" |
26         perl -e 'print reverse <>' \
27         >pushes
28
29         # create base packfile
30         head -n 1 pushes |
31         git pack-objects --delta-base-offset --revs staging/pack
32
33         # and then incrementals between each pair of commits
34         last= &&
35         while read rev
36         do
37                 if test -n "$last"; then
38                         {
39                                 echo "$rev" &&
40                                 echo "^$last"
41                         } |
42                         git pack-objects --delta-base-offset --revs \
43                                 staging/pack || return 1
44                 fi
45                 last=$rev
46         done <pushes &&
47
48         # and install the whole thing
49         rm -f .git/objects/pack/* &&
50         mv staging/* .git/objects/pack/
51 }
52
53 # Pretend we just have a single branch and no reflogs, and that everything is
54 # in objects/pack; that makes our fake pack-building via repack_into_n()
55 # much simpler.
56 test_expect_success 'simplify reachability' '
57         tip=$(git rev-parse --verify HEAD) &&
58         git for-each-ref --format="option no-deref%0adelete %(refname)" |
59         git update-ref --stdin &&
60         rm -rf .git/logs &&
61         git update-ref refs/heads/master $tip &&
62         git symbolic-ref HEAD refs/heads/master &&
63         git repack -ad
64 '
65
66 for nr_packs in 1 50 1000
67 do
68         test_expect_success "create $nr_packs-pack scenario" '
69                 repack_into_n $nr_packs
70         '
71
72         test_perf "rev-list ($nr_packs)" '
73                 git rev-list --objects --all >/dev/null
74         '
75
76         # This simulates the interesting part of the repack, which is the
77         # actual pack generation, without smudging the on-disk setup
78         # between trials.
79         test_perf "repack ($nr_packs)" '
80                 GIT_TEST_FULL_IN_PACK_ARRAY=1 \
81                 git pack-objects --keep-true-parents \
82                   --honor-pack-keep --non-empty --all \
83                   --reflog --indexed-objects --delta-base-offset \
84                   --stdout </dev/null >/dev/null
85         '
86 done
87
88 # Measure pack loading with 10,000 packs.
89 test_expect_success 'generate lots of packs' '
90         for i in $(test_seq 10000); do
91                 echo "blob"
92                 echo "data <<EOF"
93                 echo "blob $i"
94                 echo "EOF"
95                 echo "checkpoint"
96         done |
97         git -c fastimport.unpackLimit=0 fast-import
98 '
99
100 # The purpose of this test is to evaluate load time for a large number
101 # of packs while doing as little other work as possible.
102 test_perf "load 10,000 packs" '
103         git rev-parse --verify "HEAD^{commit}"
104 '
105
106 test_done