UploadPack: Avoid walking the entire project history

If the client presents a common commit on a side branch, and there is
a want for a disconnected branch UploadPack was walking back on the
entire history of the disconnected branch because it never would find
the common commit.

Limit our search back along any given want to be no earlier than the
oldest common commit received via a "have" line from our client.  This
prevents us from looking at all of the project history.

Bug: 301639
Change-Id: Iffaaa2250907150d6efa1cf2f2fcf59851d5267d
Signed-off-by: Shawn O. Pearce <spearce@spearce.org>
Signed-off-by: Chris Aniszczyk <caniszczyk@gmail.com>
This commit is contained in:
Shawn O. Pearce 2011-02-05 19:00:15 -08:00 committed by Chris Aniszczyk
parent 8949ea4789
commit d6b7139cd8
2 changed files with 50 additions and 3 deletions

View File

@ -63,7 +63,18 @@ public abstract class CommitTimeRevFilter extends RevFilter {
* @return a new filter to select commits on or before <code>ts</code>.
*/
public static final RevFilter before(final Date ts) {
return new Before(ts.getTime());
return before(ts.getTime());
}
/**
* Create a new filter to select commits before a given date/time.
*
* @param ts
* the point in time to cut on, in milliseconds
* @return a new filter to select commits on or before <code>ts</code>.
*/
public static final RevFilter before(final long ts) {
return new Before(ts);
}
/**
@ -74,7 +85,18 @@ public static final RevFilter before(final Date ts) {
* @return a new filter to select commits on or after <code>ts</code>.
*/
public static final RevFilter after(final Date ts) {
return new After(ts.getTime());
return after(ts.getTime());
}
/**
* Create a new filter to select commits after a given date/time.
*
* @param ts
* the point in time to cut on, in milliseconds.
* @return a new filter to select commits on or after <code>ts</code>.
*/
public static final RevFilter after(final long ts) {
return new After(ts);
}
/**
@ -86,7 +108,19 @@ public static final RevFilter after(final Date ts) {
* @return a new filter to select commits between the given date/times.
*/
public static final RevFilter between(final Date since, final Date until) {
return new Between(since.getTime(), until.getTime());
return between(since.getTime(), until.getTime());
}
/**
* Create a new filter to select commits after or equal a given date/time <code>since</code>
* and before or equal a given date/time <code>until</code>.
*
* @param since the point in time to cut on, in milliseconds.
* @param until the point in time to cut off, in millisconds.
* @return a new filter to select commits between the given date/times.
*/
public static final RevFilter between(final long since, final long until) {
return new Between(since, until);
}
final int when;

View File

@ -71,6 +71,7 @@
import org.eclipse.jgit.revwalk.RevObject;
import org.eclipse.jgit.revwalk.RevTag;
import org.eclipse.jgit.revwalk.RevWalk;
import org.eclipse.jgit.revwalk.filter.CommitTimeRevFilter;
import org.eclipse.jgit.storage.pack.PackConfig;
import org.eclipse.jgit.storage.pack.PackWriter;
import org.eclipse.jgit.transport.BasePackFetchConnection.MultiAck;
@ -153,6 +154,9 @@ public class UploadPack {
/** Objects on both sides, these don't have to be sent. */
private final List<RevObject> commonBase = new ArrayList<RevObject>();
/** Commit time of the oldest common commit, in seconds. */
private int oldestTime;
/** null if {@link #commonBase} should be examined again. */
private Boolean okToGiveUp;
@ -517,6 +521,13 @@ private ObjectId processHaveLines(List<ObjectId> peerHas, ObjectId last)
}
last = obj;
if (obj instanceof RevCommit) {
RevCommit c = (RevCommit) obj;
if (oldestTime == 0 || c.getCommitTime() < oldestTime)
oldestTime = c.getCommitTime();
}
if (obj.has(PEER_HAS))
continue;
@ -606,6 +617,8 @@ private boolean wantSatisfied(final RevObject want) throws IOException {
walk.resetRetain(SAVE);
walk.markStart((RevCommit) want);
if (oldestTime != 0)
walk.setRevFilter(CommitTimeRevFilter.after(oldestTime * 1000L));
for (;;) {
final RevCommit c = walk.next();
if (c == null)