VisibilityCache: Use streams internally This is not a huge win in terms of readability or boilerplate reduction over the old approach using Collections2 methods. However, using streams makes it clearer where we're materializing to a list to avoid repeated iteration. In the old code, calling isEmpty() on a collection produced by Collections2.filter was unexpectedly O(n); in the new code, we have an explicit collect(toList()) step. Change-Id: I873fdb99129129ac4e66b522caf16e86c2589fb4
diff --git a/gitiles-servlet/src/main/java/com/google/gitiles/VisibilityCache.java b/gitiles-servlet/src/main/java/com/google/gitiles/VisibilityCache.java index e90d3d1..3bb3ac0 100644 --- a/gitiles-servlet/src/main/java/com/google/gitiles/VisibilityCache.java +++ b/gitiles-servlet/src/main/java/com/google/gitiles/VisibilityCache.java
@@ -14,17 +14,17 @@ package com.google.gitiles; +import static com.google.common.base.MoreObjects.firstNonNull; import static com.google.common.base.MoreObjects.toStringHelper; import static com.google.common.base.Preconditions.checkNotNull; -import static com.google.common.collect.Collections2.filter; import static java.util.Objects.hash; +import static java.util.stream.Collectors.toList; import static org.eclipse.jgit.lib.Constants.R_HEADS; import static org.eclipse.jgit.lib.Constants.R_TAGS; import com.google.common.base.Throwables; import com.google.common.cache.Cache; import com.google.common.cache.CacheBuilder; -import com.google.common.collect.Collections2; import com.google.common.util.concurrent.ExecutionError; import java.io.IOException; import java.util.Arrays; @@ -33,6 +33,7 @@ import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; +import java.util.stream.Stream; import org.eclipse.jgit.errors.IncorrectObjectTypeException; import org.eclipse.jgit.errors.MissingObjectException; import org.eclipse.jgit.lib.ObjectId; @@ -122,9 +123,8 @@ Throwables.propagateIfInstanceOf(e.getCause(), IOException.class); throw new IOException(e); } catch (ExecutionError e) { - // markUninteresting may overflow on pathological repos with very long - // merge chains. Play it safe and return false rather than letting the - // error propagate. + // markUninteresting may overflow on pathological repos with very long merge chains. Play it + // safe and return false rather than letting the error propagate. if (e.getCause() instanceof StackOverflowError) { return false; } @@ -142,24 +142,23 @@ return false; } - // If any reference directly points at the requested object, permit display. - // Common for displays of pending patch sets in Gerrit Code Review, or - // bookmarks to the commit a tag points at. - Collection<Ref> allRefs = repo.getRefDatabase().getRefs(RefDatabase.ALL).values(); - for (Ref ref : allRefs) { + // If any reference directly points at the requested object, permit display. Common for displays + // of pending patch sets in Gerrit Code Review, or bookmarks to the commit a tag points at. + Collection<Ref> all = repo.getRefDatabase().getRefs(RefDatabase.ALL).values(); + for (Ref ref : all) { ref = repo.getRefDatabase().peel(ref); if (id.equals(ref.getObjectId()) || id.equals(ref.getPeeledObjectId())) { return true; } } - // Check heads first under the assumption that most requests are for refs - // close to a head. Tags tend to be much further back in history and just - // clutter up the priority queue in the common case. + // Check heads first under the assumption that most requests are for refs close to a head. Tags + // tend to be much further back in history and just clutter up the priority queue in the common + // case. return isReachableFrom(walk, commit, knownReachable) - || isReachableFromRefs(walk, commit, filter(allRefs, r -> refStartsWith(r, R_HEADS))) - || isReachableFromRefs(walk, commit, filter(allRefs, r -> refStartsWith(r, R_TAGS))) - || isReachableFromRefs(walk, commit, filter(allRefs, r -> otherRefs(r))); + || isReachableFromRefs(walk, commit, all.stream().filter(r -> refStartsWith(r, R_HEADS))) + || isReachableFromRefs(walk, commit, all.stream().filter(r -> refStartsWith(r, R_TAGS))) + || isReachableFromRefs(walk, commit, all.stream().filter(r -> otherRefs(r))); } private static boolean refStartsWith(Ref ref, String prefix) { @@ -172,14 +171,15 @@ || refStartsWith(r, "refs/changes/")); } - private boolean isReachableFromRefs(RevWalk walk, RevCommit commit, Collection<Ref> refs) + private boolean isReachableFromRefs(RevWalk walk, RevCommit commit, Stream<Ref> refs) throws IOException { return isReachableFrom( - walk, - commit, - Collections2.transform( - refs, - r -> r.getPeeledObjectId() != null ? r.getPeeledObjectId() : r.getObjectId())); + walk, commit, refs.map(r -> firstNonNull(r.getPeeledObjectId(), r.getObjectId()))); + } + + private boolean isReachableFrom(RevWalk walk, RevCommit commit, Stream<ObjectId> ids) + throws IOException { + return isReachableFrom(walk, commit, ids.collect(toList())); } private boolean isReachableFrom(RevWalk walk, RevCommit commit, Collection<ObjectId> ids)