]> source.dussan.org Git - jgit.git/commitdiff
checkNotAdvertisedWants: Be lazy converting Ref to RevCommit 89/152989/8
authorIvan Frade <ifrade@google.com>
Tue, 19 Nov 2019 20:08:53 +0000 (12:08 -0800)
committerIvan Frade <ifrade@google.com>
Thu, 21 Nov 2019 17:30:19 +0000 (09:30 -0800)
The ref points to an ObjectId that then is translated into a RevCommit.
This translation can be costly and with the incremental reachability
check is probably not needed for most of the elements.

Delay the translation from ObjectId to RevCommit to when it is needed.
Use Streams, that have the laziness built-in, all the way from Ref to
RevCommit.

This should reduce the latency for reachability checks over big sets of
references.

Change-Id: I28693087321b2beff3eaa1f3d2e7840ab0eedc6d
Signed-off-by: Ivan Frade <ifrade@google.com>
org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/UploadPackRefSortingForReachabilityTest.java [new file with mode: 0644]
org.eclipse.jgit/src/org/eclipse/jgit/transport/UploadPack.java

diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/UploadPackRefSortingForReachabilityTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/UploadPackRefSortingForReachabilityTest.java
new file mode 100644 (file)
index 0000000..c9632ae
--- /dev/null
@@ -0,0 +1,33 @@
+package org.eclipse.jgit.transport;
+
+import static org.hamcrest.Matchers.contains;
+import static org.junit.Assert.assertThat;
+
+import java.util.List;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+import org.eclipse.jgit.lib.ObjectId;
+import org.eclipse.jgit.lib.ObjectIdRef.Unpeeled;
+import org.eclipse.jgit.lib.Ref;
+import org.eclipse.jgit.lib.Ref.Storage;
+import org.junit.Test;
+
+public class UploadPackRefSortingForReachabilityTest {
+
+       @Test
+       public void sortReferences() {
+               List<Ref> refs = Stream.of("refs/changes/12/12", "refs/changes/12/1",
+                               "refs/heads/master", "refs/heads/something",
+                               "refs/changes/55/1", "refs/tags/v1.1")
+                               .map(s -> new Unpeeled(Storage.LOOSE, s, ObjectId.zeroId()))
+                               .collect(Collectors.toList());
+               Stream<Ref> sorted = UploadPack.importantRefsFirst(refs);
+               List<String> collected = sorted.map(Ref::getName)
+                               .collect(Collectors.toList());
+               assertThat(collected,
+                               contains("refs/heads/master", "refs/heads/something",
+                                               "refs/tags/v1.1", "refs/changes/12/12",
+                                               "refs/changes/12/1", "refs/changes/55/1"));
+       }
+}
index a26d23d6db7aae4f01148a7acba360f71a618e9e..6ee280b81e8133d5d81aef44cfe424e082ca80be 100644 (file)
@@ -87,6 +87,7 @@ import java.util.Set;
 import java.util.TreeMap;
 import java.util.function.Predicate;
 import java.util.stream.Collectors;
+import java.util.stream.Stream;
 
 import org.eclipse.jgit.annotations.NonNull;
 import org.eclipse.jgit.annotations.Nullable;
@@ -2025,11 +2026,13 @@ public class UploadPack {
                        ReachabilityChecker reachabilityChecker = walk
                                        .createReachabilityChecker();
 
-                       List<Ref> sortedVisibleRefs = moreImportantRefsFirst(visibleRefs);
-                       List<RevCommit> reachableCommits = refsToRevCommits(walk,
-                                       sortedVisibleRefs);
+                       Stream<RevCommit> reachableCommits = importantRefsFirst(visibleRefs)
+                                       .map(UploadPack::refToObjectId)
+                                       .map(objId -> objectIdToRevCommit(walk, objId))
+                                       .filter(Objects::nonNull); // Ignore missing tips
+
                        Optional<RevCommit> unreachable = reachabilityChecker
-                                       .areAllReachable(wantsAsCommits, reachableCommits.stream());
+                                       .areAllReachable(wantsAsCommits, reachableCommits);
                        if (unreachable.isPresent()) {
                                throw new WantNotValidException(unreachable.get());
                        }
@@ -2039,7 +2042,7 @@ public class UploadPack {
                }
        }
 
-       private static List<Ref> moreImportantRefsFirst(
+       static Stream<Ref> importantRefsFirst(
                        Collection<Ref> visibleRefs) {
                Predicate<Ref> startsWithRefsHeads = ref -> ref.getName()
                                .startsWith(Constants.R_HEADS);
@@ -2048,29 +2051,39 @@ public class UploadPack {
                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;
+               return Stream.concat(
+                               visibleRefs.stream().filter(startsWithRefsHeads),
+                               Stream.concat(
+                                               visibleRefs.stream().filter(startsWithRefsTags),
+                                               visibleRefs.stream().filter(allOther)));
        }
 
-       private static List<Ref> filterRefByPredicate(Collection<Ref> refs,
-                       Predicate<Ref> predicate) {
-               return refs.stream().filter(predicate).collect(Collectors.toList());
+       private static ObjectId refToObjectId(Ref ref) {
+               return ref.getObjectId() != null ? ref.getObjectId()
+                               : ref.getPeeledObjectId();
        }
 
-       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);
-       }
+       /**
+        * Translate an object id to a RevCommit.
+        *
+        * @param walk
+        *            walk on the relevant object storae
+        * @param objectId
+        *            Object Id
+        * @return RevCommit instance or null if the object is missing
+        */
+       @Nullable
+       private static RevCommit objectIdToRevCommit(RevWalk walk,
+                       ObjectId objectId) {
+               if (objectId == null) {
+                       return null;
+               }
 
-       private static ObjectId firstNonNull(ObjectId one, ObjectId two) {
-               return one != null ? one : two;
+               try {
+                       return walk.parseCommit(objectId);
+               } catch (IOException e) {
+                       return null;
+               }
        }
 
        // Resolve the ObjectIds into RevObjects. Any missing object raises an
@@ -2085,23 +2098,6 @@ public class UploadPack {
                return result;
        }
 
-       // Get commits from object ids. If the id is not a commit, ignore it. If the
-       // id doesn't exist, report the missing object in a exception.
-       private static List<RevCommit> objectIdsToRevCommits(RevWalk walk,
-                       Iterable<ObjectId> objectIds)
-                       throws MissingObjectException, IOException {
-               List<RevCommit> result = new ArrayList<>();
-               for (ObjectId objectId : objectIds) {
-                       try {
-                               result.add(walk.parseCommit(objectId));
-                       } catch (IncorrectObjectTypeException e) {
-                               continue;
-                       }
-               }
-               return result;
-       }
-
-
        private void addCommonBase(RevObject o) {
                if (!o.has(COMMON)) {
                        o.add(COMMON);