Merge "Emails: Retry failed index queries when querying accounts by preferred email"
diff --git a/java/com/google/gerrit/server/account/Emails.java b/java/com/google/gerrit/server/account/Emails.java
index 31e845b..8a48167 100644
--- a/java/com/google/gerrit/server/account/Emails.java
+++ b/java/com/google/gerrit/server/account/Emails.java
@@ -16,6 +16,7 @@
 
 import static com.google.common.collect.ImmutableSet.toImmutableSet;
 
+import com.google.common.base.Throwables;
 import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.ImmutableSetMultimap;
 import com.google.common.collect.Streams;
@@ -23,6 +24,9 @@
 import com.google.gerrit.server.account.externalids.ExternalId;
 import com.google.gerrit.server.account.externalids.ExternalIds;
 import com.google.gerrit.server.query.account.InternalAccountQuery;
+import com.google.gerrit.server.update.RetryHelper;
+import com.google.gerrit.server.update.RetryHelper.Action;
+import com.google.gerrit.server.update.RetryHelper.ActionType;
 import com.google.gwtorm.server.OrmException;
 import com.google.inject.Inject;
 import com.google.inject.Provider;
@@ -34,11 +38,16 @@
 public class Emails {
   private final ExternalIds externalIds;
   private final Provider<InternalAccountQuery> queryProvider;
+  private final RetryHelper retryHelper;
 
   @Inject
-  public Emails(ExternalIds externalIds, Provider<InternalAccountQuery> queryProvider) {
+  public Emails(
+      ExternalIds externalIds,
+      Provider<InternalAccountQuery> queryProvider,
+      RetryHelper retryHelper) {
     this.externalIds = externalIds;
     this.queryProvider = queryProvider;
+    this.retryHelper = retryHelper;
   }
 
   /**
@@ -63,7 +72,8 @@
   public ImmutableSet<Account.Id> getAccountFor(String email) throws IOException, OrmException {
     return Streams.concat(
             externalIds.byEmail(email).stream().map(ExternalId::accountId),
-            queryProvider.get().byPreferredEmail(email).stream().map(a -> a.getAccount().getId()))
+            executeIndexQuery(() -> queryProvider.get().byPreferredEmail(email).stream())
+                .map(a -> a.getAccount().getId()))
         .collect(toImmutableSet());
   }
 
@@ -80,12 +90,18 @@
         .entries()
         .stream()
         .forEach(e -> builder.put(e.getKey(), e.getValue().accountId()));
-    queryProvider
-        .get()
-        .byPreferredEmail(emails)
-        .entries()
-        .stream()
+    executeIndexQuery(() -> queryProvider.get().byPreferredEmail(emails).entries().stream())
         .forEach(e -> builder.put(e.getKey(), e.getValue().getAccount().getId()));
     return builder.build();
   }
+
+  private <T> T executeIndexQuery(Action<T> action) throws OrmException {
+    try {
+      return retryHelper.execute(ActionType.INDEX_QUERY, action, OrmException.class::isInstance);
+    } catch (Exception e) {
+      Throwables.throwIfUnchecked(e);
+      Throwables.throwIfInstanceOf(e, OrmException.class);
+      throw new OrmException(e);
+    }
+  }
 }
diff --git a/java/com/google/gerrit/server/git/receive/ReceiveCommits.java b/java/com/google/gerrit/server/git/receive/ReceiveCommits.java
index 3f59d5c..5c3984c 100644
--- a/java/com/google/gerrit/server/git/receive/ReceiveCommits.java
+++ b/java/com/google/gerrit/server/git/receive/ReceiveCommits.java
@@ -2974,7 +2974,7 @@
 
               for (ReplaceRequest req : replaceAndClose) {
                 Change.Id id = req.notes.getChangeId();
-                if (!executeRequestValidation(() -> req.validate(true))) {
+                if (!req.validate(true)) {
                   logDebug("Not closing %s because validation failed", id);
                   continue;
                 }
@@ -3026,20 +3026,6 @@
     }
   }
 
-  private <T> T executeRequestValidation(Action<T> action)
-      throws IOException, PermissionBackendException, OrmException {
-    try {
-      // The request validation needs to do an account query to lookup accounts by preferred email,
-      // if that index query fails the request validation should be retried.
-      return retryHelper.execute(ActionType.INDEX_QUERY, action, OrmException.class::isInstance);
-    } catch (Exception t) {
-      Throwables.throwIfInstanceOf(t, IOException.class);
-      Throwables.throwIfInstanceOf(t, PermissionBackendException.class);
-      Throwables.throwIfInstanceOf(t, OrmException.class);
-      throw new OrmException(t);
-    }
-  }
-
   private void updateAccountInfo() {
     if (setFullNameTo == null) {
       return;