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.file;
45
46 import static org.hamcrest.Matchers.lessThanOrEqualTo;
47 import static org.junit.Assert.assertEquals;
48 import static org.junit.Assert.assertFalse;
49 import static org.junit.Assert.assertNotNull;
50 import static org.junit.Assert.assertNull;
51 import static org.junit.Assert.assertSame;
52 import static org.junit.Assert.assertThat;
53
54 import java.io.File;
55 import java.io.IOException;
56 import java.nio.file.Files;
57 import java.nio.file.Path;
58 import java.util.concurrent.BrokenBarrierException;
59 import java.util.concurrent.Callable;
60 import java.util.concurrent.CyclicBarrier;
61 import java.util.concurrent.ExecutorService;
62 import java.util.concurrent.Executors;
63 import java.util.concurrent.Future;
64 import java.util.concurrent.TimeUnit;
65
66 import org.eclipse.jgit.api.Git;
67 import org.eclipse.jgit.junit.TestRepository.BranchBuilder;
68 import org.eclipse.jgit.lib.ConfigConstants;
69 import org.eclipse.jgit.lib.Constants;
70 import org.eclipse.jgit.lib.Ref.Storage;
71 import org.eclipse.jgit.lib.RefUpdate;
72 import org.eclipse.jgit.lib.RefUpdate.Result;
73 import org.eclipse.jgit.revwalk.RevBlob;
74 import org.eclipse.jgit.revwalk.RevCommit;
75 import org.eclipse.jgit.storage.file.FileBasedConfig;
76 import org.junit.Test;
77
78 @SuppressWarnings("boxing")
79 public class GcPackRefsTest extends GcTestCase {
80 @Test
81 public void looseRefPacked() throws Exception {
82 RevBlob a = tr.blob("a");
83 tr.lightweightTag("t", a);
84
85 gc.packRefs();
86 assertSame(repo.exactRef("refs/tags/t").getStorage(), Storage.PACKED);
87 }
88
89 @Test
90 public void emptyRefDirectoryDeleted() throws Exception {
91 String ref = "dir/ref";
92 tr.branch(ref).commit().create();
93 String name = repo.findRef(ref).getName();
94 Path dir = repo.getDirectory().toPath().resolve(name).getParent();
95 assertNotNull(dir);
96 gc.packRefs();
97 assertFalse(Files.exists(dir));
98 }
99
100 @Test
101 public void concurrentOnlyOneWritesPackedRefs() throws Exception {
102 RevBlob a = tr.blob("a");
103 tr.lightweightTag("t", a);
104
105 CyclicBarrier syncPoint = new CyclicBarrier(2);
106
107
108 Callable<Integer> packRefs = () -> {
109 syncPoint.await();
110 try {
111 gc.packRefs();
112 return 0;
113 } catch (IOException e) {
114 return 1;
115 }
116 };
117 ExecutorService pool = Executors.newFixedThreadPool(2);
118 try {
119 Future<Integer> p1 = pool.submit(packRefs);
120 Future<Integer> p2 = pool.submit(packRefs);
121 assertThat(p1.get() + p2.get(), lessThanOrEqualTo(1));
122 } finally {
123 pool.shutdown();
124 pool.awaitTermination(Long.MAX_VALUE, TimeUnit.SECONDS);
125 }
126 }
127
128 @Test
129 public void whileRefLockedRefNotPackedNoError()
130 throws Exception {
131 RevBlob a = tr.blob("a");
132 tr.lightweightTag("t1", a);
133 tr.lightweightTag("t2", a);
134 LockFile refLock = new LockFile(new File(repo.getDirectory(),
135 "refs/tags/t1"));
136 try {
137 refLock.lock();
138 gc.packRefs();
139 } finally {
140 refLock.unlock();
141 }
142
143 assertSame(repo.exactRef("refs/tags/t1").getStorage(), Storage.LOOSE);
144 assertSame(repo.exactRef("refs/tags/t2").getStorage(), Storage.PACKED);
145 }
146
147 @Test
148 public void whileRefUpdatedRefUpdateSucceeds()
149 throws Exception {
150 RevBlob a = tr.blob("a");
151 tr.lightweightTag("t", a);
152 final RevBlob b = tr.blob("b");
153
154 final CyclicBarrier refUpdateLockedRef = new CyclicBarrier(2);
155 final CyclicBarrier packRefsDone = new CyclicBarrier(2);
156 ExecutorService pool = Executors.newFixedThreadPool(2);
157 try {
158 Future<Result> result = pool.submit(new Callable<Result>() {
159
160 @Override
161 public Result call() throws Exception {
162 RefUpdate update = new RefDirectoryUpdate(
163 (RefDirectory) repo.getRefDatabase(),
164 repo.exactRef("refs/tags/t")) {
165 @Override
166 public boolean isForceUpdate() {
167 try {
168 refUpdateLockedRef.await();
169 packRefsDone.await();
170 } catch (InterruptedException e) {
171 Thread.currentThread().interrupt();
172 } catch (BrokenBarrierException e) {
173 Thread.currentThread().interrupt();
174 }
175 return super.isForceUpdate();
176 }
177 };
178 update.setForceUpdate(true);
179 update.setNewObjectId(b);
180 return update.update();
181 }
182 });
183
184 pool.submit(new Callable<Void>() {
185 @Override
186 public Void call() throws Exception {
187 refUpdateLockedRef.await();
188 gc.packRefs();
189 packRefsDone.await();
190 return null;
191 }
192 });
193
194 assertSame(result.get(), Result.FORCED);
195
196 } finally {
197 pool.shutdownNow();
198 pool.awaitTermination(Long.MAX_VALUE, TimeUnit.SECONDS);
199 }
200
201 assertEquals(repo.exactRef("refs/tags/t").getObjectId(), b);
202 }
203
204 @Test
205 public void dontPackHEAD_nonBare() throws Exception {
206 BranchBuilder bb = tr.branch("refs/heads/side");
207 RevCommit first = bb.commit().add("A", "A").add("B", "B").create();
208 bb.commit().add("A", "A2").add("B", "B2").create();
209 Git git = Git.wrap(repo);
210
211
212
213 assertEquals(repo.exactRef("HEAD").getTarget().getName(),
214 "refs/heads/master");
215 assertNull(repo.exactRef("HEAD").getTarget().getObjectId());
216 gc.packRefs();
217 assertSame(repo.exactRef("HEAD").getStorage(), Storage.LOOSE);
218 assertEquals(repo.exactRef("HEAD").getTarget().getName(),
219 "refs/heads/master");
220 assertNull(repo.exactRef("HEAD").getTarget().getObjectId());
221
222 git.checkout().setName("refs/heads/side").call();
223 gc.packRefs();
224 assertSame(repo.exactRef("HEAD").getStorage(), Storage.LOOSE);
225
226
227 git.checkout().setName(first.getName()).call();
228 gc.packRefs();
229 assertSame(repo.exactRef("HEAD").getStorage(), Storage.LOOSE);
230 }
231
232 @Test
233 public void dontPackHEAD_bare() throws Exception {
234 BranchBuilder bb = tr.branch("refs/heads/side");
235 bb.commit().add("A", "A").add("B", "B").create();
236 RevCommit second = bb.commit().add("A", "A2").add("B", "B2").create();
237
238
239 FileBasedConfig cfg = repo.getConfig();
240 cfg.setBoolean(ConfigConstants.CONFIG_CORE_SECTION, null,
241 ConfigConstants.CONFIG_KEY_BARE, true);
242 cfg.save();
243 Git git = Git.open(repo.getDirectory());
244 repo = (FileRepository) git.getRepository();
245
246
247
248 assertEquals(repo.exactRef("HEAD").getTarget().getName(),
249 "refs/heads/master");
250 assertNull(repo.exactRef("HEAD").getTarget().getObjectId());
251 gc.packRefs();
252 assertSame(repo.exactRef("HEAD").getStorage(), Storage.LOOSE);
253 assertEquals(repo.exactRef("HEAD").getTarget().getName(),
254 "refs/heads/master");
255 assertNull(repo.exactRef("HEAD").getTarget().getObjectId());
256
257
258 repo.updateRef(Constants.HEAD).link("refs/heads/side");
259 gc.packRefs();
260 assertSame(repo.exactRef("HEAD").getStorage(), Storage.LOOSE);
261 assertEquals(repo.exactRef("HEAD").getTarget().getObjectId(),
262 second.getId());
263 }
264 }