summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorIvan Frade <ifrade@google.com>2019-11-19 12:08:53 -0800
committerIvan Frade <ifrade@google.com>2019-11-21 09:30:19 -0800
commit989a927a5f0aa21745d560e77e9eb7c76682c117 (patch)
treea3c3d055d5ca6ddc4996ecbf1da151ceccce3c0c
parenta0204a4727ce39f3bd1564c445065dce6cefe608 (diff)
downloadjgit-989a927a5f0aa21745d560e77e9eb7c76682c117.tar.gz
jgit-989a927a5f0aa21745d560e77e9eb7c76682c117.zip
checkNotAdvertisedWants: Be lazy converting Ref to RevCommit
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>
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/UploadPackRefSortingForReachabilityTest.java33
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/transport/UploadPack.java76
2 files changed, 69 insertions, 40 deletions
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
index 0000000000..c9632aefa2
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/UploadPackRefSortingForReachabilityTest.java
@@ -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"));
+ }
+}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/UploadPack.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/UploadPack.java
index a26d23d6db..6ee280b81e 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/UploadPack.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/UploadPack.java
@@ -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);