Use 'reused' bitmap to filter tip commit setup walk

When garbage collecting, we decide to reuse some bitmaps in older
history from the previous pack to save time.  The remainder of commit
selection only involves commits not covered by those bitmaps.

Currently we carry that out in two ways:

1. by building a bitmap representing the already-covered commits,
   for easy containment checks and AND-NOT-ing against
2. by marking the reused bitmap commits as uninteresting in the
   RevWalk that finds new commits

The mechanism in (2) is less efficient than (1): rw.next() will walk
back from reused bitmap commits to check whether the commit it is
about to emit is an ancestor of them, when using the bitmap from (1)
would let us perform the same check with a single contains() call.
Add a RevFilter teaching the RevWalk to perform that same check
directly using the bitmap from (1).

The next time the RevWalk is used, a different RevFilter is installed
so this does not break that.

A later commit will drop the markUninteresting calls.

No functional change intended except a possible speedup.

Change-Id: Ic375210fa69330948be488bf9dbbe4cb0d069ae6
This commit is contained in:
Jonathan Nieder 2015-11-03 11:15:36 -08:00
parent 99d4040094
commit 9d4e5216a6
1 changed files with 42 additions and 0 deletions

View File

@ -44,6 +44,7 @@
package org.eclipse.jgit.internal.storage.pack;
import static org.eclipse.jgit.internal.storage.file.PackBitmapIndex.FLAG_REUSE;
import static org.eclipse.jgit.revwalk.RevFlag.SEEN;
import java.io.IOException;
import java.util.ArrayList;
@ -72,6 +73,7 @@
import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.revwalk.RevObject;
import org.eclipse.jgit.revwalk.RevWalk;
import org.eclipse.jgit.revwalk.filter.RevFilter;
import org.eclipse.jgit.storage.pack.PackConfig;
import org.eclipse.jgit.util.BlockList;
import org.eclipse.jgit.util.SystemReader;
@ -312,6 +314,45 @@ private boolean isRecentCommit(RevCommit revCommit) {
return revCommit.getCommitTime() > inactiveBranchTimestamp;
}
/**
* A RevFilter that excludes the commits named in a bitmap from the walk.
* <p>
* If a commit is in {@code bitmap} then that commit is not emitted by the
* walk and its parents are marked as SEEN so the walk can skip them. The
* bitmaps passed in have the property that the parents of any commit in
* {@code bitmap} are also in {@code bitmap}, so marking the parents as
* SEEN speeds up the RevWalk by saving it from walking down blind alleys
* and does not change the commits emitted.
*/
private static class NotInBitmapFilter extends RevFilter {
private final BitmapBuilder bitmap;
NotInBitmapFilter(BitmapBuilder bitmap) {
this.bitmap = bitmap;
}
@Override
public final boolean include(RevWalk rw, RevCommit c) {
if (!bitmap.contains(c)) {
return true;
}
for (RevCommit p : c.getParents()) {
p.add(SEEN);
}
return false;
}
@Override
public final NotInBitmapFilter clone() {
throw new UnsupportedOperationException();
}
@Override
public final boolean requiresCommitBody() {
return false;
}
}
/**
* For each of the {@code want}s, which represent the tip commit of each
* branch, set up an initial {@link BitmapBuilder}. Reuse previously built
@ -380,6 +421,7 @@ private CommitSelectionHelper setupTipCommitBitmaps(RevWalk rw,
// Create a list of commits in reverse order (older to newer).
// For each branch that contains the commit, mark its parents as being
// in the bitmap.
rw.setRevFilter(new NotInBitmapFilter(reuse));
RevCommit[] commits = new RevCommit[expectedCommitCount];
int pos = commits.length;
RevCommit rc;