diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/PackWriterBitmapPreparer.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/PackWriterBitmapPreparer.java index d7d45e41f..e250289bd 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/PackWriterBitmapPreparer.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/PackWriterBitmapPreparer.java @@ -181,8 +181,14 @@ Collection selectCommits(int expectedCommitCount) BitmapBuilder bitmap = entry.getBuilder(); int cardinality = bitmap.cardinality(); - List> running = new ArrayList< - List>(); + // Within this branch, keep ordered lists of commits representing + // chains in its history, where each chain is a "sub-branch". + // Ordering commits by these chains makes for fewer differences + // between consecutive selected commits, which in turn provides + // better compression/on the run-length encoding of the XORs between + // them. + List> chains = + new ArrayList>(); // Mark the current branch as inactive if its tip commit isn't // recent and there are an excessive number of branches, to @@ -195,7 +201,8 @@ Collection selectCommits(int expectedCommitCount) } // Insert bitmaps at the offsets suggested by the - // nextSelectionDistance() heuristic. + // nextSelectionDistance() heuristic. Only reuse bitmaps created + // for more distant commits. int index = -1; int nextIn = nextSpan(cardinality); int nextFlg = nextIn == distantCommitSpan @@ -241,7 +248,8 @@ Collection selectCommits(int expectedCommitCount) } } - // This commit is selected, calculate the next one. + // This commit is selected. + // Calculate where to look for the next one. int flags = nextFlg; nextIn = nextSpan(distanceFromTip); nextFlg = nextIn == distantCommitSpan @@ -250,43 +258,48 @@ Collection selectCommits(int expectedCommitCount) BitmapBuilder fullBitmap = commitBitmapIndex.newBitmapBuilder(); rw.reset(); rw.markStart(c); - for (AnyObjectId objectId : selectionHelper.reusedCommits) + for (AnyObjectId objectId : selectionHelper.reusedCommits) { rw.markUninteresting(rw.parseCommit(objectId)); + } rw.setRevFilter( PackWriterBitmapWalker.newRevFilter(null, fullBitmap)); while (rw.next() != null) { - // Work is done in the RevFilter. + // The RevFilter adds the reachable commits from this + // selected commit to fullBitmap. } - List> matches = new ArrayList< + // Sort the commits by independent chains in its history, + // yielding better compression when building bitmaps. + List> candidateChain = new ArrayList< List>(); - for (List list : running) { - BitmapCommit last = list.get(list.size() - 1); - if (fullBitmap.contains(last)) { - matches.add(list); + for (List chain : chains) { + BitmapCommit mostRecentCommit = chain.get(chain.size() - 1); + if (fullBitmap.contains(mostRecentCommit)) { + candidateChain.add(chain); } } - List match; - if (matches.isEmpty()) { - match = new ArrayList(); - running.add(match); + List longestAncestorChain; + if (candidateChain.isEmpty()) { + longestAncestorChain = new ArrayList(); + chains.add(longestAncestorChain); } else { - match = matches.get(0); + longestAncestorChain = candidateChain.get(0); // Append to longest - for (List list : matches) { - if (list.size() > match.size()) { - match = list; + for (List chain : candidateChain) { + if (chain.size() > longestAncestorChain.size()) { + longestAncestorChain = chain; } } } - match.add(new BitmapCommit(c, !match.isEmpty(), flags)); + longestAncestorChain.add(new BitmapCommit( + c, !longestAncestorChain.isEmpty(), flags)); writeBitmaps.addBitmap(c, fullBitmap, 0); } - for (List list : running) { - selections.addAll(list); + for (List chain : chains) { + selections.addAll(chain); } } writeBitmaps.clearBitmaps(); // Remove the temporary commit bitmaps. @@ -329,6 +342,7 @@ private CommitSelectionHelper setupTipCommitBitmaps(RevWalk rw, BitmapBuilder reuse = commitBitmapIndex.newBitmapBuilder(); List reuseCommits = new ArrayList(); for (PackBitmapIndexRemapper.Entry entry : bitmapRemapper) { + // More recent commits did not have the reuse flag set, so skip them if ((entry.getFlags() & FLAG_REUSE) != FLAG_REUSE) { continue; } @@ -346,8 +360,8 @@ private CommitSelectionHelper setupTipCommitBitmaps(RevWalk rw, } } - // Do a RevWalk by commit time descending. Keep track of all the paths - // from the wants. + // Add branch tips that are not represented in old bitmap indices. Set + // up the RevWalk to walk the new commits not in the old packs. List tipCommitBitmaps = new ArrayList( want.size()); Set peeledWant = new HashSet(want.size()); @@ -366,6 +380,8 @@ 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. RevCommit[] commits = new RevCommit[expectedCommitCount]; int pos = commits.length; RevCommit rc; @@ -480,7 +496,6 @@ int getFlags() { */ private static final class BitmapBuilderEntry { private final RevCommit commit; - private final BitmapBuilder builder; BitmapBuilderEntry(RevCommit commit, BitmapBuilder builder) { @@ -509,7 +524,6 @@ BitmapBuilder getBuilder() { */ private static final class CommitSelectionHelper implements Iterable { final Set peeledWants; - final List tipCommitBitmaps; final Iterable reusedCommits; final RevCommit[] commitsByOldest; @@ -527,6 +541,8 @@ private static final class CommitSelectionHelper implements Iterable } public Iterator iterator() { + // Member variables referenced by this iterator will have synthetic + // accessors generated for them if they are made private. return new Iterator() { int pos = commitStartPos;