/** * Find a reference by name. * * @param name * full name of the reference. * @return the reference, if it exists, otherwise null. */ public Ref get(String name) { return ids.get(name); }
/** * Get a reference object by name. * * @param name * the name of the reference. * @return the reference object; null if it does not exist in this list. */ public final T get(String name) { int idx = find(name); return 0 <= idx ? get(idx) : null; }
private Ref resolveLoose(Ref l) { if (resolvedIdx < resolved.size()) { Ref r = resolved.get(resolvedIdx); int cmp = RefComparator.compareTo(l, r); if (cmp == 0) { resolvedIdx++; return r; } else if (cmp > 0) { // WTF, we have a symbolic entry but no match // in the loose collection. That's an error. throw new IllegalStateException(); } } return l; }
/** {@inheritDoc} */ @Override public Ref exactRef(String name) throws IOException { RefCache curr = read(); Ref ref = curr.ids.get(name); return ref != null ? resolve(ref, 0, curr.ids) : null; }
/** {@inheritDoc} */ @Override public Ref getRef(String needle) throws IOException { RefCache curr = read(); for (String prefix : SEARCH_PATH) { Ref ref = curr.ids.get(prefix + needle); if (ref != null) { ref = resolve(ref, 0, curr.ids); return ref; } } return null; }
private Ref readRef(String name, RefList<Ref> packed) throws IOException { final RefList<LooseRef> curList = looseRefs.get(); final int idx = curList.find(name); if (0 <= idx) { final LooseRef o = curList.get(idx); final LooseRef n = scanRef(o, name); if (n == null) { if (looseRefs.compareAndSet(curList, curList.remove(idx))) modCnt.incrementAndGet(); return packed.get(name); } if (o == n) return n; if (looseRefs.compareAndSet(curList, curList.set(idx, n))) modCnt.incrementAndGet(); return n; } final LooseRef n = scanRef(null, name); if (n == null) return packed.get(name); // check whether the found new ref is the an additional ref. These refs // should not go into looseRefs for (int i = 0; i < additionalRefsNames.length; i++) if (name.equals(additionalRefsNames[i])) return n; if (looseRefs.compareAndSet(curList, curList.add(idx, n))) modCnt.incrementAndGet(); return n; }
/** {@inheritDoc} */ @Override public boolean isNameConflicting(String refName) throws IOException { RefList<Ref> all = read().ids; // Cannot be nested within an existing reference. int lastSlash = refName.lastIndexOf('/'); while (0 < lastSlash) { String needle = refName.substring(0, lastSlash); if (all.contains(needle)) return true; lastSlash = refName.lastIndexOf('/', lastSlash - 1); } // Cannot be the container of an existing reference. String prefix = refName + '/'; int idx = -(all.find(prefix) + 1); if (idx < all.size() && all.get(idx).getName().startsWith(prefix)) return true; return false; }
/** {@inheritDoc} */ @Override public Ref remove(Object key) { String name = toRefName((String) key); Ref res = null; int idx; if (0 <= (idx = packed.find(name))) { res = packed.get(name); packed = packed.remove(idx); sizeIsValid = false; } if (0 <= (idx = loose.find(name))) { res = loose.get(name); loose = loose.remove(idx); sizeIsValid = false; } if (0 <= (idx = resolved.find(name))) { res = resolved.get(name); resolved = resolved.remove(idx); sizeIsValid = false; } return res; }
public Entry<String, Ref> peek() { if (packedIdx < packed.size() && looseIdx < loose.size()) { Ref p = packed.get(packedIdx); Ref l = loose.get(looseIdx); int cmp = RefComparator.compareTo(p, l); if (cmp < 0) { packedIdx++; return toEntry(p); } if (cmp == 0) packedIdx++; looseIdx++; return toEntry(resolveLoose(l)); } if (looseIdx < loose.size()) return toEntry(resolveLoose(loose.get(looseIdx++))); if (packedIdx < packed.size()) return toEntry(packed.get(packedIdx++)); return null; }
void scan(String prefix) { if (ALL.equals(prefix)) { scanOne(HEAD); scanTree(R_REFS, refsDir); // If any entries remain, they are deleted, drop them. if (newLoose == null && curIdx < curLoose.size()) newLoose = curLoose.copy(curIdx); } else if (prefix.startsWith(R_REFS) && prefix.endsWith("/")) { //$NON-NLS-1$ curIdx = -(curLoose.find(prefix) + 1); File dir = new File(refsDir, prefix.substring(R_REFS.length())); scanTree(prefix, dir); // Skip over entries still within the prefix; these have // been removed from the directory. while (curIdx < curLoose.size()) { if (!curLoose.get(curIdx).getName().startsWith(prefix)) break; if (newLoose == null) newLoose = curLoose.copy(curIdx); curIdx++; } // Keep any entries outside of the prefix space, we // do not know anything about their status. if (newLoose != null) { while (curIdx < curLoose.size()) newLoose.add(curLoose.get(curIdx++)); } } }
/** {@inheritDoc} */ @Override public boolean isNameConflicting(String name) throws IOException { RefList<Ref> packed = getPackedRefs(); RefList<LooseRef> loose = getLooseRefs(); // Cannot be nested within an existing reference. int lastSlash = name.lastIndexOf('/'); while (0 < lastSlash) { String needle = name.substring(0, lastSlash); if (loose.contains(needle) || packed.contains(needle)) return true; lastSlash = name.lastIndexOf('/', lastSlash - 1); } // Cannot be the container of an existing reference. String prefix = name + '/'; int idx; idx = -(packed.find(prefix) + 1); if (idx < packed.size() && packed.get(idx).getName().startsWith(prefix)) return true; idx = -(loose.find(prefix) + 1); if (idx < loose.size() && loose.get(idx).getName().startsWith(prefix)) return true; return false; }
/** {@inheritDoc} */ @Override public Ref exactRef(String name) throws IOException { if (!repo.isBare() && name.indexOf('/') < 0 && !HEAD.equals(name)) { // Pass through names like MERGE_HEAD, ORIG_HEAD, FETCH_HEAD. return bootstrap.exactRef(name); } else if (conflictsWithBootstrap(name)) { return null; } boolean partial = false; Ref src = bootstrap.exactRef(txnCommitted); Scanner.Result c = refs; if (c == null || !c.refTreeId.equals(idOf(src))) { c = Scanner.scanRefTree(repo, src, prefixOf(name), false); partial = true; } Ref r = c.all.get(name); if (r != null && r.isSymbolic()) { r = c.sym.get(name); if (partial && r.getObjectId() == null) { // Attempting exactRef("HEAD") with partial scan will leave // an unresolved symref as its target e.g. refs/heads/master // was not read by the partial scan. Scan everything instead. return getRefs(ALL).get(name); } } return r; }
private Ref resolve(Ref ref, int depth, RefList<Ref> loose) throws IOException { if (!ref.isSymbolic()) return ref; Ref dst = ref.getTarget(); if (MAX_SYMBOLIC_REF_DEPTH <= depth) return null; // claim it doesn't exist dst = loose.get(dst.getName()); if (dst == null) return ref; dst = resolve(dst, depth + 1, loose); if (dst == null) return null; return new SymbolicRef(ref.getName(), dst); }
/** {@inheritDoc} */ @Override public Ref put(String keyName, Ref value) { String name = toRefName(keyName); if (!name.equals(value.getName())) throw new IllegalArgumentException(); if (!resolved.isEmpty()) { // Collapse the resolved list into the loose list so we // can discard it and stop joining the two together. for (Ref ref : resolved) loose = loose.put(ref); resolved = RefList.emptyList(); } int idx = loose.find(name); if (0 <= idx) { Ref prior = loose.get(name); loose = loose.set(idx, value); return prior; } else { Ref prior = get(keyName); loose = loose.add(idx, value); sizeIsValid = false; return prior; } }
private static Ref resolve(Ref ref, int depth, RefList<Ref> refs) throws IOException { if (!ref.isSymbolic()) { return ref; } else if (MAX_SYMBOLIC_REF_DEPTH <= depth) { return null; } Ref r = refs.get(ref.getTarget().getName()); if (r == null) { return ref; } Ref dst = resolve(r, depth + 1, refs); if (dst == null) { return null; } return new SymbolicRef(ref.getName(), dst); }
private Ref resolve(final Ref ref, int depth, String prefix, RefList<LooseRef> loose, RefList<Ref> packed) throws IOException { if (ref.isSymbolic()) { Ref dst = ref.getTarget(); if (MAX_SYMBOLIC_REF_DEPTH <= depth) return null; // claim it doesn't exist // If the cached value can be assumed to be current due to a // recent scan of the loose directory, use it. if (loose != null && dst.getName().startsWith(prefix)) { int idx; if (0 <= (idx = loose.find(dst.getName()))) dst = loose.get(idx); else if (0 <= (idx = packed.find(dst.getName()))) dst = packed.get(idx); else return ref; } else { dst = readRef(dst.getName(), packed); if (dst == null) return ref; } dst = resolve(dst, depth + 1, prefix, loose, packed); if (dst == null) return null; return new SymbolicRef(ref.getName(), dst); } return ref; }
/** {@inheritDoc} */ @Override public Ref peel(Ref ref) throws IOException { final Ref leaf = ref.getLeaf(); if (leaf.isPeeled() || leaf.getObjectId() == null) return ref; ObjectIdRef newLeaf = doPeel(leaf); // Try to remember this peeling in the cache, so we don't have to do // it again in the future, but only if the reference is unchanged. if (leaf.getStorage().isLoose()) { RefList<LooseRef> curList = looseRefs.get(); int idx = curList.find(leaf.getName()); if (0 <= idx && curList.get(idx) == leaf) { LooseRef asPeeled = ((LooseRef) leaf).peel(newLeaf); RefList<LooseRef> newList = curList.set(idx, asPeeled); looseRefs.compareAndSet(curList, newList); } } return recreate(ref, newLeaf); }
/** {@inheritDoc} */ @Override public Ref peel(Ref ref) throws IOException { final Ref oldLeaf = ref.getLeaf(); if (oldLeaf.isPeeled() || oldLeaf.getObjectId() == null) return ref; Ref newLeaf = doPeel(oldLeaf); RefCache cur = read(); int idx = cur.ids.find(oldLeaf.getName()); if (0 <= idx && cur.ids.get(idx) == oldLeaf) { RefList<Ref> newList = cur.ids.set(idx, newLeaf); cache.compareAndSet(cur, new RefCache(newList, cur)); cachePeeledState(oldLeaf, newLeaf); } return recreate(ref, newLeaf); }
/** {@inheritDoc} */ @Override public Map<String, Ref> getRefs(String prefix) throws IOException { RefCache curr = read(); RefList<Ref> packed = RefList.emptyList(); RefList<Ref> loose = curr.ids; RefList.Builder<Ref> sym = new RefList.Builder<>(curr.sym.size()); for (int idx = 0; idx < curr.sym.size(); idx++) { Ref ref = curr.sym.get(idx); String name = ref.getName(); ref = resolve(ref, 0, loose); if (ref != null && ref.getObjectId() != null) { sym.add(ref); } else { // A broken symbolic reference, we have to drop it from the // collections the client is about to receive. Should be a // rare occurrence so pay a copy penalty. int toRemove = loose.find(name); if (0 <= toRemove) loose = loose.remove(toRemove); } } return new RefMap(prefix, packed, loose, sym.toRefList()); }