Make IndexProjects REST endpoint take an argument for being async

Not all callers might want to have this be an asynchronous operation,
but some might, especially when reindexing projects with lots of
children. Hence, this commit makes that configurable.

Change-Id: Id67734cf0e33408f384925514cf8886c229844d2
diff --git a/Documentation/rest-api-projects.txt b/Documentation/rest-api-projects.txt
index 54f8022..792cca8 100644
--- a/Documentation/rest-api-projects.txt
+++ b/Documentation/rest-api-projects.txt
@@ -1357,8 +1357,8 @@
 === Index project
 
 Adds or updates the current project (and children, if specified) in the secondary index.
-The indexing task is executed asynchronously in background, so this command
-returns immediately.
+The indexing task is executed asynchronously in background and this command returns
+immediately if `async` is specified in the input.
 
 As an input, a link:#index-project-input[IndexProjectInput] entity can be provided.
 
@@ -1369,6 +1369,7 @@
 
   {
     "index_children": "true"
+    "async": "true"
   }
 ----
 
@@ -3162,6 +3163,8 @@
 |Field Name         ||Description
 |`index_children`   ||
 If children should be indexed recursively.
+|`async`            ||
+If projects should be indexed asynchronously.
 |================================
 
 [[inherited-boolean-info]]
diff --git a/java/com/google/gerrit/extensions/api/projects/IndexProjectInput.java b/java/com/google/gerrit/extensions/api/projects/IndexProjectInput.java
index a41f227..1b962c1 100644
--- a/java/com/google/gerrit/extensions/api/projects/IndexProjectInput.java
+++ b/java/com/google/gerrit/extensions/api/projects/IndexProjectInput.java
@@ -16,4 +16,5 @@
 
 public class IndexProjectInput {
   public Boolean indexChildren;
+  public Boolean async;
 }
diff --git a/java/com/google/gerrit/server/restapi/project/Index.java b/java/com/google/gerrit/server/restapi/project/Index.java
index 5547864..1b2a523 100644
--- a/java/com/google/gerrit/server/restapi/project/Index.java
+++ b/java/com/google/gerrit/server/restapi/project/Index.java
@@ -21,6 +21,7 @@
 import com.google.gerrit.common.data.GlobalCapability;
 import com.google.gerrit.extensions.annotations.RequiresCapability;
 import com.google.gerrit.extensions.api.projects.IndexProjectInput;
+import com.google.gerrit.extensions.common.ProjectInfo;
 import com.google.gerrit.extensions.restapi.AuthException;
 import com.google.gerrit.extensions.restapi.ResourceConflictException;
 import com.google.gerrit.extensions.restapi.Response;
@@ -62,27 +63,33 @@
           ResourceConflictException {
     String response = "Project " + rsrc.getName() + " submitted for reindexing";
 
-    reindexAsync(rsrc.getNameKey());
+    reindex(rsrc.getNameKey(), input.async);
     if (Boolean.TRUE.equals(input.indexChildren)) {
       ListChildProjects listChildProjects = listChildProjectsProvider.get();
       listChildProjects.setRecursive(true);
-      listChildProjects.apply(rsrc).forEach(p -> reindexAsync(new Project.NameKey(p.name)));
+      for (ProjectInfo child : listChildProjects.apply(rsrc)) {
+        reindex(new Project.NameKey(child.name), input.async);
+      }
 
       response += " (indexing children recursively)";
     }
     return Response.accepted(response);
   }
 
-  private void reindexAsync(Project.NameKey project) {
-    @SuppressWarnings("unused")
-    Future<?> possiblyIgnoredError =
-        executor.submit(
-            () -> {
-              try {
-                indexer.index(project);
-              } catch (IOException e) {
-                logger.atWarning().withCause(e).log("reindexing project %s failed", project);
-              }
-            });
+  private void reindex(Project.NameKey project, Boolean async) throws IOException {
+    if (Boolean.TRUE.equals(async)) {
+      @SuppressWarnings("unused")
+      Future<?> possiblyIgnoredError =
+          executor.submit(
+              () -> {
+                try {
+                  indexer.index(project);
+                } catch (IOException e) {
+                  logger.atWarning().withCause(e).log("reindexing project %s failed", project);
+                }
+              });
+    } else {
+      indexer.index(project);
+    }
   }
 }