private DhtRef resolve(DhtRef ref, int depth, RefList<DhtRef> loose) throws IOException { if (!ref.isSymbolic()) return ref; DhtRef dst = (DhtRef) 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 DhtSymbolicRef(ref.getName(), dst, ((DhtSymbolicRef) ref).getRefData()); }
void stored(String refName, RefData newData) { DhtRef ref = fromData(refName, newData); RefCache oldCache, newCache; do { oldCache = cache.get(); if (oldCache == null) return; RefList<DhtRef> ids = oldCache.ids.put(ref); RefList<DhtRef> sym = oldCache.sym; if (ref.isSymbolic()) { sym = sym.put(ref); } else { int p = sym.find(refName); if (0 <= p) sym = sym.remove(p); } newCache = new RefCache(ids, sym, oldCache.hints); } while (!cache.compareAndSet(oldCache, newCache)); }
@Override public DhtRefUpdate newUpdate(String refName, boolean detach) throws IOException { boolean detachingSymbolicRef = false; DhtRef ref = getOneRef(refName); if (ref == null) ref = new DhtObjectIdRef(refName, NONE); else detachingSymbolicRef = detach && ref.isSymbolic(); if (detachingSymbolicRef) { RefData src = ((DhtRef) ref.getLeaf()).getRefData(); RefData.Builder b = RefData.newBuilder(ref.getRefData()); b.clearSymref(); b.setTarget(src.getTarget()); ref = new DhtObjectIdRef(refName, b.build()); } RepositoryKey repo = repository.getRepositoryKey(); DhtRefUpdate update = new DhtRefUpdate(this, repo, db, ref); if (detachingSymbolicRef) update.setDetachingSymbolicRef(); return update; }
@Override public Map<String, Ref> getRefs(String prefix) throws IOException { RefCache curr = readRefs(); RefList<DhtRef> packed = RefList.emptyList(); RefList<DhtRef> loose = curr.ids; RefList.Builder<DhtRef> sym = new RefList.Builder<DhtRef>(curr.sym.size()); for (int idx = 0; idx < curr.sym.size(); idx++) { DhtRef 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()); }
private RefCache read() throws DhtException, TimeoutException { RefList.Builder<DhtRef> id = new RefList.Builder<DhtRef>(); RefList.Builder<DhtRef> sym = new RefList.Builder<DhtRef>(); ObjectIdSubclassMap<IdWithChunk> hints = new ObjectIdSubclassMap<IdWithChunk>(); for (Map.Entry<RefKey, RefData> e : scan()) { DhtRef ref = fromData(e.getKey().getName(), e.getValue()); if (ref.isSymbolic()) sym.add(ref); id.add(ref); if (ref.getObjectId() instanceof IdWithChunk && !hints.contains(ref.getObjectId())) hints.add((IdWithChunk) ref.getObjectId()); if (ref.getPeeledObjectId() instanceof IdWithChunk && !hints.contains(ref.getPeeledObjectId())) hints.add((IdWithChunk) ref.getPeeledObjectId()); } id.sort(); sym.sort(); return new RefCache(id.toRefList(), sym.toRefList(), hints); }