1
+#!/bin/sh
2
+
3
+test_description='pseudo-merge bitmaps'
4
+
5
+GIT_TEST_MULTI_PACK_INDEX_WRITE_BITMAP=0
6
+
7
+. ./test-lib.sh
8
+
9
+test_pseudo_merges () {
10
+ test-tool bitmap dump-pseudo-merges
11
+}
12
+
13
+test_pseudo_merge_commits () {
14
+ test-tool bitmap dump-pseudo-merge-commits "$1"
15
+}
16
+
17
+test_pseudo_merges_satisfied () {
18
+ test_trace2_data bitmap pseudo_merges_satisfied "$1"
19
+}
20
+
21
+test_pseudo_merges_cascades () {
22
+ test_trace2_data bitmap pseudo_merges_cascades "$1"
23
+}
24
+
25
+tag_everything () {
26
+ git rev-list --all --no-object-names >in &&
27
+ perl -lne '
28
+ print "create refs/tags/" . $. . " " . $1 if /([0-9a-f]+)/
29
+ ' <in | git update-ref --stdin
30
+}
31
+
32
+test_expect_success 'setup' '
33
+ test_commit_bulk 512 &&
34
+ tag_everything
35
+'
36
+
37
+test_expect_success 'bitmap traversal without pseudo-merges' '
38
+ git repack -adb &&
39
+
40
+ git rev-list --count --all --objects >expect &&
41
+
42
+ : >trace2.txt &&
43
+ GIT_TRACE2_EVENT=$PWD/trace2.txt \
44
+ git rev-list --count --all --objects --use-bitmap-index >actual &&
45
+
46
+ test_pseudo_merges_satisfied 0 <trace2.txt &&
47
+ test_pseudo_merges_cascades 0 <trace2.txt &&
48
+ test_pseudo_merges >merges &&
49
+ test_must_be_empty merges &&
50
+ test_cmp expect actual
51
+'
52
+
53
+test_expect_success 'pseudo-merges accurately represent their objects' '
54
+ test_config bitmapPseudoMerge.test.pattern "refs/tags/" &&
55
+ test_config bitmapPseudoMerge.test.maxMerges 8 &&
56
+ test_config bitmapPseudoMerge.test.stableThreshold never &&
57
+
58
+ git repack -adb &&
59
+
60
+ test_pseudo_merges >merges &&
61
+ test_line_count = 8 merges &&
62
+
63
+ for i in $(test_seq 0 $(($(wc -l <merges)-1)))
64
+ do
65
+ test-tool bitmap dump-pseudo-merge-commits $i >commits &&
66
+
67
+ git rev-list --objects --no-object-names --stdin <commits >expect.raw &&
68
+ test-tool bitmap dump-pseudo-merge-objects $i >actual.raw &&
69
+
70
+ sort -u <expect.raw >expect &&
71
+ sort -u <actual.raw >actual &&
72
+
73
+ test_cmp expect actual || return 1
74
+ done
75
+'
76
+
77
+test_expect_success 'bitmap traversal with pseudo-merges' '
78
+ : >trace2.txt &&
79
+ GIT_TRACE2_EVENT=$PWD/trace2.txt \
80
+ git rev-list --count --all --objects --use-bitmap-index >actual &&
81
+ git rev-list --count --all --objects >expect &&
82
+
83
+ test_pseudo_merges_satisfied 8 <trace2.txt &&
84
+ test_pseudo_merges_cascades 1 <trace2.txt &&
85
+ test_cmp expect actual
86
+'
87
+
88
+test_expect_success 'stale bitmap traversal with pseudo-merges' '
89
+ test_commit other &&
90
+
91
+ : >trace2.txt &&
92
+ GIT_TRACE2_EVENT=$PWD/trace2.txt \
93
+ git rev-list --count --all --objects --use-bitmap-index >actual &&
94
+ git rev-list --count --all --objects >expect &&
95
+
96
+ test_pseudo_merges_satisfied 8 <trace2.txt &&
97
+ test_pseudo_merges_cascades 1 <trace2.txt &&
98
+ test_cmp expect actual
99
+'
100
+
101
+test_expect_success 'bitmapPseudoMerge.sampleRate adjusts commit selection rate' '
102
+ test_config bitmapPseudoMerge.test.pattern "refs/tags/" &&
103
+ test_config bitmapPseudoMerge.test.maxMerges 1 &&
104
+ test_config bitmapPseudoMerge.test.stableThreshold never &&
105
+
106
+ commits_nr=$(git rev-list --all --count) &&
107
+
108
+ for rate in 1.0 0.5 0.25
109
+ do
110
+ git -c bitmapPseudoMerge.test.sampleRate=$rate repack -adb &&
111
+
112
+ test_pseudo_merges >merges &&
113
+ test_line_count = 1 merges &&
114
+ test_pseudo_merge_commits 0 >commits &&
115
+
116
+ test-tool bitmap list-commits >bitmaps &&
117
+ bitmaps_nr="$(wc -l <bitmaps)" &&
118
+
119
+ perl -MPOSIX -e "print ceil(\$ARGV[0]*(\$ARGV[1]-\$ARGV[2]))" \
120
+ "$rate" "$commits_nr" "$bitmaps_nr" >expect &&
121
+
122
+ test $(cat expect) -eq $(wc -l <commits) || return 1
123
+ done
124
+'
125
+
126
+test_expect_success 'bitmapPseudoMerge.threshold excludes newer commits' '
127
+ git init pseudo-merge-threshold &&
128
+ (
129
+ cd pseudo-merge-threshold &&
130
+
131
+ new="1672549200" && # 2023-01-01
132
+ old="1641013200" && # 2022-01-01
133
+
134
+ GIT_COMMITTER_DATE="$new +0000" &&
135
+ export GIT_COMMITTER_DATE &&
136
+ test_commit_bulk --message="new" --notick 128 &&
137
+
138
+ GIT_COMMITTER_DATE="$old +0000" &&
139
+ export GIT_COMMITTER_DATE &&
140
+ test_commit_bulk --message="old" --notick 128 &&
141
+
142
+ tag_everything &&
143
+
144
+ git \
145
+ -c bitmapPseudoMerge.test.pattern="refs/tags/" \
146
+ -c bitmapPseudoMerge.test.maxMerges=1 \
147
+ -c bitmapPseudoMerge.test.threshold=$(($new - 1)) \
148
+ -c bitmapPseudoMerge.test.stableThreshold=never \
149
+ repack -adb &&
150
+
151
+ test_pseudo_merges >merges &&
152
+ test_line_count = 1 merges &&
153
+
154
+ test_pseudo_merge_commits 0 >oids &&
155
+ git cat-file --batch <oids >commits &&
156
+
157
+ test $(wc -l <oids) = $(grep -c "^committer.*$old +0000$" commits)
158
+ )
159
+'
160
+
161
+test_expect_success 'bitmapPseudoMerge.stableThreshold creates stable groups' '
162
+ (
163
+ cd pseudo-merge-threshold &&
164
+
165
+ new="1672549200" && # 2023-01-01
166
+ mid="1654059600" && # 2022-06-01
167
+ old="1641013200" && # 2022-01-01
168
+
169
+ GIT_COMMITTER_DATE="$mid +0000" &&
170
+ export GIT_COMMITTER_DATE &&
171
+ test_commit_bulk --message="mid" --notick 128 &&
172
+
173
+ git for-each-ref --format="delete %(refname)" refs/tags >in &&
174
+ git update-ref --stdin <in &&
175
+
176
+ tag_everything &&
177
+
178
+ git \
179
+ -c bitmapPseudoMerge.test.pattern="refs/tags/" \
180
+ -c bitmapPseudoMerge.test.maxMerges=1 \
181
+ -c bitmapPseudoMerge.test.threshold=$(($new - 1)) \
182
+ -c bitmapPseudoMerge.test.stableThreshold=$(($mid - 1)) \
183
+ -c bitmapPseudoMerge.test.stableSize=10 \
184
+ repack -adb &&
185
+
186
+ test_pseudo_merges >merges &&
187
+ merges_nr="$(wc -l <merges)" &&
188
+
189
+ for i in $(test_seq $(($merges_nr - 1)))
190
+ do
191
+ test_pseudo_merge_commits 0 >oids &&
192
+ git cat-file --batch <oids >commits &&
193
+
194
+ expect="$(grep -c "^committer.*$old +0000$" commits)" &&
195
+ actual="$(wc -l <oids)" &&
196
+
197
+ test $expect = $actual || return 1
198
+ done &&
199
+
200
+ test_pseudo_merge_commits $(($merges_nr - 1)) >oids &&
201
+ git cat-file --batch <oids >commits &&
202
+ test $(wc -l <oids) = $(grep -c "^committer.*$mid +0000$" commits)
203
+ )
204
+'
205
+
206
+test_expect_success 'out of order thresholds are rejected' '
207
+ test_must_fail git \
208
+ -c bitmapPseudoMerge.test.pattern="refs/*" \
209
+ -c bitmapPseudoMerge.test.threshold=1.month.ago \
210
+ -c bitmapPseudoMerge.test.stableThreshold=1.week.ago \
211
+ repack -adb 2>err &&
212
+
213
+ cat >expect <<-EOF &&
214
+ fatal: pseudo-merge group ${SQ}test${SQ} has unstable threshold before stable one
215
+ EOF
216
+
217
+ test_cmp expect err
218
+'
219
+
220
+test_expect_success 'pseudo-merge pattern with capture groups' '
221
+ git init pseudo-merge-captures &&
222
+ (
223
+ cd pseudo-merge-captures &&
224
+
225
+ test_commit_bulk 128 &&
226
+ tag_everything &&
227
+
228
+ for r in $(test_seq 8)
229
+ do
230
+ test_commit_bulk 16 &&
231
+
232
+ git rev-list HEAD~16.. >in &&
233
+
234
+ perl -lne "print \"create refs/remotes/$r/tags/\$. \$_\"" <in |
235
+ git update-ref --stdin || return 1
236
+ done &&
237
+
238
+ git \
239
+ -c bitmapPseudoMerge.tags.pattern="refs/remotes/([0-9]+)/tags/" \
240
+ -c bitmapPseudoMerge.tags.maxMerges=1 \
241
+ repack -adb &&
242
+
243
+ git for-each-ref --format="%(objectname) %(refname)" >refs &&
244
+
245
+ test_pseudo_merges >merges &&
246
+ for m in $(test_seq 0 $(($(wc -l <merges) - 1)))
247
+ do
248
+ test_pseudo_merge_commits $m >oids &&
249
+ grep -f oids refs |
250
+ perl -lne "print \$1 if /refs\/remotes\/([0-9]+)/" |
251
+ sort -u || return 1
252
+ done >remotes &&
253
+
254
+ test $(wc -l <remotes) -eq $(sort -u <remotes | wc -l)
255
+ )
256
+'
257
+
258
+test_expect_success 'pseudo-merge overlap setup' '
259
+ git init pseudo-merge-overlap &&
260
+ (
261
+ cd pseudo-merge-overlap &&
262
+
263
+ test_commit_bulk 256 &&
264
+ tag_everything &&
265
+
266
+ git \
267
+ -c bitmapPseudoMerge.all.pattern="refs/" \
268
+ -c bitmapPseudoMerge.all.maxMerges=1 \
269
+ -c bitmapPseudoMerge.all.stableThreshold=never \
270
+ -c bitmapPseudoMerge.tags.pattern="refs/tags/" \
271
+ -c bitmapPseudoMerge.tags.maxMerges=1 \
272
+ -c bitmapPseudoMerge.tags.stableThreshold=never \
273
+ repack -adb
274
+ )
275
+'
276
+
277
+test_expect_success 'pseudo-merge overlap generates overlapping groups' '
278
+ (
279
+ cd pseudo-merge-overlap &&
280
+
281
+ test_pseudo_merges >merges &&
282
+ test_line_count = 2 merges &&
283
+
284
+ test_pseudo_merge_commits 0 >commits-0.raw &&
285
+ test_pseudo_merge_commits 1 >commits-1.raw &&
286
+
287
+ sort commits-0.raw >commits-0 &&
288
+ sort commits-1.raw >commits-1 &&
289
+
290
+ comm -12 commits-0 commits-1 >overlap &&
291
+
292
+ test_line_count -gt 0 overlap
293
+ )
294
+'
295
+
296
+test_expect_success 'pseudo-merge overlap traversal' '
297
+ (
298
+ cd pseudo-merge-overlap &&
299
+
300
+ : >trace2.txt &&
301
+ GIT_TRACE2_EVENT=$PWD/trace2.txt \
302
+ git rev-list --count --all --objects --use-bitmap-index >actual &&
303
+ git rev-list --count --all --objects >expect &&
304
+
305
+ test_pseudo_merges_satisfied 2 <trace2.txt &&
306
+ test_pseudo_merges_cascades 1 <trace2.txt &&
307
+ test_cmp expect actual
308
+ )
309
+'
310
+
311
+test_expect_success 'pseudo-merge overlap stale traversal' '
312
+ (
313
+ cd pseudo-merge-overlap &&
314
+
315
+ test_commit other &&
316
+
317
+ : >trace2.txt &&
318
+ GIT_TRACE2_EVENT=$PWD/trace2.txt \
319
+ git rev-list --count --all --objects --use-bitmap-index >actual &&
320
+ git rev-list --count --all --objects >expect &&
321
+
322
+ test_pseudo_merges_satisfied 2 <trace2.txt &&
323
+ test_pseudo_merges_cascades 1 <trace2.txt &&
324
+ test_cmp expect actual
325
+ )
326
+'
327
+
328
+test_done