Merge changes from topic "reverse-dns-lookup"

* changes:
  Disable gerrit.enableReverseDnsLookup by default
  Replace gerrit.disableReverseDnsLookup with gerrit.enableReverseDnsLookup
diff --git a/Documentation/config-gerrit.txt b/Documentation/config-gerrit.txt
index 95baed6..8479a8e 100644
--- a/Documentation/config-gerrit.txt
+++ b/Documentation/config-gerrit.txt
@@ -1967,6 +1967,23 @@
   installModule = com.example.abc.OurSpecialSauceModule
 ----
 
+[[gerrit.listProjectsFromIndex]]gerrit.listProjectsFromIndex::
++
+Enable rendering of project list from the secondary index instead
+of purely relying on the in-memory cache.
++
+By default false.
++
+[NOTE]
+The in-memory cache (set to false) rendering provides an **unlimited list** as a result
+of the list project API, causing the full list of projects to be
+returned as a result of the link:rest-api-projects.html[/projects/] REST API
+or the link:cmd-ls-projects.html[gerrit ls-projects] SSH command.
+When the rendering from the secondary index (set to true),
+the **list is limited** by the global capability
+link:access-control.html#capability_queryLimit[queryLimit]
+which is defaulted to 500 entries.
+
 [[gerrit.primaryWeblinkName]]gerrit.primaryWeblinkName::
 +
 Name of the link:dev-plugins.html#links-to-external-tools[Weblink] that should
diff --git a/java/com/google/gerrit/acceptance/GerritServer.java b/java/com/google/gerrit/acceptance/GerritServer.java
index 7571184..3a49f46 100644
--- a/java/com/google/gerrit/acceptance/GerritServer.java
+++ b/java/com/google/gerrit/acceptance/GerritServer.java
@@ -113,7 +113,8 @@
           null, // @GerritConfig is only valid on methods.
           null, // @GerritConfigs is only valid on methods.
           null, // @GlobalPluginConfig is only valid on methods.
-          null); // @GlobalPluginConfigs is only valid on methods.
+          null, // @GlobalPluginConfigs is only valid on methods.
+          getLogLevelThresholdAnnotation(testDesc));
     }
 
     public static Description forTestMethod(
@@ -135,7 +136,8 @@
           testDesc.getAnnotation(GerritConfig.class),
           testDesc.getAnnotation(GerritConfigs.class),
           testDesc.getAnnotation(GlobalPluginConfig.class),
-          testDesc.getAnnotation(GlobalPluginConfigs.class));
+          testDesc.getAnnotation(GlobalPluginConfigs.class),
+          getLogLevelThresholdAnnotation(testDesc));
     }
 
     private static boolean has(Class<? extends Annotation> annotation, Class<?> clazz) {
@@ -147,6 +149,14 @@
       return false;
     }
 
+    private static Level getLogLevelThresholdAnnotation(org.junit.runner.Description testDesc) {
+      LogThreshold logLevelThreshold = testDesc.getTestClass().getAnnotation(LogThreshold.class);
+      if (logLevelThreshold == null) {
+        return Level.DEBUG;
+      }
+      return Level.toLevel(logLevelThreshold.level());
+    }
+
     abstract org.junit.runner.Description testDescription();
 
     @Nullable
@@ -178,6 +188,8 @@
     @Nullable
     abstract GlobalPluginConfigs pluginConfigs();
 
+    abstract Level logLevelThreshold();
+
     private void checkValidAnnotations() {
       if (configs() != null && config() != null) {
         throw new IllegalStateException("Use either @GerritConfigs or @GerritConfig not both");
@@ -364,7 +376,7 @@
       throws Exception {
     checkArgument(site != null, "site is required (even for in-memory server");
     desc.checkValidAnnotations();
-    configureLogging();
+    configureLogging(desc.logLevelThreshold());
     CyclicBarrier serverStarted = new CyclicBarrier(2);
     Daemon daemon =
         new Daemon(
@@ -468,7 +480,7 @@
     return new GerritServer(desc, site, createTestInjector(daemon), daemon, daemonService);
   }
 
-  private static void configureLogging() {
+  private static void configureLogging(Level threshold) {
     LogManager.resetConfiguration();
 
     PatternLayout layout = new PatternLayout();
@@ -477,7 +489,7 @@
     ConsoleAppender dst = new ConsoleAppender();
     dst.setLayout(layout);
     dst.setTarget("System.err");
-    dst.setThreshold(Level.DEBUG);
+    dst.setThreshold(threshold);
     dst.activateOptions();
 
     Logger root = LogManager.getRootLogger();
diff --git a/java/com/google/gerrit/acceptance/LogThreshold.java b/java/com/google/gerrit/acceptance/LogThreshold.java
new file mode 100644
index 0000000..da1fcc5
--- /dev/null
+++ b/java/com/google/gerrit/acceptance/LogThreshold.java
@@ -0,0 +1,27 @@
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+package com.google.gerrit.acceptance;
+
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.ElementType.TYPE;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+@Target({TYPE, METHOD})
+@Retention(RUNTIME)
+public @interface LogThreshold {
+  String level() default "DEBUG";
+}
diff --git a/java/com/google/gerrit/server/restapi/project/ListProjects.java b/java/com/google/gerrit/server/restapi/project/ListProjects.java
index 4bf1230..4c55ff5 100644
--- a/java/com/google/gerrit/server/restapi/project/ListProjects.java
+++ b/java/com/google/gerrit/server/restapi/project/ListProjects.java
@@ -44,6 +44,7 @@
 import com.google.gerrit.server.CurrentUser;
 import com.google.gerrit.server.WebLinks;
 import com.google.gerrit.server.account.GroupControl;
+import com.google.gerrit.server.config.GerritServerConfig;
 import com.google.gerrit.server.git.GitRepositoryManager;
 import com.google.gerrit.server.group.GroupResolver;
 import com.google.gerrit.server.ioutil.RegexListSearcher;
@@ -82,6 +83,7 @@
 import java.util.stream.Stream;
 import java.util.stream.StreamSupport;
 import org.eclipse.jgit.errors.RepositoryNotFoundException;
+import org.eclipse.jgit.lib.Config;
 import org.eclipse.jgit.lib.Constants;
 import org.eclipse.jgit.lib.Ref;
 import org.eclipse.jgit.lib.Repository;
@@ -253,6 +255,7 @@
   private String matchRegex;
   private AccountGroup.UUID groupUuid;
   private final Provider<QueryProjects> queryProjectsProvider;
+  private final boolean listProjectsFromIndex;
 
   @Inject
   protected ListProjects(
@@ -264,7 +267,8 @@
       PermissionBackend permissionBackend,
       ProjectNode.Factory projectNodeFactory,
       WebLinks webLinks,
-      Provider<QueryProjects> queryProjectsProvider) {
+      Provider<QueryProjects> queryProjectsProvider,
+      @GerritServerConfig Config config) {
     this.currentUser = currentUser;
     this.projectCache = projectCache;
     this.groupResolver = groupResolver;
@@ -274,6 +278,7 @@
     this.projectNodeFactory = projectNodeFactory;
     this.webLinks = webLinks;
     this.queryProjectsProvider = queryProjectsProvider;
+    this.listProjectsFromIndex = config.getBoolean("gerrit", "listProjectsFromIndex", false);
   }
 
   public List<String> getShowBranch() {
@@ -322,7 +327,8 @@
   }
 
   private Optional<String> expressAsProjectsQuery() {
-    return !all
+    return listProjectsFromIndex
+            && !all
             && state != HIDDEN
             && isNullOrEmpty(matchPrefix)
             && isNullOrEmpty(matchRegex)
diff --git a/javatests/com/google/gerrit/acceptance/rest/project/ListProjectsIT.java b/javatests/com/google/gerrit/acceptance/rest/project/ListProjectsIT.java
index a30e2b9..f2c369e 100644
--- a/javatests/com/google/gerrit/acceptance/rest/project/ListProjectsIT.java
+++ b/javatests/com/google/gerrit/acceptance/rest/project/ListProjectsIT.java
@@ -23,6 +23,7 @@
 import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.Iterables;
 import com.google.gerrit.acceptance.AbstractDaemonTest;
+import com.google.gerrit.acceptance.GerritConfig;
 import com.google.gerrit.acceptance.NoHttpd;
 import com.google.gerrit.acceptance.Sandboxed;
 import com.google.gerrit.acceptance.TestProjectInput;
@@ -121,6 +122,21 @@
   }
 
   @Test
+  @GerritConfig(name = "gerrit.listProjectsFromIndex", value = "true")
+  public void listProjectsFromIndexShouldBeLimitedTo500() throws Exception {
+    int numTestProjects = 501;
+    assertThat(createProjects("foo", numTestProjects)).hasSize(numTestProjects);
+    assertThat(gApi.projects().list().get()).hasSize(500);
+  }
+
+  @Test
+  public void listProjectsShouldNotBeLimitedByDefault() throws Exception {
+    int numTestProjects = 501;
+    assertThat(createProjects("foo", numTestProjects)).hasSize(numTestProjects);
+    assertThat(gApi.projects().list().get().size()).isAtLeast(numTestProjects);
+  }
+
+  @Test
   public void listProjectsToOutputStream() throws Exception {
     int numInitialProjects = gApi.projects().list().get().size();
     int numTestProjects = 5;