Cache RefControl.isVisible()

In VisibleRefFilter, when VisibleChanges() is evaluated,
the RefControl.isVisible() is calculated for each change
even though they share destination ref.

For a git with many changes, storing the RefControl.isVisible()
can save valuable CPU-cycles. Especially in complex setups with
many rules.

When testing on a (real) project with many Changes and
PermissionRules a noticeable different could be seen:

ls-remote before fix:
real	0m3.024s
real	0m2.304s
real	0m2.654s
real	0m2.754s
real	0m3.474s
real	0m3.494s

ls-remote after fix:
real	0m2.004s
real	0m2.164s
real	0m1.934s
real	0m1.704s
real	0m1.674s
real	0m1.754s

Time for calculating visible refs could be cut down 30-50%.

Change-Id: I1a9f63f1c64cdeaa692429a1534e92b6f10eb62b
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/project/RefControl.java b/gerrit-server/src/main/java/com/google/gerrit/server/project/RefControl.java
index 4e6f626..229b062 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/project/RefControl.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/project/RefControl.java
@@ -58,6 +58,7 @@
   private Boolean owner;
   private Boolean canForgeAuthor;
   private Boolean canForgeCommitter;
+  private Boolean isVisible;
 
   RefControl(ProjectControl projectControl, String ref,
       PermissionCollection relevant) {
@@ -103,8 +104,12 @@
 
   /** Can this user see this reference exists? */
   public boolean isVisible() {
-    return (getCurrentUser() instanceof InternalUser || canPerform(Permission.READ))
-        && canRead();
+    if (isVisible == null) {
+      isVisible =
+          (getCurrentUser() instanceof InternalUser || canPerform(Permission.READ))
+              && canRead();
+    }
+    return isVisible;
   }
 
   /**