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