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(() -> {
159 RefUpdate update = new RefDirectoryUpdate(
160 (RefDirectory) repo.getRefDatabase(),
161 repo.exactRef("refs/tags/t")) {
162 @Override
163 public boolean isForceUpdate() {
164 try {
165 refUpdateLockedRef.await();
166 packRefsDone.await();
167 } catch (InterruptedException
168 | BrokenBarrierException e) {
169 Thread.currentThread().interrupt();
170 }
171 return super.isForceUpdate();
172 }
173 };
174 update.setForceUpdate(true);
175 update.setNewObjectId(b);
176 return update.update();
177 });
178
179 Future<Result> result2 = pool.submit(() -> {
180 refUpdateLockedRef.await();
181 gc.packRefs();
182 packRefsDone.await();
183 return null;
184 });
185 assertNull(result2.get());
186
187 assertSame(result.get(), Result.FORCED);
188
189 } finally {
190 pool.shutdownNow();
191 pool.awaitTermination(Long.MAX_VALUE, TimeUnit.SECONDS);
192 }
193
194 assertEquals(repo.exactRef("refs/tags/t").getObjectId(), b);
195 }
196
197 @Test
198 public void dontPackHEAD_nonBare() throws Exception {
199 BranchBuilder bb = tr.branch("refs/heads/side");
200 RevCommit first = bb.commit().add("A", "A").add("B", "B").create();
201 bb.commit().add("A", "A2").add("B", "B2").create();
202 Git git = Git.wrap(repo);
203
204
205
206 assertEquals(repo.exactRef("HEAD").getTarget().getName(),
207 "refs/heads/master");
208 assertNull(repo.exactRef("HEAD").getTarget().getObjectId());
209 gc.packRefs();
210 assertSame(repo.exactRef("HEAD").getStorage(), Storage.LOOSE);
211 assertEquals(repo.exactRef("HEAD").getTarget().getName(),
212 "refs/heads/master");
213 assertNull(repo.exactRef("HEAD").getTarget().getObjectId());
214
215 git.checkout().setName("refs/heads/side").call();
216 gc.packRefs();
217 assertSame(repo.exactRef("HEAD").getStorage(), Storage.LOOSE);
218
219
220 git.checkout().setName(first.getName()).call();
221 gc.packRefs();
222 assertSame(repo.exactRef("HEAD").getStorage(), Storage.LOOSE);
223 }
224
225 @Test
226 public void dontPackHEAD_bare() throws Exception {
227 BranchBuilder bb = tr.branch("refs/heads/side");
228 bb.commit().add("A", "A").add("B", "B").create();
229 RevCommit second = bb.commit().add("A", "A2").add("B", "B2").create();
230
231
232 FileBasedConfig cfg = repo.getConfig();
233 cfg.setBoolean(ConfigConstants.CONFIG_CORE_SECTION, null,
234 ConfigConstants.CONFIG_KEY_BARE, true);
235 cfg.save();
236 Git git = Git.open(repo.getDirectory());
237 repo = (FileRepository) git.getRepository();
238
239
240
241 assertEquals(repo.exactRef("HEAD").getTarget().getName(),
242 "refs/heads/master");
243 assertNull(repo.exactRef("HEAD").getTarget().getObjectId());
244 gc.packRefs();
245 assertSame(repo.exactRef("HEAD").getStorage(), Storage.LOOSE);
246 assertEquals(repo.exactRef("HEAD").getTarget().getName(),
247 "refs/heads/master");
248 assertNull(repo.exactRef("HEAD").getTarget().getObjectId());
249
250
251 repo.updateRef(Constants.HEAD).link("refs/heads/side");
252 gc.packRefs();
253 assertSame(repo.exactRef("HEAD").getStorage(), Storage.LOOSE);
254 assertEquals(repo.exactRef("HEAD").getTarget().getObjectId(),
255 second.getId());
256 }
257 }