1
2
3
4
5
6
7
8
9
10
11 package org.eclipse.jgit.internal.storage.reftable;
12
13 import java.io.IOException;
14 import java.util.ArrayList;
15 import java.util.Collections;
16 import java.util.HashSet;
17 import java.util.List;
18 import java.util.Set;
19 import java.util.TreeSet;
20 import java.util.concurrent.locks.ReentrantLock;
21
22 import org.eclipse.jgit.annotations.Nullable;
23 import org.eclipse.jgit.lib.ObjectId;
24 import org.eclipse.jgit.lib.Ref;
25 import org.eclipse.jgit.lib.RefDatabase;
26 import org.eclipse.jgit.lib.ReflogReader;
27 import org.eclipse.jgit.transport.ReceiveCommand;
28
29
30
31
32
33
34
35 public abstract class ReftableDatabase {
36
37 private final ReentrantLock lock = new ReentrantLock(true);
38
39 private Reftable mergedTables;
40
41
42
43
44
45
46
47
48
49
50 protected abstract MergedReftable openMergedReftable() throws IOException;
51
52
53
54
55
56
57
58 public long nextUpdateIndex() throws IOException {
59 lock.lock();
60 try {
61 return reader().maxUpdateIndex() + 1;
62 } finally {
63 lock.unlock();
64 }
65 }
66
67
68
69
70
71
72
73
74 public ReflogReader getReflogReader(String refname) throws IOException {
75 lock.lock();
76 try {
77 return new ReftableReflogReader(lock, reader(), refname);
78 } finally {
79 lock.unlock();
80 }
81 }
82
83
84
85
86
87
88
89
90 public static ReceiveCommand toCommand(Refref="../../../../../../org/eclipse/jgit/lib/Ref.html#Ref">Ref oldRef, Ref newRef) {
91 ObjectId oldId = toId(oldRef);
92 ObjectId newId = toId(newRef);
93 String name = oldRef != null ? oldRef.getName() : newRef.getName();
94
95 if (oldRef != null && oldRef.isSymbolic()) {
96 if (newRef != null) {
97 if (newRef.isSymbolic()) {
98 return ReceiveCommand.link(oldRef.getTarget().getName(),
99 newRef.getTarget().getName(), name);
100 }
101
102
103 return ReceiveCommand.unlink(oldRef.getTarget().getName(),
104 newId, name);
105 }
106 return ReceiveCommand.unlink(oldRef.getTarget().getName(),
107 ObjectId.zeroId(), name);
108 }
109
110 if (newRef != null && newRef.isSymbolic()) {
111 if (oldRef != null) {
112 if (oldRef.isSymbolic()) {
113 return ReceiveCommand.link(oldRef.getTarget().getName(),
114 newRef.getTarget().getName(), name);
115 }
116 return ReceiveCommand.link(oldId,
117 newRef.getTarget().getName(), name);
118 }
119 return ReceiveCommand.link(ObjectId.zeroId(),
120 newRef.getTarget().getName(), name);
121 }
122
123 return new ReceiveCommand(oldId, newId, name);
124 }
125
126 private static ObjectId toId(Ref ref) {
127 if (ref != null) {
128 ObjectId id = ref.getObjectId();
129 if (id != null) {
130 return id;
131 }
132 }
133 return ObjectId.zeroId();
134 }
135
136
137
138
139
140 public ReentrantLock getLock() {
141 return lock;
142 }
143
144
145
146
147
148
149
150 private Reftable reader() throws IOException {
151 if (!lock.isLocked()) {
152 throw new IllegalStateException(
153 "must hold lock to access merged table");
154 }
155 if (mergedTables == null) {
156 mergedTables = openMergedReftable();
157 }
158 return mergedTables;
159 }
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174 public boolean isNameConflicting(String refName, TreeSet<String> added,
175 Set<String> deleted) throws IOException {
176 lock.lock();
177 try {
178 Reftable table = reader();
179
180
181 int lastSlash = refName.lastIndexOf('/');
182 while (0 < lastSlash) {
183 String prefix = refName.substring(0, lastSlash);
184 if (!deleted.contains(prefix)
185 && (table.hasRef(prefix) || added.contains(prefix))) {
186 return true;
187 }
188 lastSlash = refName.lastIndexOf('/', lastSlash - 1);
189 }
190
191
192 String prefix = refName + '/';
193 RefCursor c = table.seekRefsWithPrefix(prefix);
194 while (c.next()) {
195 if (!deleted.contains(c.getRef().getName())) {
196 return true;
197 }
198 }
199
200 String it = added.ceiling(refName + '/');
201 if (it != null && it.startsWith(prefix)) {
202 return true;
203 }
204 return false;
205 } finally {
206 lock.unlock();
207 }
208 }
209
210
211
212
213
214
215
216
217
218
219
220
221
222 @Nullable
223 public Ref exactRef(String name) throws IOException {
224 lock.lock();
225 try {
226 Reftable table = reader();
227 Ref ref = table.exactRef(name);
228 if (ref != null && ref.isSymbolic()) {
229 return table.resolve(ref);
230 }
231 return ref;
232 } finally {
233 lock.unlock();
234 }
235 }
236
237
238
239
240
241
242
243
244
245
246
247 public List<Ref> getRefsByPrefix(String prefix) throws IOException {
248 List<Ref> all = new ArrayList<>();
249 lock.lock();
250 try {
251 Reftable table = reader();
252 try (RefCursor rc = RefDatabase.ALL.equals(prefix) ? table.allRefs()
253 : table.seekRefsWithPrefix(prefix)) {
254 while (rc.next()) {
255 Ref ref = table.resolve(rc.getRef());
256 if (ref != null && ref.getObjectId() != null) {
257 all.add(ref);
258 }
259 }
260 }
261 } finally {
262 lock.unlock();
263 }
264
265 return Collections.unmodifiableList(all);
266 }
267
268
269
270
271
272 public boolean hasFastTipsWithSha1() throws IOException {
273 lock.lock();
274 try {
275 return reader().hasObjectMap();
276 } finally {
277 lock.unlock();
278 }
279 }
280
281
282
283
284
285
286
287
288
289
290
291
292 public Set<Ref> getTipsWithSha1(ObjectId id) throws IOException {
293 lock.lock();
294 try {
295 RefCursor cursor = reader().byObjectId(id);
296 Set<Ref> refs = new HashSet<>();
297 while (cursor.next()) {
298 refs.add(cursor.getRef());
299 }
300 return refs;
301 } finally {
302 lock.unlock();
303 }
304 }
305
306
307
308
309 public void clearCache() {
310 lock.lock();
311 try {
312 mergedTables = null;
313 } finally {
314 lock.unlock();
315 }
316 }
317 }