/** {@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 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 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 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; }
/** * Store a reference, adding or replacing as necessary. * <p> * This list instance is not affected by the store. The correct position is * determined, and the item is added if missing, or replaced if existing. * Because this method copies the entire list, it runs in O(N + log N) time. * * @param ref * the reference to store. * @return copy of this list, after performing the addition or replacement. */ public final RefList<T> put(T ref) { int idx = find(ref.getName()); if (0 <= idx) return set(idx, ref); return add(idx, ref); }
/** {@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()); }
/** * Obtain a modified copy of the cache with a ref stored. * <p> * This cache instance is not modified by this method. * * @param ref * reference to add or replace. * @return a copy of this cache, with the reference added or replaced. */ public RefCache put(Ref ref) { RefList<Ref> newIds = this.ids.put(ref); RefList<Ref> newSym = this.sym; if (ref.isSymbolic()) { newSym = newSym.put(ref); } else { int p = newSym.find(ref.getName()); if (0 <= p) newSym = newSym.remove(p); } return new RefCache(newIds, newSym); }
/** * Obtain a modified copy of the cache with the ref removed. * <p> * This cache instance is not modified by this method. * * @param refName * reference to remove, if it exists. * @return a copy of this cache, with the reference removed. */ public RefCache remove(String refName) { RefList<Ref> newIds = this.ids; int p = newIds.find(refName); if (0 <= p) newIds = newIds.remove(p); RefList<Ref> newSym = this.sym; p = newSym.find(refName); if (0 <= p) newSym = newSym.remove(p); return new RefCache(newIds, newSym); } }
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++)); } } }
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; }
private void scanOne(String name) { LooseRef cur; if (curIdx < curLoose.size()) { do { cur = curLoose.get(curIdx); int cmp = RefComparator.compareTo(cur, name); if (cmp < 0) { newLoose = curLoose.copy(curIdx); curIdx++; cur = null; cur = null; break; } while (curIdx < curLoose.size()); } else newLoose = curLoose.copy(curIdx); if (newLoose != null) newLoose.add(n); newLoose = curLoose.copy(curIdx);
/** * Remove an item at a specific index. * <p> * This list instance is not affected by the addition. Because this method * copies the entire list, it runs in O(N) time. * * @param idx * position to remove the item from. * @return copy of this list, after making removing the item at {@code idx}. */ public final RefList<T> remove(int idx) { if (cnt == 1) return emptyList(); Ref[] newList = new Ref[cnt - 1]; if (0 < idx) System.arraycopy(list, 0, newList, 0, idx); if (idx + 1 < cnt) System.arraycopy(list, idx + 1, newList, idx, cnt - (idx + 1)); return new RefList<>(newList, cnt - 1); }
/** * 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); }
/** @return number of references in this cache. */ public int size() { return ids.size(); }
/** @return an unmodifiable list using this collection's backing array. */ public RefList<T> toRefList() { return new RefList<>(list, size); }
private void putLooseRef(LooseRef ref) { RefList<LooseRef> cList, nList; do { cList = looseRefs.get(); nList = cList.put(ref); } while (!looseRefs.compareAndSet(cList, nList)); modCnt.incrementAndGet(); fireRefsChanged(); }
/** * Determine if a reference is present. * * @param name * name of the reference to find. * @return true if the reference is present; false if it is not. */ public final boolean contains(String name) { return 0 <= find(name); }