1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44 package org.eclipse.jgit.internal.storage.pack;
45
46 import static org.junit.Assert.assertEquals;
47 import static org.junit.Assert.assertTrue;
48
49 import java.io.IOException;
50 import java.util.ArrayList;
51 import java.util.Arrays;
52 import java.util.Collections;
53 import java.util.List;
54 import java.util.Set;
55
56 import org.eclipse.jgit.internal.storage.file.GcTestCase;
57 import org.eclipse.jgit.internal.storage.file.PackBitmapIndexBuilder;
58 import org.eclipse.jgit.internal.storage.pack.PackWriterBitmapPreparer.BitmapCommit;
59 import org.eclipse.jgit.junit.TestRepository.BranchBuilder;
60 import org.eclipse.jgit.junit.TestRepository.CommitBuilder;
61 import org.eclipse.jgit.lib.Constants;
62 import org.eclipse.jgit.lib.NullProgressMonitor;
63 import org.eclipse.jgit.lib.ObjectId;
64 import org.eclipse.jgit.revwalk.RevCommit;
65 import org.eclipse.jgit.storage.pack.PackConfig;
66 import org.junit.Test;
67
68 public class GcCommitSelectionTest extends GcTestCase {
69
70 @Test
71 public void testBitmapSpansNoMerges() throws Exception {
72 testBitmapSpansNoMerges(false);
73 }
74
75 @Test
76 public void testBitmapSpansNoMergesWithTags() throws Exception {
77 testBitmapSpansNoMerges(true);
78 }
79
80 private void testBitmapSpansNoMerges(boolean withTags) throws Exception {
81
82
83
84
85
86
87
88 int[][] bitmapCounts = {
89 { 1, 1 }, { 50, 50 }, { 99, 99 }, { 100, 100 }, { 101, 100 },
90 { 200, 100 }, { 201, 100 }, { 299, 100 }, { 300, 101 },
91 { 301, 101 }, { 401, 101 }, { 499, 101 }, { 500, 102 }, };
92 int currentCommits = 0;
93 BranchBuilder bb = tr.branch("refs/heads/main");
94
95 for (int[] counts : bitmapCounts) {
96 int nextCommitCount = counts[0];
97 int expectedBitmapCount = counts[1];
98 assertTrue(nextCommitCount > currentCommits);
99 for (int i = currentCommits; i < nextCommitCount; i++) {
100 String str = "A" + i;
101 RevCommit rc = bb.commit().message(str).add(str, str).create();
102 if (withTags) {
103 tr.lightweightTag(str, rc);
104 }
105 }
106 currentCommits = nextCommitCount;
107
108 gc.setPackExpireAgeMillis(0);
109 gc.setExpireAgeMillis(0);
110 gc.gc();
111 assertEquals(currentCommits * 3,
112 gc.getStatistics().numberOfPackedObjects);
113 assertEquals(currentCommits + " commits: ", expectedBitmapCount,
114 gc.getStatistics().numberOfBitmaps);
115 }
116 }
117
118 @Test
119 public void testBitmapSpansWithMerges() throws Exception {
120
121
122
123
124
125
126 List<Integer> merges = Arrays.asList(Integer.valueOf(55),
127 Integer.valueOf(115), Integer.valueOf(175),
128 Integer.valueOf(235));
129
130
131
132
133
134
135
136 int[][] bitmapCounts = {
137 { 1, 1 }, { 55, 55 }, { 56, 57 },
138 { 99, 100 },
139 { 100, 100 },
140 { 116, 100 },
141 { 176, 101 },
142 { 213, 101 },
143 { 214, 102 },
144 { 236, 102 },
145 { 273, 102 },
146 { 274, 103 },
147 { 334, 103 },
148 { 335, 104 },
149 { 435, 104 },
150 { 436, 104 },
151 };
152
153 int currentCommits = 0;
154 BranchBuilder bb = tr.branch("refs/heads/main");
155
156 for (int[] counts : bitmapCounts) {
157 int nextCommitCount = counts[0];
158 int expectedBitmapCount = counts[1];
159 assertTrue(nextCommitCount > currentCommits);
160 for (int i = currentCommits; i < nextCommitCount; i++) {
161 String str = "A" + i;
162 if (!merges.contains(Integer.valueOf(i))) {
163 bb.commit().message(str).add(str, str).create();
164 } else {
165 BranchBuilder bbN = tr.branch("refs/heads/A" + i);
166 bb.commit().message(str).add(str, str)
167 .parent(bbN.commit().create()).create();
168 }
169 }
170 currentCommits = nextCommitCount;
171
172 gc.setPackExpireAgeMillis(0);
173 gc.setExpireAgeMillis(0);
174 gc.gc();
175 assertEquals(currentCommits + " commits: ", expectedBitmapCount,
176 gc.getStatistics().numberOfBitmaps);
177 }
178 }
179
180 @Test
181 public void testBitmapsForExcessiveBranches() throws Exception {
182 int oneDayInSeconds = 60 * 60 * 24;
183
184
185 BranchBuilder bbA = tr.branch("refs/heads/A");
186 for (int i = 0; i < 1001; i++) {
187 String msg = "A" + i;
188 bbA.commit().message(msg).add(msg, msg).create();
189 }
190
191 tr.tick(oneDayInSeconds * 90);
192 BranchBuilder bbB = tr.branch("refs/heads/B");
193 for (int i = 0; i < 1001; i++) {
194 String msg = "B" + i;
195 bbB.commit().message(msg).add(msg, msg).create();
196 }
197
198 for (int i = 0; i < 100; i++) {
199 BranchBuilder bb = tr.branch("refs/heads/N" + i);
200 String msg = "singlecommit" + i;
201 bb.commit().message(msg).add(msg, msg).create();
202 }
203
204 tr.tick(oneDayInSeconds);
205
206
207
208 final int commitsForSparseBranch = 1 + (1001 / 200);
209 final int commitsForFullBranch = 100 + (901 / 200);
210 final int commitsForShallowBranches = 100;
211
212
213 gc.setPackExpireAgeMillis(0);
214 gc.setExpireAgeMillis(0);
215 gc.gc();
216 assertEquals(
217 commitsForSparseBranch + commitsForFullBranch
218 + commitsForShallowBranches,
219 gc.getStatistics().numberOfBitmaps);
220 }
221
222 @Test
223 public void testSelectionOrderingWithChains() throws Exception {
224
225
226
227
228
229
230
231
232 BranchBuilder bb = tr.branch("refs/heads/main");
233 RevCommit m0 = addCommit(bb, "m0");
234 RevCommit m1 = addCommit(bb, "m1", m0);
235 RevCommit m2 = addCommit(bb, "m2", m1);
236 RevCommit b3 = addCommit(bb, "b3", m1);
237 RevCommit m4 = addCommit(bb, "m4", m2);
238 RevCommit b5 = addCommit(bb, "m5", b3);
239 RevCommit m6 = addCommit(bb, "m6", m4);
240 RevCommit b7 = addCommit(bb, "m7", b5);
241 RevCommit m8 = addCommit(bb, "m8", m6, b7);
242 RevCommit m9 = addCommit(bb, "m9", m8);
243
244 List<RevCommit> commits = Arrays.asList(m0, m1, m2, b3, m4, b5, m6, b7,
245 m8, m9);
246 PackWriterBitmapPreparer preparer = newPeparer(m9, commits);
247 List<BitmapCommit> selection = new ArrayList<>(
248 preparer.selectCommits(commits.size(), PackWriter.NONE));
249
250
251 String[] expected = { m0.name(), m1.name(), m2.name(), m4.name(),
252 m6.name(), m8.name(), m9.name(), b3.name(), b5.name(),
253 b7.name() };
254 assertEquals(expected.length, selection.size());
255 for (int i = 0; i < expected.length; i++) {
256 assertEquals("Entry " + i, expected[i], selection.get(i).getName());
257 }
258 }
259
260 private RevCommit addCommit(BranchBuilder bb, String msg,
261 RevCommit... parents) throws Exception {
262 CommitBuilder commit = bb.commit().message(msg).add(msg, msg).tick(1)
263 .noParents();
264 for (RevCommit parent : parents) {
265 commit.parent(parent);
266 }
267 return commit.create();
268 }
269
270 private PackWriterBitmapPreparer newPeparer(RevCommit want,
271 List<RevCommit> commits)
272 throws IOException {
273 List<ObjectToPack> objects = new ArrayList<>(commits.size());
274 for (RevCommit commit : commits) {
275 objects.add(new ObjectToPack(commit, Constants.OBJ_COMMIT));
276 }
277 Set<ObjectId> wants = Collections.singleton((ObjectId) want);
278 PackConfig config = new PackConfig();
279 PackBitmapIndexBuilder builder = new PackBitmapIndexBuilder(objects);
280 return new PackWriterBitmapPreparer(
281 tr.getRepository().newObjectReader(), builder,
282 NullProgressMonitor.INSTANCE, wants, config);
283 }
284 }