1
2
3
4
5
6
7
8
9
10
11 package org.eclipse.jgit.internal.storage.file;
12
13 import static java.lang.Integer.valueOf;
14 import static org.junit.Assert.assertEquals;
15 import static org.junit.Assert.assertNotEquals;
16 import static org.junit.Assert.assertNotNull;
17 import static org.junit.Assert.assertTrue;
18 import static org.junit.Assert.fail;
19
20 import java.io.IOException;
21 import java.util.Collection;
22 import java.util.Collections;
23 import java.util.concurrent.BrokenBarrierException;
24 import java.util.concurrent.Callable;
25 import java.util.concurrent.CountDownLatch;
26 import java.util.concurrent.CyclicBarrier;
27 import java.util.concurrent.ExecutionException;
28 import java.util.concurrent.ExecutorService;
29 import java.util.concurrent.Executors;
30 import java.util.concurrent.Future;
31 import java.util.concurrent.TimeUnit;
32
33 import org.eclipse.jgit.errors.CancelledException;
34 import org.eclipse.jgit.internal.JGitText;
35 import org.eclipse.jgit.internal.storage.pack.PackWriter;
36 import org.eclipse.jgit.junit.TestRepository;
37 import org.eclipse.jgit.lib.ConfigConstants;
38 import org.eclipse.jgit.lib.EmptyProgressMonitor;
39 import org.eclipse.jgit.lib.NullProgressMonitor;
40 import org.eclipse.jgit.lib.ObjectId;
41 import org.eclipse.jgit.lib.Sets;
42 import org.eclipse.jgit.revwalk.RevBlob;
43 import org.eclipse.jgit.revwalk.RevCommit;
44 import org.eclipse.jgit.storage.file.FileBasedConfig;
45 import org.eclipse.jgit.test.resources.SampleDataRepositoryTestCase;
46 import org.junit.Test;
47
48 public class GcConcurrentTest extends GcTestCase {
49 @Test
50 public void concurrentRepack() throws Exception {
51 final CyclicBarrier syncPoint = new CyclicBarrier(2);
52
53 class DoRepack extends EmptyProgressMonitor implements
54 Callable<Integer> {
55
56 @Override
57 public void beginTask(String title, int totalWork) {
58 if (title.equals(JGitText.get().writingObjects)) {
59 try {
60 syncPoint.await();
61 } catch (InterruptedException e) {
62 Thread.currentThread().interrupt();
63 } catch (BrokenBarrierException ignored) {
64
65 }
66 }
67 }
68
69
70 @Override
71 public Integer call() throws Exception {
72 try {
73 gc.setProgressMonitor(this);
74 gc.repack();
75 return valueOf(0);
76 } catch (IOException e) {
77
78
79
80 Thread.currentThread().interrupt();
81 try {
82 syncPoint.await();
83 } catch (InterruptedException ignored) {
84
85 }
86 return valueOf(1);
87 }
88 }
89 }
90
91 RevBlob a = tr.blob("a");
92 tr.lightweightTag("t", a);
93
94 ExecutorService pool = Executors.newFixedThreadPool(2);
95 try {
96 DoRepack repack1 = new DoRepack();
97 DoRepack repack2 = new DoRepack();
98 Future<Integer> result1 = pool.submit(repack1);
99 Future<Integer> result2 = pool.submit(repack2);
100 assertEquals(0, result1.get().intValue() + result2.get().intValue());
101 } finally {
102 pool.shutdown();
103 pool.awaitTermination(Long.MAX_VALUE, TimeUnit.SECONDS);
104 }
105 }
106
107 @Test
108 public void repackAndGetStats() throws Exception {
109 TestRepository<FileRepository>.BranchBuilder test = tr.branch("test");
110 test.commit().add("a", "a").create();
111 GC gc1 = new GC(tr.getRepository());
112 gc1.setPackExpireAgeMillis(0);
113 gc1.gc().get();
114 test.commit().add("b", "b").create();
115
116
117
118
119 FileRepository r2 = new FileRepository(
120 tr.getRepository().getDirectory());
121 GC gc2 = new GC(r2);
122 gc2.setPackExpireAgeMillis(0);
123 gc2.gc().get();
124
125 new GC(tr.getRepository()).getStatistics();
126 }
127
128 @Test
129 public void repackAndUploadPack() throws Exception {
130 TestRepository<FileRepository>.BranchBuilder test = tr.branch("test");
131
132 test.commit().add("a", "a").create();
133
134 GC gc1 = new GC(tr.getRepository());
135 gc1.setPackExpireAgeMillis(0);
136 gc1.gc().get();
137
138 RevCommit b = test.commit().add("b", "b").create();
139
140 FileRepository r2 = new FileRepository(
141 tr.getRepository().getDirectory());
142 GC gc2 = new GC(r2);
143 gc2.setPackExpireAgeMillis(0);
144 gc2.gc().get();
145
146
147
148
149
150
151 try (PackWriter pw = new PackWriter(tr.getRepository())) {
152 pw.setUseBitmaps(true);
153 pw.preparePack(NullProgressMonitor.INSTANCE, Sets.of(b),
154 Collections.<ObjectId> emptySet());
155 new GC(tr.getRepository()).getStatistics();
156 }
157 }
158
159 Pack getSinglePack(FileRepository r) {
160 Collection<Pack> packs = r.getObjectDatabase().getPacks();
161 assertEquals(1, packs.size());
162 return packs.iterator().next();
163 }
164
165 @Test
166 public void repackAndCheckBitmapUsage() throws Exception {
167
168
169
170 TestRepository<FileRepository>.BranchBuilder test = tr.branch("test");
171 test.commit().add("a", "a").create();
172 FileRepository repository = tr.getRepository();
173 GC gc1 = new GC(repository);
174 gc1.setPackExpireAgeMillis(0);
175 gc1.gc().get();
176 String oldPackName = getSinglePack(repository).getPackName();
177 RevCommit b = test.commit().add("b", "b").create();
178
179
180 FileRepository repository2 = new FileRepository(repository.getDirectory());
181 GC gc2 = new GC(repository2);
182 gc2.setPackExpireAgeMillis(0);
183 gc2.gc().get();
184 String newPackName = getSinglePack(repository2).getPackName();
185
186 assertNotEquals(oldPackName, newPackName);
187
188
189
190
191 assertNotEquals(getSinglePack(repository).getPackName(), newPackName);
192
193
194
195 repository.getObjectDatabase().open(b).getSize();
196 assertEquals(getSinglePack(repository).getPackName(), newPackName);
197 assertNotNull(getSinglePack(repository).getBitmapIndex());
198 }
199
200 @Test
201 public void testInterruptGc() throws Exception {
202 FileBasedConfig c = repo.getConfig();
203 c.setInt(ConfigConstants.CONFIG_GC_SECTION, null,
204 ConfigConstants.CONFIG_KEY_AUTOPACKLIMIT, 1);
205 c.save();
206 SampleDataRepositoryTestCase.copyCGitTestPacks(repo);
207 ExecutorService executor = Executors.newSingleThreadExecutor();
208 final CountDownLatch latch = new CountDownLatch(1);
209 Future<Collection<Pack>> result = executor.submit(() -> {
210 long start = System.currentTimeMillis();
211 System.out.println("starting gc");
212 latch.countDown();
213 Collection<Pack> r = gc.gc().get();
214 System.out.println(
215 "gc took " + (System.currentTimeMillis() - start) + " ms");
216 return r;
217 });
218 try {
219 latch.await();
220 Thread.sleep(5);
221 executor.shutdownNow();
222 result.get();
223 fail("thread wasn't interrupted");
224 } catch (ExecutionException e) {
225 Throwable cause = e.getCause();
226 if (cause instanceof CancelledException) {
227 assertEquals(JGitText.get().operationCanceled,
228 cause.getMessage());
229 } else if (cause instanceof IOException) {
230 Throwable cause2 = cause.getCause();
231 assertTrue(cause2 instanceof InterruptedException
232 || cause2 instanceof ExecutionException);
233 } else {
234 fail("unexpected exception " + e);
235 }
236 }
237 }
238 }