Beispiel #1
0
  @Override
  public Map<String, Ref> getRefs(String prefix) throws IOException {
    final RefList<LooseRef> oldLoose = looseRefs.get();
    LooseScanner scan = new LooseScanner(oldLoose);
    scan.scan(prefix);
    final RefList<Ref> packed = getPackedRefs();

    RefList<LooseRef> loose;
    if (scan.newLoose != null) {
      scan.newLoose.sort();
      loose = scan.newLoose.toRefList();
      if (looseRefs.compareAndSet(oldLoose, loose)) modCnt.incrementAndGet();
    } else loose = oldLoose;
    fireRefsChanged();

    RefList.Builder<Ref> symbolic = scan.symbolic;
    for (int idx = 0; idx < symbolic.size(); ) {
      final Ref symbolicRef = symbolic.get(idx);
      final Ref resolvedRef = resolve(symbolicRef, 0, prefix, loose, packed);
      if (resolvedRef != null && resolvedRef.getObjectId() != null) {
        symbolic.set(idx, resolvedRef);
        idx++;
      } 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.
        symbolic.remove(idx);
        final int toRemove = loose.find(symbolicRef.getName());
        if (0 <= toRemove) loose = loose.remove(toRemove);
      }
    }
    symbolic.sort();

    return new RefMap(prefix, packed, upcast(loose), symbolic.toRefList());
  }
Beispiel #2
0
  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;
  }
Beispiel #3
0
  @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;
  }
Beispiel #4
0
 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();
 }
Beispiel #5
0
 /**
  * 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);
 }
Beispiel #6
0
    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++));
        }
      }
    }
Beispiel #7
0
  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;
  }
Beispiel #8
0
  /**
   * Adds a set of refs to the set of packed-refs. Only non-symbolic refs are added. If a ref with
   * the given name already existed in packed-refs it is updated with the new value. Each loose ref
   * which was added to the packed-ref file is deleted. If a given ref can't be locked it will not
   * be added to the pack file.
   *
   * @param refs the refs to be added. Must be fully qualified.
   * @throws IOException
   */
  public void pack(List<String> refs) throws IOException {
    if (refs.size() == 0) return;
    FS fs = parent.getFS();

    // Lock the packed refs file and read the content
    LockFile lck = new LockFile(packedRefsFile);
    if (!lck.lock())
      throw new IOException(MessageFormat.format(JGitText.get().cannotLock, packedRefsFile));

    try {
      final PackedRefList packed = getPackedRefs();
      RefList<Ref> cur = readPackedRefs();

      // Iterate over all refs to be packed
      for (String refName : refs) {
        Ref ref = readRef(refName, cur);
        if (ref.isSymbolic()) continue; // can't pack symbolic refs
        // Add/Update it to packed-refs
        int idx = cur.find(refName);
        if (idx >= 0) cur = cur.set(idx, peeledPackedRef(ref));
        else cur = cur.add(idx, peeledPackedRef(ref));
      }

      // The new content for packed-refs is collected. Persist it.
      commitPackedRefs(lck, cur, packed);

      // Now delete the loose refs which are now packed
      for (String refName : refs) {
        // Lock the loose ref
        File refFile = fileFor(refName);
        if (!fs.exists(refFile)) continue;
        LockFile rLck = new LockFile(refFile);
        if (!rLck.lock()) continue;
        try {
          LooseRef currentLooseRef = scanRef(null, refName);
          if (currentLooseRef == null || currentLooseRef.isSymbolic()) continue;
          Ref packedRef = cur.get(refName);
          ObjectId clr_oid = currentLooseRef.getObjectId();
          if (clr_oid != null && clr_oid.equals(packedRef.getObjectId())) {
            RefList<LooseRef> curLoose, newLoose;
            do {
              curLoose = looseRefs.get();
              int idx = curLoose.find(refName);
              if (idx < 0) break;
              newLoose = curLoose.remove(idx);
            } while (!looseRefs.compareAndSet(curLoose, newLoose));
            int levels = levelsIn(refName) - 2;
            delete(refFile, levels, rLck);
          }
        } finally {
          rLck.unlock();
        }
      }
      // Don't fire refsChanged. The refs have not change, only their
      // storage.
    } finally {
      lck.unlock();
    }
  }
  @Override
  public boolean isNameConflicting(String refName) throws IOException {
    RefList<DhtRef> all = readRefs().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;
  }
Beispiel #10
0
  RefDirectory(final FileRepository db) {
    final FS fs = db.getFS();
    parent = db;
    gitDir = db.getDirectory();
    logWriter = new ReflogWriter(db);
    refsDir = fs.resolve(gitDir, R_REFS);
    packedRefsFile = fs.resolve(gitDir, PACKED_REFS);

    looseRefs.set(RefList.<LooseRef>emptyList());
    packedRefs.set(PackedRefList.NO_PACKED_REFS);
  }
  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));
  }
Beispiel #12
0
  @Override
  public Ref peel(final 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);
  }
Beispiel #13
0
  void delete(RefDirectoryUpdate update) throws IOException {
    Ref dst = update.getRef();
    String name = dst.getName();

    // Write the packed-refs file using an atomic update. We might
    // wind up reading it twice, before and after the lock, to ensure
    // we don't miss an edit made externally.
    final PackedRefList packed = getPackedRefs();
    if (packed.contains(name)) {
      LockFile lck = new LockFile(packedRefsFile);
      if (!lck.lock()) throw new LockFailedException(packedRefsFile);
      try {
        PackedRefList cur = readPackedRefs();
        int idx = cur.find(name);
        if (0 <= idx) commitPackedRefs(lck, cur.remove(idx), packed);
      } finally {
        lck.unlock();
      }
    }

    RefList<LooseRef> curLoose, newLoose;
    do {
      curLoose = looseRefs.get();
      int idx = curLoose.find(name);
      if (idx < 0) break;
      newLoose = curLoose.remove(idx);
    } while (!looseRefs.compareAndSet(curLoose, newLoose));

    int levels = levelsIn(name) - 2;
    delete(logWriter.logFor(name), levels);
    if (dst.getStorage().isLoose()) {
      update.unlock();
      delete(fileFor(name), levels);
    }

    modCnt.incrementAndGet();
    fireRefsChanged();
  }
Beispiel #14
0
  private static class PackedRefList extends RefList<Ref> {
    static final PackedRefList NO_PACKED_REFS =
        new PackedRefList(RefList.emptyList(), FileSnapshot.MISSING_FILE, ObjectId.zeroId());

    final FileSnapshot snapshot;

    final ObjectId id;

    PackedRefList(RefList<Ref> src, FileSnapshot s, ObjectId i) {
      super(src);
      snapshot = s;
      id = i;
    }
  }
Beispiel #15
0
  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);
  }
  @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());
  }
Beispiel #17
0
    /**
     * 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 removed(String refName) {
    RefCache oldCache, newCache;
    do {
      oldCache = cache.get();
      if (oldCache == null) return;

      int p;

      RefList<DhtRef> ids = oldCache.ids;
      p = ids.find(refName);
      if (0 <= p) ids = ids.remove(p);

      RefList<DhtRef> sym = oldCache.sym;
      p = sym.find(refName);
      if (0 <= p) sym = sym.remove(p);

      newCache = new RefCache(ids, sym, oldCache.hints);
    } while (!cache.compareAndSet(oldCache, newCache));
  }
Beispiel #19
0
    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) {
            // Reference is not loose anymore, its been deleted.
            // Skip the name in the new result list.
            if (newLoose == null) newLoose = curLoose.copy(curIdx);
            curIdx++;
            cur = null;
            continue;
          }

          if (cmp > 0) // Newly discovered loose reference.
          cur = null;
          break;
        } while (curIdx < curLoose.size());
      } else cur = null; // Newly discovered loose reference.

      LooseRef n;
      try {
        n = scanRef(cur, name);
      } catch (IOException notValid) {
        n = null;
      }

      if (n != null) {
        if (cur != n && newLoose == null) newLoose = curLoose.copy(curIdx);
        if (newLoose != null) newLoose.add(n);
        if (n.isSymbolic()) symbolic.add(n);
      } else if (cur != null) {
        // Tragically, this file is no longer a loose reference.
        // Kill our cached entry of it.
        if (newLoose == null) newLoose = curLoose.copy(curIdx);
      }

      if (cur != null) curIdx++;
    }
Beispiel #20
0
 private void clearReferences() {
   looseRefs.set(RefList.<LooseRef>emptyList());
   packedRefs.set(PackedRefList.NO_PACKED_REFS);
 }
Beispiel #21
0
 /**
  * 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);
 }
Beispiel #22
0
 /** @return number of references in this cache. */
 public int size() {
   return ids.size();
 }