Special case hiding refs/meta/config from Git clients

VisibleRefFilter requires a lot of server CPU to accurately provide
the correct listing to clients when they cannot read refs/*.

Since the default configuration is now to hide refs/meta/config,
use a special case in VisibleRefFilter that permits showing every
reference except refs/meta/config if a user can read every other
reference in the repository.

Change-Id: Iba12ee5ea1babcfeb71d378139ce2fcfb121b949
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/VisibleRefFilter.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/VisibleRefFilter.java
index fc47f10..cb88f1e 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/git/VisibleRefFilter.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/VisibleRefFilter.java
@@ -14,6 +14,8 @@
 
 package com.google.gerrit.server.git;
 
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Maps;
 import com.google.gerrit.reviewdb.client.Change;
 import com.google.gerrit.reviewdb.client.PatchSet;
 import com.google.gerrit.reviewdb.client.Project;
@@ -60,6 +62,13 @@
   }
 
   public Map<String, Ref> filter(Map<String, Ref> refs, boolean filterTagsSeperately) {
+    if (projectCtl.allRefsAreVisibleExcept(
+        ImmutableSet.of(GitRepositoryManager.REF_CONFIG))) {
+      Map<String, Ref> r = Maps.newHashMap(refs);
+      r.remove(GitRepositoryManager.REF_CONFIG);
+      return r;
+    }
+
     final Set<Change.Id> visibleChanges = visibleChanges();
     final Map<String, Ref> result = new HashMap<String, Ref>();
     final List<Ref> deferredTags = new ArrayList<Ref>();
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/project/ProjectControl.java b/gerrit-server/src/main/java/com/google/gerrit/server/project/ProjectControl.java
index 67d91d5..513f1b1 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/project/ProjectControl.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/project/ProjectControl.java
@@ -38,6 +38,7 @@
 import com.google.inject.assistedinject.Assisted;
 
 import java.util.Collection;
+import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
@@ -196,8 +197,12 @@
 
   /** Can this user see all the refs in this projects? */
   public boolean allRefsAreVisible() {
+    return allRefsAreVisibleExcept(Collections.<String> emptySet());
+  }
+
+  public boolean allRefsAreVisibleExcept(Set<String> except) {
     return user instanceof InternalUser
-        || canPerformOnAllRefs(Permission.READ);
+        || canPerformOnAllRefs(Permission.READ, except);
   }
 
   /** Is this user a project owner? Ownership does not imply {@link #isVisible()} */
@@ -347,7 +352,7 @@
     return false;
   }
 
-  private boolean canPerformOnAllRefs(String permission) {
+  private boolean canPerformOnAllRefs(String permission, Set<String> except) {
     boolean canPerform = false;
     Set<String> patterns = allRefPatterns(permission);
     if (patterns.contains(AccessSection.ALL)) {
@@ -358,6 +363,8 @@
       for (final String pattern : patterns) {
         if (controlForRef(pattern).canPerform(permission)) {
           canPerform = true;
+        } else if (except.contains(pattern)) {
+          continue;
         } else {
           return false;
         }