Пример #1
0
  private void negotiateBegin() throws IOException {
    walk.resetRetain(REACHABLE, ADVERTISED);
    walk.markStart(reachableCommits);
    walk.sort(RevSort.COMMIT_TIME_DESC);
    walk.setRevFilter(
        new RevFilter() {
          @Override
          public RevFilter clone() {
            return this;
          }

          @Override
          public boolean include(final RevWalk walker, final RevCommit c) {
            final boolean remoteKnowsIsCommon = c.has(COMMON);
            if (c.has(ADVERTISED)) {
              // Remote advertised this, and we have it, hence common.
              // Whether or not the remote knows that fact is tested
              // before we added the flag. If the remote doesn't know
              // we have to still send them this object.
              //
              c.add(COMMON);
            }
            return !remoteKnowsIsCommon;
          }
        });
  }
Пример #2
0
  private Map<String, Ref> computeNewRefs() throws IOException {
    final RevWalk rw = new RevWalk(db);
    final Map<String, Ref> refs = new HashMap<String, Ref>();
    final BufferedReader br =
        new BufferedReader(new InputStreamReader(new FileInputStream(refList), Constants.CHARSET));
    try {
      String line;
      while ((line = br.readLine()) != null) {
        final String[] parts = line.split("[ \t]{1,}");
        final ObjectId origId = ObjectId.fromString(parts[0]);
        final String type = parts[1];
        final String name = parts[2];

        ObjectId id = rewrites.get(origId);
        if (id == null) id = origId;
        try {
          rw.parseAny(id);
        } catch (MissingObjectException mue) {
          if (!Constants.TYPE_COMMIT.equals(type)) {
            System.err.println("skipping " + type + " " + name);
            continue;
          }
          throw new MissingObjectException(id, type);
        }
        refs.put(name, new Ref(Ref.Storage.PACKED, name, id));
      }
    } finally {
      br.close();
    }
    return refs;
  }
Пример #3
0
 private void markAdvertised(final AnyObjectId id) {
   try {
     walk.parseAny(id).add(ADVERTISED);
   } catch (IOException readError) {
     // We probably just do not have this object locally.
   }
 }
Пример #4
0
  private boolean sendWants(final Collection<Ref> want) throws IOException {
    boolean first = true;
    for (final Ref r : want) {
      try {
        if (walk.parseAny(r.getObjectId()).has(REACHABLE)) {
          // We already have this object. Asking for it is
          // not a very good idea.
          //
          continue;
        }
      } catch (IOException err) {
        // Its OK, we don't have it, but we want to fix that
        // by fetching the object from the other side.
      }

      final StringBuilder line = new StringBuilder(46);
      line.append("want ");
      line.append(r.getObjectId().name());
      if (first) {
        line.append(enableCapabilities());
        first = false;
      }
      line.append('\n');
      pckOut.writeString(line.toString());
    }
    pckOut.end();
    outNeedsEnd = false;
    return !first;
  }
Пример #5
0
  protected void doFetch(
      final ProgressMonitor monitor, final Collection<Ref> want, final Set<ObjectId> have)
      throws TransportException {
    try {
      markRefsAdvertised();
      markReachable(have, maxTimeWanted(want));

      if (sendWants(want)) {
        negotiate(monitor);

        walk.dispose();
        reachableCommits = null;

        receivePack(monitor);
      }
    } catch (CancelledException ce) {
      close();
      return; // Caller should test (or just know) this themselves.
    } catch (IOException err) {
      close();
      throw new TransportException(err.getMessage(), err);
    } catch (RuntimeException err) {
      close();
      throw new TransportException(err.getMessage(), err);
    }
  }
Пример #6
0
    private void verifyPrerequisites() throws TransportException {
      if (prereqs.isEmpty()) return;

      final RevWalk rw = new RevWalk(local);
      final RevFlag PREREQ = rw.newFlag("PREREQ");
      final RevFlag SEEN = rw.newFlag("SEEN");

      final List<ObjectId> missing = new ArrayList<ObjectId>();
      final List<RevObject> commits = new ArrayList<RevObject>();
      for (final ObjectId p : prereqs) {
        try {
          final RevCommit c = rw.parseCommit(p);
          if (!c.has(PREREQ)) {
            c.add(PREREQ);
            commits.add(c);
          }
        } catch (MissingObjectException notFound) {
          missing.add(p);
        } catch (IOException err) {
          throw new TransportException(uri, "Cannot read commit " + p.name(), err);
        }
      }
      if (!missing.isEmpty()) throw new MissingBundlePrerequisiteException(uri, missing);

      for (final Ref r : local.getAllRefs().values()) {
        try {
          rw.markStart(rw.parseCommit(r.getObjectId()));
        } catch (IOException readError) {
          // If we cannot read the value of the ref skip it.
        }
      }

      int remaining = commits.size();
      try {
        RevCommit c;
        while ((c = rw.next()) != null) {
          if (c.has(PREREQ)) {
            c.add(SEEN);
            if (--remaining == 0) break;
          }
        }
      } catch (IOException err) {
        throw new TransportException(uri, "Cannot read object", err);
      }

      if (remaining > 0) {
        for (final RevObject o : commits) {
          if (!o.has(SEEN)) missing.add(o);
        }
        throw new MissingBundlePrerequisiteException(uri, missing);
      }
    }
Пример #7
0
 private int maxTimeWanted(final Collection<Ref> wants) {
   int maxTime = 0;
   for (final Ref r : wants) {
     try {
       final RevObject obj = walk.parseAny(r.getObjectId());
       if (obj instanceof RevCommit) {
         final int cTime = ((RevCommit) obj).getCommitTime();
         if (maxTime < cTime) maxTime = cTime;
       }
     } catch (IOException error) {
       // We don't have it, but we want to fetch (thus fixing error).
     }
   }
   return maxTime;
 }
Пример #8
0
  BasePackFetchConnection(final PackTransport packTransport) {
    super(packTransport);
    includeTags = packTransport.getTagOpt() != TagOpt.NO_TAGS;
    thinPack = packTransport.isFetchThin();

    walk = new RevWalk(local);
    reachableCommits = new RevCommitList<RevCommit>();
    REACHABLE = walk.newFlag("REACHABLE");
    COMMON = walk.newFlag("COMMON");
    ADVERTISED = walk.newFlag("ADVERTISED");

    walk.carry(COMMON);
    walk.carry(REACHABLE);
    walk.carry(ADVERTISED);
  }
Пример #9
0
  private void markReachable(final Set<ObjectId> have, final int maxTime) throws IOException {
    for (final Ref r : local.getAllRefs().values()) {
      try {
        final RevCommit o = walk.parseCommit(r.getObjectId());
        o.add(REACHABLE);
        reachableCommits.add(o);
      } catch (IOException readError) {
        // If we cannot read the value of the ref skip it.
      }
    }

    for (final ObjectId id : have) {
      try {
        final RevCommit o = walk.parseCommit(id);
        o.add(REACHABLE);
        reachableCommits.add(o);
      } catch (IOException readError) {
        // If we cannot read the value of the ref skip it.
      }
    }

    if (maxTime > 0) {
      // Mark reachable commits until we reach maxTime. These may
      // wind up later matching up against things we want and we
      // can avoid asking for something we already happen to have.
      //
      final Date maxWhen = new Date(maxTime * 1000L);
      walk.sort(RevSort.COMMIT_TIME_DESC);
      walk.markStart(reachableCommits);
      walk.setRevFilter(CommitTimeRevFilter.after(maxWhen));
      for (; ; ) {
        final RevCommit c = walk.next();
        if (c == null) break;
        if (c.has(ADVERTISED) && !c.has(COMMON)) {
          // This is actually going to be a common commit, but
          // our peer doesn't know that fact yet.
          //
          c.add(COMMON);
          c.carry(COMMON);
          reachableCommits.add(c);
        }
      }
    }
  }
Пример #10
0
  private void negotiate(final ProgressMonitor monitor) throws IOException, CancelledException {
    final MutableObjectId ackId = new MutableObjectId();
    int resultsPending = 0;
    int havesSent = 0;
    int havesSinceLastContinue = 0;
    boolean receivedContinue = false;
    boolean receivedAck = false;
    boolean sendHaves = true;

    negotiateBegin();
    while (sendHaves) {
      final RevCommit c = walk.next();
      if (c == null) break;

      pckOut.writeString("have " + c.getId().name() + "\n");
      havesSent++;
      havesSinceLastContinue++;

      if ((31 & havesSent) != 0) {
        // We group the have lines into blocks of 32, each marked
        // with a flush (aka end). This one is within a block so
        // continue with another have line.
        //
        continue;
      }

      if (monitor.isCancelled()) throw new CancelledException();

      pckOut.end();
      resultsPending++; // Each end will cause a result to come back.

      if (havesSent == 32) {
        // On the first block we race ahead and try to send
        // more of the second block while waiting for the
        // remote to respond to our first block request.
        // This keeps us one block ahead of the peer.
        //
        continue;
      }

      while (resultsPending > 0) {
        final PacketLineIn.AckNackResult anr;

        anr = pckIn.readACK(ackId);
        resultsPending--;
        if (anr == PacketLineIn.AckNackResult.NAK) {
          // More have lines are necessary to compute the
          // pack on the remote side. Keep doing that.
          //
          break;
        }

        if (anr == PacketLineIn.AckNackResult.ACK) {
          // The remote side is happy and knows exactly what
          // to send us. There is no further negotiation and
          // we can break out immediately.
          //
          multiAck = false;
          resultsPending = 0;
          receivedAck = true;
          sendHaves = false;
          break;
        }

        if (anr == PacketLineIn.AckNackResult.ACK_CONTINUE) {
          // The server knows this commit (ackId). We don't
          // need to send any further along its ancestry, but
          // we need to continue to talk about other parts of
          // our local history.
          //
          markCommon(walk.parseAny(ackId));
          receivedAck = true;
          receivedContinue = true;
          havesSinceLastContinue = 0;
        }

        if (monitor.isCancelled()) throw new CancelledException();
      }

      if (receivedContinue && havesSinceLastContinue > MAX_HAVES) {
        // Our history must be really different from the remote's.
        // We just sent a whole slew of have lines, and it did not
        // recognize any of them. Avoid sending our entire history
        // to them by giving up early.
        //
        break;
      }
    }

    // Tell the remote side we have run out of things to talk about.
    //
    if (monitor.isCancelled()) throw new CancelledException();
    pckOut.writeString("done\n");
    pckOut.flush();

    if (!receivedAck) {
      // Apparently if we have never received an ACK earlier
      // there is one more result expected from the done we
      // just sent to the remote.
      //
      multiAck = false;
      resultsPending++;
    }

    while (resultsPending > 0 || multiAck) {
      final PacketLineIn.AckNackResult anr;

      anr = pckIn.readACK(ackId);
      resultsPending--;

      if (anr == PacketLineIn.AckNackResult.ACK) break; // commit negotiation is finished.

      if (anr == PacketLineIn.AckNackResult.ACK_CONTINUE) {
        // There must be a normal ACK following this.
        //
        multiAck = true;
      }

      if (monitor.isCancelled()) throw new CancelledException();
    }
  }
Пример #11
0
  private void recreateCommitGraph() throws IOException {
    final RevWalk rw = new RevWalk(db);
    final Map<ObjectId, ToRewrite> toRewrite = new HashMap<ObjectId, ToRewrite>();
    List<ToRewrite> queue = new ArrayList<ToRewrite>();
    final BufferedReader br =
        new BufferedReader(new InputStreamReader(new FileInputStream(graph), Constants.CHARSET));
    try {
      String line;
      while ((line = br.readLine()) != null) {
        final String[] parts = line.split("[ \t]{1,}");
        final ObjectId oldId = ObjectId.fromString(parts[0]);
        try {
          rw.parseCommit(oldId);
          // We have it already. Don't rewrite it.
          continue;
        } catch (MissingObjectException mue) {
          // Fall through and rewrite it.
        }

        final long time = Long.parseLong(parts[1]) * 1000L;
        final ObjectId[] parents = new ObjectId[parts.length - 2];
        for (int i = 0; i < parents.length; i++) {
          parents[i] = ObjectId.fromString(parts[2 + i]);
        }

        final ToRewrite t = new ToRewrite(oldId, time, parents);
        toRewrite.put(oldId, t);
        queue.add(t);
      }
    } finally {
      br.close();
    }

    pm.beginTask("Rewriting commits", queue.size());
    final ObjectWriter ow = new ObjectWriter(db);
    final ObjectId emptyTree = ow.writeTree(new Tree(db));
    final PersonIdent me =
        new PersonIdent("jgit rebuild-commitgraph", "rebuild-commitgraph@localhost");
    while (!queue.isEmpty()) {
      final ListIterator<ToRewrite> itr = queue.listIterator(queue.size());
      queue = new ArrayList<ToRewrite>();
      REWRITE:
      while (itr.hasPrevious()) {
        final ToRewrite t = itr.previous();
        final ObjectId[] newParents = new ObjectId[t.oldParents.length];
        for (int k = 0; k < t.oldParents.length; k++) {
          final ToRewrite p = toRewrite.get(t.oldParents[k]);
          if (p != null) {
            if (p.newId == null) {
              // Must defer until after the parent is rewritten.
              queue.add(t);
              continue REWRITE;
            } else {
              newParents[k] = p.newId;
            }
          } else {
            // We have the old parent object. Use it.
            //
            newParents[k] = t.oldParents[k];
          }
        }

        final Commit newc = new Commit(db);
        newc.setTreeId(emptyTree);
        newc.setAuthor(new PersonIdent(me, new Date(t.commitTime)));
        newc.setCommitter(newc.getAuthor());
        newc.setParentIds(newParents);
        newc.setMessage("ORIGINAL " + t.oldId.name() + "\n");
        t.newId = ow.writeCommit(newc);
        rewrites.put(t.oldId, t.newId);
        pm.update(1);
      }
    }
    pm.endTask();
  }