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