Browse Source

UploadPack: Prioritize references for non-advertised wants checks

UploadPack needs to check if object ids that weren't advertised before
are reachable from the references visible to the user. In the
bitmap-based reachability check, this is done incrementally: checking
against one reference, if anything remaining adding a second and so on.
It is more efficient to check first more common references (e.g. refs/heads/*)

Sort the references for the reachability checker. This should solve the
connectivity earlier and require less bitmap creation and less memory.

Change-Id: I48ac10d71e29fab2d346479802401eaea4aacb5c
Signed-off-by: Ivan Frade <ifrade@google.com>
stable-5.6
Ivan Frade 5 years ago
parent
commit
2ff0c0abaa
  1. 51
      org.eclipse.jgit/src/org/eclipse/jgit/transport/UploadPack.java

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

@ -85,6 +85,7 @@ import java.util.Objects;
import java.util.Optional; import java.util.Optional;
import java.util.Set; import java.util.Set;
import java.util.TreeMap; import java.util.TreeMap;
import java.util.function.Predicate;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import org.eclipse.jgit.annotations.NonNull; import org.eclipse.jgit.annotations.NonNull;
@ -1873,8 +1874,7 @@ public class UploadPack {
@Override @Override
public void checkWants(UploadPack up, List<ObjectId> wants) public void checkWants(UploadPack up, List<ObjectId> wants)
throws PackProtocolException, IOException { throws PackProtocolException, IOException {
checkNotAdvertisedWants(up, wants, checkNotAdvertisedWants(up, wants, up.getAdvertisedRefs().values());
refIdSet(up.getAdvertisedRefs().values()));
} }
} }
@ -1911,7 +1911,7 @@ public class UploadPack {
public void checkWants(UploadPack up, List<ObjectId> wants) public void checkWants(UploadPack up, List<ObjectId> wants)
throws PackProtocolException, IOException { throws PackProtocolException, IOException {
checkNotAdvertisedWants(up, wants, checkNotAdvertisedWants(up, wants,
refIdSet(up.getRepository().getRefDatabase().getRefs())); up.getRepository().getRefDatabase().getRefs());
} }
} }
@ -1971,12 +1971,14 @@ public class UploadPack {
} }
private static void checkNotAdvertisedWants(UploadPack up, private static void checkNotAdvertisedWants(UploadPack up,
List<ObjectId> notAdvertisedWants, Set<ObjectId> reachableFrom) List<ObjectId> notAdvertisedWants, Collection<Ref> visibleRefs)
throws IOException { throws IOException {
ObjectReader reader = up.getRevWalk().getObjectReader(); ObjectReader reader = up.getRevWalk().getObjectReader();
try (RevWalk walk = new RevWalk(reader)) { try (RevWalk walk = new RevWalk(reader)) {
walk.setRetainBody(false); walk.setRetainBody(false);
Set<ObjectId> reachableFrom = refIdSet(visibleRefs);
// Missing "wants" throw exception here // Missing "wants" throw exception here
List<RevObject> wantsAsObjs = objectIdsToRevObjects(walk, List<RevObject> wantsAsObjs = objectIdsToRevObjects(walk,
notAdvertisedWants); notAdvertisedWants);
@ -2023,10 +2025,11 @@ public class UploadPack {
ReachabilityChecker reachabilityChecker = walk ReachabilityChecker reachabilityChecker = walk
.createReachabilityChecker(); .createReachabilityChecker();
List<RevCommit> starters = objectIdsToRevCommits(walk, List<Ref> sortedVisibleRefs = moreImportantRefsFirst(visibleRefs);
reachableFrom); List<RevCommit> reachableCommits = refsToRevCommits(walk,
sortedVisibleRefs);
Optional<RevCommit> unreachable = reachabilityChecker Optional<RevCommit> unreachable = reachabilityChecker
.areAllReachable(wantsAsCommits, starters); .areAllReachable(wantsAsCommits, reachableCommits);
if (unreachable.isPresent()) { if (unreachable.isPresent()) {
throw new WantNotValidException(unreachable.get()); throw new WantNotValidException(unreachable.get());
} }
@ -2036,6 +2039,40 @@ public class UploadPack {
} }
} }
private static List<Ref> moreImportantRefsFirst(
Collection<Ref> visibleRefs) {
Predicate<Ref> startsWithRefsHeads = ref -> ref.getName()
.startsWith(Constants.R_HEADS);
Predicate<Ref> startsWithRefsTags = ref -> ref.getName()
.startsWith(Constants.R_TAGS);
Predicate<Ref> allOther = ref -> !startsWithRefsHeads.test(ref)
&& !startsWithRefsTags.test(ref);
List<Ref> sorted = new ArrayList<>(visibleRefs.size());
sorted.addAll(filterRefByPredicate(visibleRefs, startsWithRefsHeads));
sorted.addAll(filterRefByPredicate(visibleRefs, startsWithRefsTags));
sorted.addAll(filterRefByPredicate(visibleRefs, allOther));
return sorted;
}
private static List<Ref> filterRefByPredicate(Collection<Ref> refs,
Predicate<Ref> predicate) {
return refs.stream().filter(predicate).collect(Collectors.toList());
}
private static List<RevCommit> refsToRevCommits(RevWalk walk,
List<Ref> refs) throws MissingObjectException, IOException {
List<ObjectId> objIds = refs.stream().map(
ref -> firstNonNull(ref.getPeeledObjectId(), ref.getObjectId()))
.collect(Collectors.toList());
return objectIdsToRevCommits(walk, objIds);
}
private static ObjectId firstNonNull(ObjectId one, ObjectId two) {
return one != null ? one : two;
}
// Resolve the ObjectIds into RevObjects. Any missing object raises an // Resolve the ObjectIds into RevObjects. Any missing object raises an
// exception // exception
private static List<RevObject> objectIdsToRevObjects(RevWalk walk, private static List<RevObject> objectIdsToRevObjects(RevWalk walk,

Loading…
Cancel
Save