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