Browse Source

Merge changes I22a8874b,I68ed4abd,I740bc4bf,Icbd17d15

* changes:
  BitmapWalker: do not revisit objects in bitmap
  Use bitmaps for non-commit reachability checks
  Make PackWriterBitmapWalker public
  UploadPackTest: construct commits in test method
stable-4.10
Jonathan Nieder 7 years ago committed by Gerrit Code Review @ Eclipse.org
parent
commit
b88204edfb
  1. 105
      org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/UploadPackTest.java
  2. 105
      org.eclipse.jgit/src/org/eclipse/jgit/internal/revwalk/AddToBitmapFilter.java
  3. 113
      org.eclipse.jgit/src/org/eclipse/jgit/internal/revwalk/AddUnseenToBitmapFilter.java
  4. 7
      org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/PackWriter.java
  5. 7
      org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/PackWriterBitmapPreparer.java
  6. 160
      org.eclipse.jgit/src/org/eclipse/jgit/revwalk/BitmapWalker.java
  7. 35
      org.eclipse.jgit/src/org/eclipse/jgit/transport/UploadPack.java

105
org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/UploadPackTest.java

@ -4,24 +4,33 @@ import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import java.util.Collections;
import org.eclipse.jgit.errors.TransportException;
import org.eclipse.jgit.internal.storage.dfs.DfsGarbageCollector;
import org.eclipse.jgit.internal.storage.dfs.DfsRepositoryDescription;
import org.eclipse.jgit.internal.storage.dfs.InMemoryRepository;
import org.eclipse.jgit.junit.TestRepository;
import org.eclipse.jgit.lib.NullProgressMonitor;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.revwalk.RevBlob;
import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.transport.UploadPack.RequestPolicy;
import org.eclipse.jgit.transport.resolver.ServiceNotAuthorizedException;
import org.eclipse.jgit.transport.resolver.ServiceNotEnabledException;
import org.eclipse.jgit.transport.resolver.UploadPackFactory;
import org.hamcrest.Matchers;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
/**
* Tests for server upload-pack utilities.
*/
public class UploadPackTest {
@Rule
public ExpectedException thrown = ExpectedException.none();
private URIish uri;
private TestProtocol<Object> testProtocol;
@ -32,23 +41,14 @@ public class UploadPackTest {
private InMemoryRepository client;
private RevCommit commit0;
private RevCommit commit1;
private RevCommit tip;
private TestRepository<InMemoryRepository> remote;
@Before
public void setUp() throws Exception {
server = newRepo("server");
client = newRepo("client");
TestRepository<InMemoryRepository> remote =
new TestRepository<>(server);
commit0 = remote.commit().message("0").create();
commit1 = remote.commit().message("1").parent(commit0).create();
tip = remote.commit().message("2").parent(commit1).create();
remote.update("master", tip);
remote = new TestRepository<>(server);
}
@After
@ -60,8 +60,32 @@ public class UploadPackTest {
return new InMemoryRepository(new DfsRepositoryDescription(name));
}
private void generateBitmaps(InMemoryRepository repo) throws Exception {
new DfsGarbageCollector(repo).pack(null);
repo.scanForRepoChanges();
}
private static TestProtocol<Object> generateReachableCommitUploadPackProtocol() {
return new TestProtocol<>(
new UploadPackFactory<Object>() {
@Override
public UploadPack create(Object req, Repository db)
throws ServiceNotEnabledException,
ServiceNotAuthorizedException {
UploadPack up = new UploadPack(db);
up.setRequestPolicy(RequestPolicy.REACHABLE_COMMIT);
return up;
}
}, null);
}
@Test
public void testFetchParentOfShallowCommit() throws Exception {
RevCommit commit0 = remote.commit().message("0").create();
RevCommit commit1 = remote.commit().message("1").parent(commit0).create();
RevCommit tip = remote.commit().message("2").parent(commit1).create();
remote.update("master", tip);
testProtocol = new TestProtocol<>(
new UploadPackFactory<Object>() {
@Override
@ -87,4 +111,63 @@ public class UploadPackTest {
assertTrue(client.hasObject(commit0.toObjectId()));
}
}
@Test
public void testFetchUnreachableBlobWithBitmap() throws Exception {
RevBlob blob = remote.blob("foo");
remote.commit(remote.tree(remote.file("foo", blob)));
generateBitmaps(server);
testProtocol = generateReachableCommitUploadPackProtocol();
uri = testProtocol.register(ctx, server);
assertFalse(client.hasObject(blob.toObjectId()));
try (Transport tn = testProtocol.open(uri, client, "server")) {
thrown.expect(TransportException.class);
thrown.expectMessage(Matchers.containsString(
"want " + blob.name() + " not valid"));
tn.fetch(NullProgressMonitor.INSTANCE,
Collections.singletonList(new RefSpec(blob.name())));
}
}
@Test
public void testFetchReachableBlobWithBitmap() throws Exception {
RevBlob blob = remote.blob("foo");
RevCommit commit = remote.commit(remote.tree(remote.file("foo", blob)));
remote.update("master", commit);
generateBitmaps(server);
testProtocol = generateReachableCommitUploadPackProtocol();
uri = testProtocol.register(ctx, server);
assertFalse(client.hasObject(blob.toObjectId()));
try (Transport tn = testProtocol.open(uri, client, "server")) {
tn.fetch(NullProgressMonitor.INSTANCE,
Collections.singletonList(new RefSpec(blob.name())));
assertTrue(client.hasObject(blob.toObjectId()));
}
}
@Test
public void testFetchReachableBlobWithoutBitmap() throws Exception {
RevBlob blob = remote.blob("foo");
RevCommit commit = remote.commit(remote.tree(remote.file("foo", blob)));
remote.update("master", commit);
testProtocol = generateReachableCommitUploadPackProtocol();
uri = testProtocol.register(ctx, server);
assertFalse(client.hasObject(blob.toObjectId()));
try (Transport tn = testProtocol.open(uri, client, "server")) {
thrown.expect(TransportException.class);
thrown.expectMessage(Matchers.containsString(
"want " + blob.name() + " not valid"));
tn.fetch(NullProgressMonitor.INSTANCE,
Collections.singletonList(new RefSpec(blob.name())));
}
}
}

105
org.eclipse.jgit/src/org/eclipse/jgit/internal/revwalk/AddToBitmapFilter.java

@ -0,0 +1,105 @@
/*
* Copyright (C) 2017, Google Inc.
* and other copyright owners as documented in the project's IP log.
*
* This program and the accompanying materials are made available
* under the terms of the Eclipse Distribution License v1.0 which
* accompanies this distribution, is reproduced below, and is
* available at http://www.eclipse.org/org/documents/edl-v10.php
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
*
* - Neither the name of the Eclipse Foundation, Inc. nor the
* names of its contributors may be used to endorse or promote
* products derived from this software without specific prior
* written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.eclipse.jgit.internal.revwalk;
import org.eclipse.jgit.lib.BitmapIndex.Bitmap;
import org.eclipse.jgit.lib.BitmapIndex.BitmapBuilder;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.revwalk.filter.RevFilter;
import org.eclipse.jgit.revwalk.RevWalk;
import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.revwalk.RevFlag;
/**
* A RevFilter that adds the visited commits to {@code bitmap} as a side
* effect.
* <p>
* When the walk hits a commit that is part of {@code bitmap}'s
* BitmapIndex, that entire bitmap is ORed into {@code bitmap} and the
* commit and its parents are marked as SEEN so that the walk does not
* have to visit its ancestors. This ensures the walk is very short if
* there is good bitmap coverage.
*/
public class AddToBitmapFilter extends RevFilter {
private final BitmapBuilder bitmap;
/**
* Create a filter that adds visited commits to the given bitmap.
*
* @param bitmap bitmap to write visited commits to
*/
public AddToBitmapFilter(BitmapBuilder bitmap) {
this.bitmap = bitmap;
}
@Override
public final boolean include(RevWalk walker, RevCommit cmit) {
Bitmap visitedBitmap;
if (bitmap.contains(cmit)) {
// already included
} else if ((visitedBitmap = bitmap.getBitmapIndex()
.getBitmap(cmit)) != null) {
bitmap.or(visitedBitmap);
} else {
bitmap.addObject(cmit, Constants.OBJ_COMMIT);
return true;
}
for (RevCommit p : cmit.getParents()) {
p.add(RevFlag.SEEN);
}
return false;
}
@Override
public final RevFilter clone() {
throw new UnsupportedOperationException();
}
@Override
public final boolean requiresCommitBody() {
return false;
}
}

113
org.eclipse.jgit/src/org/eclipse/jgit/internal/revwalk/AddUnseenToBitmapFilter.java

@ -0,0 +1,113 @@
/*
* Copyright (C) 2017, Google Inc.
* and other copyright owners as documented in the project's IP log.
*
* This program and the accompanying materials are made available
* under the terms of the Eclipse Distribution License v1.0 which
* accompanies this distribution, is reproduced below, and is
* available at http://www.eclipse.org/org/documents/edl-v10.php
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
*
* - Neither the name of the Eclipse Foundation, Inc. nor the
* names of its contributors may be used to endorse or promote
* products derived from this software without specific prior
* written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.eclipse.jgit.internal.revwalk;
import org.eclipse.jgit.lib.BitmapIndex.Bitmap;
import org.eclipse.jgit.lib.BitmapIndex.BitmapBuilder;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.revwalk.filter.RevFilter;
import org.eclipse.jgit.revwalk.RevWalk;
import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.revwalk.RevFlag;
/**
* A RevFilter that adds the visited commits to {@code bitmap} as a side
* effect.
* <p>
* When the walk hits a commit that is part of {@code bitmap}'s
* BitmapIndex, that entire bitmap is ORed into {@code bitmap} and the
* commit and its parents are marked as SEEN so that the walk does not
* have to visit its ancestors. This ensures the walk is very short if
* there is good bitmap coverage.
* <p>
* Commits named in {@code seen} are considered already seen. If one is
* encountered, that commit and its parents will be marked with the SEEN
* flag to prevent the walk from visiting its ancestors.
*/
public class AddUnseenToBitmapFilter extends RevFilter {
private final BitmapBuilder seen;
private final BitmapBuilder bitmap;
/**
* Create a filter that adds visited commits to the given bitmap, but does not walk
* through the objects in {@code seen}.
*
* @param seen objects that are already seen
* @param bitmap bitmap to write visited commits to
*/
public AddUnseenToBitmapFilter(BitmapBuilder seen, BitmapBuilder bitmap) {
this.seen = seen;
this.bitmap = bitmap;
}
@Override
public final boolean include(RevWalk walker, RevCommit cmit) {
Bitmap visitedBitmap;
if (seen.contains(cmit) || bitmap.contains(cmit)) {
// already seen or included
} else if ((visitedBitmap = bitmap.getBitmapIndex()
.getBitmap(cmit)) != null) {
bitmap.or(visitedBitmap);
} else {
bitmap.addObject(cmit, Constants.OBJ_COMMIT);
return true;
}
for (RevCommit p : cmit.getParents()) {
p.add(RevFlag.SEEN);
}
return false;
}
@Override
public final RevFilter clone() {
throw new UnsupportedOperationException();
}
@Override
public final boolean requiresCommitBody() {
return false;
}
}

7
org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/PackWriter.java

@ -107,6 +107,7 @@ import org.eclipse.jgit.lib.ProgressMonitor;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.lib.ThreadSafeProgressMonitor;
import org.eclipse.jgit.revwalk.AsyncRevObjectQueue;
import org.eclipse.jgit.revwalk.BitmapWalker;
import org.eclipse.jgit.revwalk.DepthWalk;
import org.eclipse.jgit.revwalk.ObjectWalk;
import org.eclipse.jgit.revwalk.RevCommit;
@ -1714,7 +1715,7 @@ public class PackWriter implements AutoCloseable {
if (!shallowPack && useBitmaps) {
BitmapIndex bitmapIndex = reader.getBitmapIndex();
if (bitmapIndex != null) {
PackWriterBitmapWalker bitmapWalker = new PackWriterBitmapWalker(
BitmapWalker bitmapWalker = new BitmapWalker(
walker, bitmapIndex, countingMonitor);
findObjectsToPackUsingBitmaps(bitmapWalker, want, have);
endPhase(countingMonitor);
@ -1917,7 +1918,7 @@ public class PackWriter implements AutoCloseable {
}
private void findObjectsToPackUsingBitmaps(
PackWriterBitmapWalker bitmapWalker, Set<? extends ObjectId> want,
BitmapWalker bitmapWalker, Set<? extends ObjectId> want,
Set<? extends ObjectId> have)
throws MissingObjectException, IncorrectObjectTypeException,
IOException {
@ -2123,7 +2124,7 @@ public class PackWriter implements AutoCloseable {
beginPhase(PackingPhase.BUILDING_BITMAPS, pm, selectedCommits.size());
PackWriterBitmapWalker walker = bitmapPreparer.newBitmapWalker();
BitmapWalker walker = bitmapPreparer.newBitmapWalker();
AnyObjectId last = null;
for (PackWriterBitmapPreparer.BitmapCommit cmit : selectedCommits) {
if (!cmit.isReuseWalker()) {

7
org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/PackWriterBitmapPreparer.java

@ -59,18 +59,19 @@ import java.util.Set;
import org.eclipse.jgit.errors.IncorrectObjectTypeException;
import org.eclipse.jgit.errors.MissingObjectException;
import org.eclipse.jgit.internal.JGitText;
import org.eclipse.jgit.internal.revwalk.AddUnseenToBitmapFilter;
import org.eclipse.jgit.internal.storage.file.BitmapIndexImpl;
import org.eclipse.jgit.internal.storage.file.BitmapIndexImpl.CompressedBitmap;
import org.eclipse.jgit.internal.storage.file.PackBitmapIndex;
import org.eclipse.jgit.internal.storage.file.PackBitmapIndexBuilder;
import org.eclipse.jgit.internal.storage.file.PackBitmapIndexRemapper;
import org.eclipse.jgit.internal.storage.pack.PackWriterBitmapWalker.AddUnseenToBitmapFilter;
import org.eclipse.jgit.lib.AnyObjectId;
import org.eclipse.jgit.lib.BitmapIndex.BitmapBuilder;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.ObjectReader;
import org.eclipse.jgit.lib.ProgressMonitor;
import org.eclipse.jgit.revwalk.BitmapWalker;
import org.eclipse.jgit.revwalk.ObjectWalk;
import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.revwalk.RevObject;
@ -508,8 +509,8 @@ class PackWriterBitmapPreparer {
return Math.max(next, recentCommitSpan);
}
PackWriterBitmapWalker newBitmapWalker() {
return new PackWriterBitmapWalker(
BitmapWalker newBitmapWalker() {
return new BitmapWalker(
new ObjectWalk(reader), bitmapIndex, null);
}

160
org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/PackWriterBitmapWalker.java → org.eclipse.jgit/src/org/eclipse/jgit/revwalk/BitmapWalker.java

@ -41,29 +41,30 @@
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.eclipse.jgit.internal.storage.pack;
package org.eclipse.jgit.revwalk;
import java.io.IOException;
import java.util.Arrays;
import org.eclipse.jgit.errors.IncorrectObjectTypeException;
import org.eclipse.jgit.errors.MissingObjectException;
import org.eclipse.jgit.internal.revwalk.AddToBitmapFilter;
import org.eclipse.jgit.internal.revwalk.AddUnseenToBitmapFilter;
import org.eclipse.jgit.lib.AnyObjectId;
import org.eclipse.jgit.lib.BitmapIndex;
import org.eclipse.jgit.lib.BitmapIndex.Bitmap;
import org.eclipse.jgit.lib.BitmapIndex.BitmapBuilder;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.NullProgressMonitor;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.ProgressMonitor;
import org.eclipse.jgit.revwalk.ObjectWalk;
import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.revwalk.RevFlag;
import org.eclipse.jgit.revwalk.RevObject;
import org.eclipse.jgit.revwalk.RevWalk;
import org.eclipse.jgit.revwalk.filter.RevFilter;
import org.eclipse.jgit.revwalk.filter.ObjectFilter;
/** Helper class for PackWriter to do ObjectWalks with pack index bitmaps. */
final class PackWriterBitmapWalker {
/**
* Helper class to do ObjectWalks with pack index bitmaps.
*
* @since 4.10
*/
public final class BitmapWalker {
private final ObjectWalk walker;
@ -73,18 +74,52 @@ final class PackWriterBitmapWalker {
private long countOfBitmapIndexMisses;
PackWriterBitmapWalker(
/**
* Create a BitmapWalker.
*
* @param walker walker to use when traversing the object graph.
* @param bitmapIndex index to obtain bitmaps from.
* @param pm progress monitor to report progress on.
*/
public BitmapWalker(
ObjectWalk walker, BitmapIndex bitmapIndex, ProgressMonitor pm) {
this.walker = walker;
this.bitmapIndex = bitmapIndex;
this.pm = (pm == null) ? NullProgressMonitor.INSTANCE : pm;
}
long getCountOfBitmapIndexMisses() {
/**
* Return the number of objects that had to be walked because they were not covered by a
* bitmap.
*
* @return the number of objects that had to be walked because they were not covered by a
* bitmap.
*/
public long getCountOfBitmapIndexMisses() {
return countOfBitmapIndexMisses;
}
BitmapBuilder findObjects(Iterable<? extends ObjectId> start, BitmapBuilder seen,
/**
* Return, as a bitmap, the objects reachable from the objects in start.
*
* @param start the objects to start the object traversal from.
* @param seen the objects to skip if encountered during traversal.
* @param ignoreMissing true to ignore missing objects, false otherwise.
* @return as a bitmap, the objects reachable from the objects in start.
* @throws MissingObjectException
* the object supplied is not available from the object
* database. This usually indicates the supplied object is
* invalid, but the reference was constructed during an earlier
* invocation to {@link RevWalk#lookupAny(AnyObjectId, int)}.
* @throws IncorrectObjectTypeException
* the object was not parsed yet and it was discovered during
* parsing that it is not actually the type of the instance
* passed in. This usually indicates the caller used the wrong
* type in a {@link RevWalk#lookupAny(AnyObjectId, int)} call.
* @throws IOException
* a pack file or loose object could not be read.
*/
public BitmapBuilder findObjects(Iterable<? extends ObjectId> start, BitmapBuilder seen,
boolean ignoreMissing)
throws MissingObjectException, IncorrectObjectTypeException,
IOException {
@ -167,6 +202,7 @@ final class PackWriterBitmapWalker {
walker.setRevFilter(
new AddUnseenToBitmapFilter(seen, bitmapResult));
}
walker.setObjectFilter(new BitmapObjectFilter(bitmapResult));
while (walker.next() != null) {
// Iterate through all of the commits. The BitmapRevFilter does
@ -193,104 +229,20 @@ final class PackWriterBitmapWalker {
}
/**
* A RevFilter that adds the visited commits to {@code bitmap} as a side
* effect.
* <p>
* When the walk hits a commit that is part of {@code bitmap}'s
* BitmapIndex, that entire bitmap is ORed into {@code bitmap} and the
* commit and its parents are marked as SEEN so that the walk does not
* have to visit its ancestors. This ensures the walk is very short if
* there is good bitmap coverage.
* Filter that excludes objects already in the given bitmap.
*/
static class AddToBitmapFilter extends RevFilter {
static class BitmapObjectFilter extends ObjectFilter {
private final BitmapBuilder bitmap;
AddToBitmapFilter(BitmapBuilder bitmap) {
BitmapObjectFilter(BitmapBuilder bitmap) {
this.bitmap = bitmap;
}
@Override
public final boolean include(RevWalk walker, RevCommit cmit) {
Bitmap visitedBitmap;
if (bitmap.contains(cmit)) {
// already included
} else if ((visitedBitmap = bitmap.getBitmapIndex()
.getBitmap(cmit)) != null) {
bitmap.or(visitedBitmap);
} else {
bitmap.addObject(cmit, Constants.OBJ_COMMIT);
return true;
}
for (RevCommit p : cmit.getParents()) {
p.add(RevFlag.SEEN);
}
return false;
}
@Override
public final RevFilter clone() {
throw new UnsupportedOperationException();
}
@Override
public final boolean requiresCommitBody() {
return false;
}
}
/**
* A RevFilter that adds the visited commits to {@code bitmap} as a side
* effect.
* <p>
* When the walk hits a commit that is part of {@code bitmap}'s
* BitmapIndex, that entire bitmap is ORed into {@code bitmap} and the
* commit and its parents are marked as SEEN so that the walk does not
* have to visit its ancestors. This ensures the walk is very short if
* there is good bitmap coverage.
* <p>
* Commits named in {@code seen} are considered already seen. If one is
* encountered, that commit and its parents will be marked with the SEEN
* flag to prevent the walk from visiting its ancestors.
*/
static class AddUnseenToBitmapFilter extends RevFilter {
private final BitmapBuilder seen;
private final BitmapBuilder bitmap;
AddUnseenToBitmapFilter(BitmapBuilder seen, BitmapBuilder bitmapResult) {
this.seen = seen;
this.bitmap = bitmapResult;
}
@Override
public final boolean include(RevWalk walker, RevCommit cmit) {
Bitmap visitedBitmap;
if (seen.contains(cmit) || bitmap.contains(cmit)) {
// already seen or included
} else if ((visitedBitmap = bitmap.getBitmapIndex()
.getBitmap(cmit)) != null) {
bitmap.or(visitedBitmap);
} else {
bitmap.addObject(cmit, Constants.OBJ_COMMIT);
return true;
}
for (RevCommit p : cmit.getParents()) {
p.add(RevFlag.SEEN);
}
return false;
}
@Override
public final RevFilter clone() {
throw new UnsupportedOperationException();
}
@Override
public final boolean requiresCommitBody() {
return false;
public final boolean include(ObjectWalk walker, AnyObjectId objid)
throws MissingObjectException, IncorrectObjectTypeException,
IOException {
return !bitmap.contains(objid);
}
}
}

35
org.eclipse.jgit/src/org/eclipse/jgit/transport/UploadPack.java

@ -77,14 +77,18 @@ import org.eclipse.jgit.errors.MissingObjectException;
import org.eclipse.jgit.errors.PackProtocolException;
import org.eclipse.jgit.internal.JGitText;
import org.eclipse.jgit.internal.storage.pack.PackWriter;
import org.eclipse.jgit.lib.BitmapIndex;
import org.eclipse.jgit.lib.BitmapIndex.BitmapBuilder;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.NullProgressMonitor;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.ObjectReader;
import org.eclipse.jgit.lib.ProgressMonitor;
import org.eclipse.jgit.lib.Ref;
import org.eclipse.jgit.lib.RefDatabase;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.revwalk.AsyncRevObjectQueue;
import org.eclipse.jgit.revwalk.BitmapWalker;
import org.eclipse.jgit.revwalk.DepthWalk;
import org.eclipse.jgit.revwalk.ObjectWalk;
import org.eclipse.jgit.revwalk.RevCommit;
@ -1315,6 +1319,18 @@ public class UploadPack {
}
}
private static void checkNotAdvertisedWantsUsingBitmap(ObjectReader reader,
BitmapIndex bitmapIndex, List<ObjectId> notAdvertisedWants,
Set<ObjectId> reachableFrom) throws IOException {
BitmapWalker bitmapWalker = new BitmapWalker(new ObjectWalk(reader), bitmapIndex, null);
BitmapBuilder reachables = bitmapWalker.findObjects(reachableFrom, null, false);
for (ObjectId oid : notAdvertisedWants) {
if (!reachables.contains(oid)) {
throw new WantNotValidException(oid);
}
}
}
private static void checkNotAdvertisedWants(UploadPack up,
List<ObjectId> notAdvertisedWants, Set<ObjectId> reachableFrom)
throws MissingObjectException, IncorrectObjectTypeException, IOException {
@ -1324,13 +1340,28 @@ public class UploadPack {
// into an advertised branch it will be marked UNINTERESTING and no commits
// return.
try (RevWalk walk = new RevWalk(up.getRevWalk().getObjectReader())) {
ObjectReader reader = up.getRevWalk().getObjectReader();
try (RevWalk walk = new RevWalk(reader)) {
AsyncRevObjectQueue q = walk.parseAny(notAdvertisedWants, true);
try {
RevObject obj;
while ((obj = q.next()) != null) {
if (!(obj instanceof RevCommit))
if (!(obj instanceof RevCommit)) {
// If unadvertized non-commits are requested, use
// bitmaps. If there are no bitmaps, instead of
// incurring the expense of a manual walk, reject
// the request.
BitmapIndex bitmapIndex = reader.getBitmapIndex();
if (bitmapIndex != null) {
checkNotAdvertisedWantsUsingBitmap(
reader,
bitmapIndex,
notAdvertisedWants,
reachableFrom);
return;
}
throw new WantNotValidException(obj);
}
walk.markStart((RevCommit) obj);
}
} catch (MissingObjectException notFound) {

Loading…
Cancel
Save