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.dfs;
45
46 import static org.eclipse.jgit.lib.Ref.Storage.NEW;
47
48 import java.io.IOException;
49 import java.util.Collections;
50 import java.util.List;
51 import java.util.Map;
52 import java.util.concurrent.atomic.AtomicReference;
53
54 import org.eclipse.jgit.errors.MissingObjectException;
55 import org.eclipse.jgit.lib.ObjectIdRef;
56 import org.eclipse.jgit.lib.Ref;
57 import org.eclipse.jgit.lib.RefDatabase;
58 import org.eclipse.jgit.lib.RefRename;
59 import org.eclipse.jgit.lib.RefUpdate;
60 import org.eclipse.jgit.lib.SymbolicRef;
61 import org.eclipse.jgit.revwalk.RevObject;
62 import org.eclipse.jgit.revwalk.RevTag;
63 import org.eclipse.jgit.revwalk.RevWalk;
64 import org.eclipse.jgit.util.RefList;
65 import org.eclipse.jgit.util.RefMap;
66
67
68
69
70
71 public abstract class DfsRefDatabase extends RefDatabase {
72 private final DfsRepository repository;
73
74 private final AtomicReference<RefCache> cache;
75
76
77
78
79
80
81
82 protected DfsRefDatabase(DfsRepository repository) {
83 this.repository = repository;
84 this.cache = new AtomicReference<>();
85 }
86
87
88
89
90
91
92 protected DfsRepository getRepository() {
93 return repository;
94 }
95
96 boolean exists() throws IOException {
97 return 0 < read().size();
98 }
99
100
101 @Override
102 public Ref exactRef(String name) throws IOException {
103 RefCache curr = read();
104 Ref ref = curr.ids.get(name);
105 return ref != null ? resolve(ref, 0, curr.ids) : null;
106 }
107
108
109 @Override
110 public List<Ref> getAdditionalRefs() {
111 return Collections.emptyList();
112 }
113
114
115 @Override
116 public Map<String, Ref> getRefs(String prefix) throws IOException {
117 RefCache curr = read();
118 RefList<Ref> packed = RefList.emptyList();
119 RefList<Ref> loose = curr.ids;
120 RefList.Builder<Ref> sym = new RefList.Builder<>(curr.sym.size());
121
122 for (int idx = 0; idx < curr.sym.size(); idx++) {
123 Ref ref = curr.sym.get(idx);
124 String name = ref.getName();
125 ref = resolve(ref, 0, loose);
126 if (ref != null && ref.getObjectId() != null) {
127 sym.add(ref);
128 } else {
129
130
131
132 int toRemove = loose.find(name);
133 if (0 <= toRemove)
134 loose = loose.remove(toRemove);
135 }
136 }
137
138 return new RefMap(prefix, packed, loose, sym.toRefList());
139 }
140
141 private Refref="../../../../../../org/eclipse/jgit/lib/Ref.html#Ref">Ref resolve(Ref ref, int depth, RefList<Ref> loose)
142 throws IOException {
143 if (!ref.isSymbolic())
144 return ref;
145
146 Ref dst = ref.getTarget();
147
148 if (MAX_SYMBOLIC_REF_DEPTH <= depth)
149 return null;
150
151 dst = loose.get(dst.getName());
152 if (dst == null)
153 return ref;
154
155 dst = resolve(dst, depth + 1, loose);
156 if (dst == null)
157 return null;
158 return new SymbolicRef(ref.getName(), dst);
159 }
160
161
162 @Override
163 public Ref" href="../../../../../../org/eclipse/jgit/lib/Ref.html#Ref">Ref peel(Ref ref) throws IOException {
164 final Ref oldLeaf = ref.getLeaf();
165 if (oldLeaf.isPeeled() || oldLeaf.getObjectId() == null)
166 return ref;
167
168 Ref newLeaf = doPeel(oldLeaf);
169
170 RefCache cur = read();
171 int idx = cur.ids.find(oldLeaf.getName());
172 if (0 <= idx && cur.ids.get(idx) == oldLeaf) {
173 RefList<Ref> newList = cur.ids.set(idx, newLeaf);
174 cache.compareAndSet(cur, new RefCache(newList, cur));
175 cachePeeledState(oldLeaf, newLeaf);
176 }
177
178 return recreate(ref, newLeaf);
179 }
180
181 Ref doPeel(Ref leaf) throws MissingObjectException,
182 IOException {
183 try (RevWalkvwalk/RevWalk.html#RevWalk">RevWalk rw = new RevWalk(repository)) {
184 RevObject obj = rw.parseAny(leaf.getObjectId());
185 if (obj instanceof RevTag) {
186 return new ObjectIdRef.PeeledTag(
187 leaf.getStorage(),
188 leaf.getName(),
189 leaf.getObjectId(),
190 rw.peel(obj).copy());
191 } else {
192 return new ObjectIdRef.PeeledNonTag(
193 leaf.getStorage(),
194 leaf.getName(),
195 leaf.getObjectId());
196 }
197 }
198 }
199
200 static Ref" href="../../../../../../org/eclipse/jgit/lib/Ref.html#Ref">Refef="../../../../../../org/eclipse/jgit/lib/Ref.html#Ref">Ref recreate(Ref" href="../../../../../../org/eclipse/jgit/lib/Ref.html#Ref">Ref old, Ref leaf) {
201 if (old.isSymbolic()) {
202 Ref dst = recreate(old.getTarget(), leaf);
203 return new SymbolicRef(old.getName(), dst);
204 }
205 return leaf;
206 }
207
208
209 @Override
210 public RefUpdate newUpdate(String refName, boolean detach)
211 throws IOException {
212 boolean detachingSymbolicRef = false;
213 Ref ref = exactRef(refName);
214 if (ref == null)
215 ref = new ObjectIdRef.Unpeeled(NEW, refName, null);
216 else
217 detachingSymbolicRef = detach && ref.isSymbolic();
218
219 DfsRefUpdate update = new DfsRefUpdate(this, ref);
220 if (detachingSymbolicRef)
221 update.setDetachingSymbolicRef();
222 return update;
223 }
224
225
226 @Override
227 public RefRename newRename(String fromName, String toName)
228 throws IOException {
229 RefUpdate src = newUpdate(fromName, true);
230 RefUpdate dst = newUpdate(toName, true);
231 return new DfsRefRename(src, dst);
232 }
233
234
235 @Override
236 public boolean isNameConflicting(String refName) throws IOException {
237 RefList<Ref> all = read().ids;
238
239
240 int lastSlash = refName.lastIndexOf('/');
241 while (0 < lastSlash) {
242 String needle = refName.substring(0, lastSlash);
243 if (all.contains(needle))
244 return true;
245 lastSlash = refName.lastIndexOf('/', lastSlash - 1);
246 }
247
248
249 String prefix = refName + '/';
250 int idx = -(all.find(prefix) + 1);
251 if (idx < all.size() && all.get(idx).getName().startsWith(prefix))
252 return true;
253 return false;
254 }
255
256
257 @Override
258 public void create() {
259
260 }
261
262
263 @Override
264 public void refresh() {
265 clearCache();
266 }
267
268
269 @Override
270 public void close() {
271 clearCache();
272 }
273
274 void clearCache() {
275 cache.set(null);
276 }
277
278 void stored(Ref ref) {
279 RefCache oldCache, newCache;
280 do {
281 oldCache = cache.get();
282 if (oldCache == null)
283 return;
284 newCache = oldCache.put(ref);
285 } while (!cache.compareAndSet(oldCache, newCache));
286 }
287
288 void removed(String refName) {
289 RefCache oldCache, newCache;
290 do {
291 oldCache = cache.get();
292 if (oldCache == null)
293 return;
294 newCache = oldCache.remove(refName);
295 } while (!cache.compareAndSet(oldCache, newCache));
296 }
297
298 private RefCache read() throws IOException {
299 RefCache c = cache.get();
300 if (c == null) {
301 c = scanAllRefs();
302 cache.set(c);
303 }
304 return c;
305 }
306
307
308
309
310
311
312
313
314 protected abstract RefCache scanAllRefs() throws IOException;
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339 protected abstract boolean compareAndPut(Refref="../../../../../../org/eclipse/jgit/lib/Ref.html#Ref">Ref oldRef, Ref newRef)
340 throws IOException;
341
342
343
344
345
346
347
348
349
350
351 protected abstract boolean compareAndRemove(Ref oldRef) throws IOException;
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367 protected void cachePeeledState(Refef="../../../../../../org/eclipse/jgit/lib/Ref.html#Ref">Ref oldLeaf, Ref newLeaf) {
368 try {
369 compareAndPut(oldLeaf, newLeaf);
370 } catch (IOException e) {
371
372 }
373 }
374
375
376 public static class RefCache {
377 final RefList<Ref> ids;
378
379 final RefList<Ref> sym;
380
381
382
383
384
385
386
387
388
389
390
391
392 public RefCache(RefList<Ref> ids, RefList<Ref> sym) {
393 this.ids = ids;
394 this.sym = sym;
395 }
396
397 RefCache(RefList<Ref> ids, RefCache old) {
398 this(ids, old.sym);
399 }
400
401
402 public int size() {
403 return ids.size();
404 }
405
406
407
408
409
410
411
412
413 public Ref get(String name) {
414 return ids.get(name);
415 }
416
417
418
419
420
421
422
423
424
425
426 public RefCache put(Ref ref) {
427 RefList<Ref> newIds = this.ids.put(ref);
428 RefList<Ref> newSym = this.sym;
429 if (ref.isSymbolic()) {
430 newSym = newSym.put(ref);
431 } else {
432 int p = newSym.find(ref.getName());
433 if (0 <= p)
434 newSym = newSym.remove(p);
435 }
436 return new RefCache(newIds, newSym);
437 }
438
439
440
441
442
443
444
445
446
447
448 public RefCache remove(String refName) {
449 RefList<Ref> newIds = this.ids;
450 int p = newIds.find(refName);
451 if (0 <= p)
452 newIds = newIds.remove(p);
453
454 RefList<Ref> newSym = this.sym;
455 p = newSym.find(refName);
456 if (0 <= p)
457 newSym = newSym.remove(p);
458 return new RefCache(newIds, newSym);
459 }
460 }
461 }