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);
        }
      }
    }
  }
Example #2
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);
      }
    }
 private void markCommon(final RevObject obj) {
   obj.add(COMMON);
   if (obj instanceof RevCommit) ((RevCommit) obj).carry(COMMON);
 }
  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();
    }
  }