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 java.io.IOException;
47 import java.util.Arrays;
48 import java.util.ArrayList;
49 import java.util.Collections;
50 import java.util.HashSet;
51 import java.util.List;
52 import java.util.Map;
53 import java.util.Set;
54 import java.util.concurrent.locks.ReentrantLock;
55
56 import org.eclipse.jgit.annotations.Nullable;
57 import org.eclipse.jgit.internal.storage.reftable.MergedReftable;
58 import org.eclipse.jgit.internal.storage.reftable.RefCursor;
59 import org.eclipse.jgit.internal.storage.reftable.Reftable;
60 import org.eclipse.jgit.internal.storage.reftable.ReftableConfig;
61 import org.eclipse.jgit.lib.BatchRefUpdate;
62 import org.eclipse.jgit.lib.NullProgressMonitor;
63 import org.eclipse.jgit.lib.ObjectId;
64 import org.eclipse.jgit.lib.Ref;
65 import org.eclipse.jgit.revwalk.RevWalk;
66 import org.eclipse.jgit.transport.ReceiveCommand;
67 import org.eclipse.jgit.util.RefList;
68 import org.eclipse.jgit.util.RefMap;
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83 public class DfsReftableDatabase extends DfsRefDatabase {
84 private final ReentrantLock lock = new ReentrantLock(true);
85
86 private DfsReader ctx;
87
88 private ReftableStack tableStack;
89
90 private MergedReftable mergedTables;
91
92
93
94
95
96
97
98 protected DfsReftableDatabase(DfsRepository repo) {
99 super(repo);
100 }
101
102
103 @Override
104 public boolean hasVersioning() {
105 return true;
106 }
107
108
109 @Override
110 public boolean performsAtomicTransactions() {
111 return true;
112 }
113
114
115 @Override
116 public BatchRefUpdate newBatchUpdate() {
117 DfsObjDatabase odb = getRepository().getObjectDatabase();
118 return new ReftableBatchRefUpdate(this, odb);
119 }
120
121
122
123
124
125
126 public ReftableConfig getReftableConfig() {
127 return new ReftableConfig(getRepository().getConfig());
128 }
129
130
131
132
133
134
135 protected ReentrantLock getLock() {
136 return lock;
137 }
138
139
140
141
142
143
144
145
146 protected boolean compactDuringCommit() {
147 return true;
148 }
149
150
151
152
153
154
155
156
157 protected Reftable reader() throws IOException {
158 lock.lock();
159 try {
160 if (mergedTables == null) {
161 mergedTables = new MergedReftable(stack().readers());
162 }
163 return mergedTables;
164 } finally {
165 lock.unlock();
166 }
167 }
168
169
170
171
172
173
174
175
176 protected ReftableStack stack() throws IOException {
177 lock.lock();
178 try {
179 if (tableStack == null) {
180 DfsObjDatabase odb = getRepository().getObjectDatabase();
181 if (ctx == null) {
182 ctx = odb.newReader();
183 }
184 tableStack = ReftableStack.open(ctx,
185 Arrays.asList(odb.getReftables()));
186 }
187 return tableStack;
188 } finally {
189 lock.unlock();
190 }
191 }
192
193
194 @Override
195 public boolean isNameConflicting(String refName) throws IOException {
196 lock.lock();
197 try {
198 Reftable table = reader();
199
200
201 int lastSlash = refName.lastIndexOf('/');
202 while (0 < lastSlash) {
203 if (table.hasRef(refName.substring(0, lastSlash))) {
204 return true;
205 }
206 lastSlash = refName.lastIndexOf('/', lastSlash - 1);
207 }
208
209
210 return table.hasRefsWithPrefix(refName + '/');
211 } finally {
212 lock.unlock();
213 }
214 }
215
216
217 @Override
218 public Ref exactRef(String name) throws IOException {
219 lock.lock();
220 try {
221 Reftable table = reader();
222 Ref ref = table.exactRef(name);
223 if (ref != null && ref.isSymbolic()) {
224 return table.resolve(ref);
225 }
226 return ref;
227 } finally {
228 lock.unlock();
229 }
230 }
231
232
233 @Override
234 public Map<String, Ref> getRefs(String prefix) throws IOException {
235 RefList.Builder<Ref> all = new RefList.Builder<>();
236 lock.lock();
237 try {
238 Reftable table = reader();
239 try (RefCursor rc = ALL.equals(prefix) ? table.allRefs()
240 : (prefix.endsWith("/") ? table.seekRefsWithPrefix(prefix)
241 : table.seekRef(prefix))) {
242 while (rc.next()) {
243 Ref ref = table.resolve(rc.getRef());
244 if (ref != null && ref.getObjectId() != null) {
245 all.add(ref);
246 }
247 }
248 }
249 } finally {
250 lock.unlock();
251 }
252
253 RefList<Ref> none = RefList.emptyList();
254 return new RefMap(prefix, all.toRefList(), none, none);
255 }
256
257
258 @Override
259 public List<Ref> getRefsByPrefix(String prefix) throws IOException {
260 List<Ref> all = new ArrayList<>();
261 lock.lock();
262 try {
263 Reftable table = reader();
264 try (RefCursor rc = ALL.equals(prefix) ? table.allRefs()
265 : table.seekRefsWithPrefix(prefix)) {
266 while (rc.next()) {
267 Ref ref = table.resolve(rc.getRef());
268 if (ref != null && ref.getObjectId() != null) {
269 all.add(ref);
270 }
271 }
272 }
273 } finally {
274 lock.unlock();
275 }
276
277 return Collections.unmodifiableList(all);
278 }
279
280
281 @Override
282 public Set<Ref> getTipsWithSha1(ObjectId id) throws IOException {
283 if (!getReftableConfig().isIndexObjects()) {
284 return super.getTipsWithSha1(id);
285 }
286 lock.lock();
287 try {
288 RefCursor cursor = reader().byObjectId(id);
289 Set<Ref> refs = new HashSet<>();
290 while (cursor.next()) {
291 refs.add(cursor.getRef());
292 }
293 return refs;
294 } finally {
295 lock.unlock();
296 }
297 }
298
299
300 @Override
301 public Ref" href="../../../../../../org/eclipse/jgit/lib/Ref.html#Ref">Ref peel(Ref ref) throws IOException {
302 Ref oldLeaf = ref.getLeaf();
303 if (oldLeaf.isPeeled() || oldLeaf.getObjectId() == null) {
304 return ref;
305 }
306 return recreate(ref, doPeel(oldLeaf), hasVersioning());
307 }
308
309 @Override
310 boolean exists() throws IOException {
311 DfsObjDatabase odb = getRepository().getObjectDatabase();
312 return odb.getReftables().length > 0;
313 }
314
315 @Override
316 void clearCache() {
317 lock.lock();
318 try {
319 if (tableStack != null) {
320 tableStack.close();
321 tableStack = null;
322 }
323 if (ctx != null) {
324 ctx.close();
325 ctx = null;
326 }
327 mergedTables = null;
328 } finally {
329 lock.unlock();
330 }
331 }
332
333
334 @Override
335 protected boolean compareAndPut(Ref/../../../../org/eclipse/jgit/lib/Ref.html#Ref">Ref oldRef, @Nullable Ref newRef)
336 throws IOException {
337 ReceiveCommand cmd = toCommand(oldRef, newRef);
338 try (RevWalkvwalk/RevWalk.html#RevWalk">RevWalk rw = new RevWalk(getRepository())) {
339 rw.setRetainBody(false);
340 newBatchUpdate().setAllowNonFastForwards(true).addCommand(cmd)
341 .execute(rw, NullProgressMonitor.INSTANCE);
342 }
343 switch (cmd.getResult()) {
344 case OK:
345 return true;
346 case REJECTED_OTHER_REASON:
347 throw new IOException(cmd.getMessage());
348 case LOCK_FAILURE:
349 default:
350 return false;
351 }
352 }
353
354 private static ReceiveCommand toCommand(Refref="../../../../../../org/eclipse/jgit/lib/Ref.html#Ref">Ref oldRef, Ref newRef) {
355 ObjectId oldId = toId(oldRef);
356 ObjectId newId = toId(newRef);
357 String name = toName(oldRef, newRef);
358
359 if (oldRef != null && oldRef.isSymbolic()) {
360 if (newRef != null) {
361 if (newRef.isSymbolic()) {
362 return ReceiveCommand.link(oldRef.getTarget().getName(),
363 newRef.getTarget().getName(), name);
364 } else {
365 return ReceiveCommand.unlink(oldRef.getTarget().getName(),
366 newId, name);
367 }
368 } else {
369 return ReceiveCommand.unlink(oldRef.getTarget().getName(),
370 ObjectId.zeroId(), name);
371 }
372 }
373
374 if (newRef != null && newRef.isSymbolic()) {
375 if (oldRef != null) {
376 if (oldRef.isSymbolic()) {
377 return ReceiveCommand.link(oldRef.getTarget().getName(),
378 newRef.getTarget().getName(), name);
379 } else {
380 return ReceiveCommand.link(oldId,
381 newRef.getTarget().getName(), name);
382 }
383 } else {
384 return ReceiveCommand.link(ObjectId.zeroId(),
385 newRef.getTarget().getName(), name);
386 }
387 }
388
389 return new ReceiveCommand(oldId, newId, name);
390 }
391
392 private static ObjectId toId(Ref ref) {
393 if (ref != null) {
394 ObjectId id = ref.getObjectId();
395 if (id != null) {
396 return id;
397 }
398 }
399 return ObjectId.zeroId();
400 }
401
402 private static String toName(Refref="../../../../../../org/eclipse/jgit/lib/Ref.html#Ref">Ref oldRef, Ref newRef) {
403 return oldRef != null ? oldRef.getName() : newRef.getName();
404 }
405
406
407 @Override
408 protected boolean compareAndRemove(Ref oldRef) throws IOException {
409 return compareAndPut(oldRef, null);
410 }
411
412
413 @Override
414 protected RefCache scanAllRefs() throws IOException {
415 throw new UnsupportedOperationException();
416 }
417
418 @Override
419 void stored(Ref ref) {
420
421 }
422
423 @Override
424 void removed(String refName) {
425
426 }
427
428
429 @Override
430 protected void cachePeeledState(Refef="../../../../../../org/eclipse/jgit/lib/Ref.html#Ref">Ref oldLeaf, Ref newLeaf) {
431
432 }
433 }