Merge branch 'stable-3.10'

* stable-3.10:
  Add acceptance test for change up-to-date checker
  Indexing retries: lower normal condition logs to debug
  Check for existence of change's target SHA1 for reindexing

Change-Id: I1b7dc06bf8d91c4da12685483f529ba1cdc74481
diff --git a/setup_local_env/README.md b/setup_local_env/README.md
index e6ec9e7..8d9665f 100644
--- a/setup_local_env/README.md
+++ b/setup_local_env/README.md
@@ -74,7 +74,7 @@
 [--gerrit2-httpd-port]          Gerrit Instance 2 http port; default 18081
 [--gerrit2-sshd-port]           Gerrit Instance 2 sshd port; default 49418
 
-[--replication-delay]           Replication delay across the two instances in seconds
+[--replication-delay]           Replication delay across the two instances in seconds; default 5 seconds
 
 [--just-cleanup-env]            Cleans up previous deployment; default false
 
diff --git a/src/main/java/com/googlesource/gerrit/plugins/multisite/index/ChangeChecker.java b/src/main/java/com/googlesource/gerrit/plugins/multisite/index/ChangeChecker.java
index 3277150..4a081d0 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/multisite/index/ChangeChecker.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/multisite/index/ChangeChecker.java
@@ -27,7 +27,7 @@
    *
    * @return notes of the Change
    */
-  public Optional<ChangeNotes> getChangeNotes();
+  Optional<ChangeNotes> getChangeNotes();
 
   /**
    * Create a new index event POJO associated with the current Change.
@@ -39,7 +39,7 @@
    * @return new IndexEvent
    * @throws IOException if the current Change cannot read
    */
-  public Optional<ChangeIndexEvent> newIndexEvent(String projectName, int changeId, boolean deleted)
+  Optional<ChangeIndexEvent> newIndexEvent(String projectName, int changeId, boolean deleted)
       throws IOException;
 
   /**
@@ -48,7 +48,7 @@
    * @param indexEvent indexing event
    * @return true if the local Change is up-to-date, false otherwise.
    */
-  public boolean isUpToDate(Optional<ChangeIndexEvent> indexEvent);
+  boolean isUpToDate(Optional<ChangeIndexEvent> indexEvent);
 
   /**
    * Return the last computed up-to-date Change time-stamp.
@@ -58,12 +58,12 @@
    * @return the Change timestamp epoch in seconds
    * @throws IOException if an I/O error occurred while reading the local Change
    */
-  public Optional<Long> getComputedChangeTs() throws IOException;
+  Optional<Long> getComputedChangeTs() throws IOException;
 
   /**
    * Check if the local Change contains current patchset refs
    *
    * @return true if local change contains meta and current patchset refs
    */
-  public boolean isChangeConsistent();
+  boolean isChangeConsistent();
 }
diff --git a/src/main/java/com/googlesource/gerrit/plugins/multisite/index/ChangeCheckerImpl.java b/src/main/java/com/googlesource/gerrit/plugins/multisite/index/ChangeCheckerImpl.java
index f3fa2e3..57c7cd1 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/multisite/index/ChangeCheckerImpl.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/multisite/index/ChangeCheckerImpl.java
@@ -15,9 +15,7 @@
 package com.googlesource.gerrit.plugins.multisite.index;
 
 import com.google.gerrit.entities.Change;
-import com.google.gerrit.entities.HumanComment;
 import com.google.gerrit.exceptions.StorageException;
-import com.google.gerrit.server.DraftCommentsReader;
 import com.google.gerrit.server.change.ChangeFinder;
 import com.google.gerrit.server.config.GerritInstanceId;
 import com.google.gerrit.server.config.GerritServerConfig;
@@ -45,12 +43,10 @@
 public class ChangeCheckerImpl implements ChangeChecker {
   private static final Logger log = LoggerFactory.getLogger(ChangeCheckerImpl.class);
   private final GitRepositoryManager gitRepoMgr;
-  private final DraftCommentsReader draftCommentsReader;
   private final OneOffRequestContext oneOffReqCtx;
   private final String changeId;
   private final ChangeFinder changeFinder;
   private final String instanceId;
-  private final boolean enableDraftCommentEvents;
   private Optional<Long> computedChangeTs = Optional.empty();
   private Optional<ChangeNotes> changeNotes = Optional.empty();
 
@@ -67,7 +63,6 @@
   @Inject
   public ChangeCheckerImpl(
       GitRepositoryManager gitRepoMgr,
-      DraftCommentsReader draftCommentsReader,
       ChangeFinder changeFinder,
       OneOffRequestContext oneOffReqCtx,
       @GerritInstanceId String instanceId,
@@ -75,12 +70,9 @@
       @Assisted String changeId) {
     this.changeFinder = changeFinder;
     this.gitRepoMgr = gitRepoMgr;
-    this.draftCommentsReader = draftCommentsReader;
     this.oneOffReqCtx = oneOffReqCtx;
     this.changeId = changeId;
     this.instanceId = instanceId;
-    this.enableDraftCommentEvents =
-        config.getBoolean("event", "stream-events", "enableDraftCommentEvents", false);
   }
 
   @Override
@@ -198,23 +190,12 @@
   }
 
   private Optional<Long> computeLastChangeTs() {
-    return getChangeNotes().map(this::getTsFromChangeAndDraftComments);
+    return getChangeNotes().map(this::getTsFromChange);
   }
 
-  private long getTsFromChangeAndDraftComments(ChangeNotes notes) {
+  private long getTsFromChange(ChangeNotes notes) {
     Change change = notes.getChange();
     Timestamp changeTs = Timestamp.from(change.getLastUpdatedOn());
-    if (enableDraftCommentEvents) {
-      try {
-        for (HumanComment comment :
-            draftCommentsReader.getDraftsByChangeForAllAuthors(changeNotes.get())) {
-          Timestamp commentTs = comment.writtenOn;
-          changeTs = commentTs.after(changeTs) ? commentTs : changeTs;
-        }
-      } catch (StorageException e) {
-        log.warn("Unable to access draft comments for change {}", change, e);
-      }
-    }
     return changeTs.getTime() / 1000;
   }
 }
diff --git a/src/main/java/com/googlesource/gerrit/plugins/multisite/validation/ValidationModule.java b/src/main/java/com/googlesource/gerrit/plugins/multisite/validation/ValidationModule.java
index fc4d505..ed22855 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/multisite/validation/ValidationModule.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/multisite/validation/ValidationModule.java
@@ -20,6 +20,7 @@
 import com.gerritforge.gerrit.globalrefdb.validation.RefUpdateValidator;
 import com.gerritforge.gerrit.globalrefdb.validation.SharedRefDatabaseWrapper;
 import com.gerritforge.gerrit.globalrefdb.validation.SharedRefDbBatchRefUpdate;
+import com.gerritforge.gerrit.globalrefdb.validation.SharedRefDbExceptionHook;
 import com.gerritforge.gerrit.globalrefdb.validation.SharedRefDbGitRepositoryManager;
 import com.gerritforge.gerrit.globalrefdb.validation.SharedRefDbRefDatabase;
 import com.gerritforge.gerrit.globalrefdb.validation.SharedRefDbRefUpdate;
@@ -30,6 +31,8 @@
 import com.gerritforge.gerrit.globalrefdb.validation.dfsrefdb.SharedRefEnforcement;
 import com.google.common.collect.ImmutableSet;
 import com.google.gerrit.extensions.config.FactoryModule;
+import com.google.gerrit.extensions.registration.DynamicSet;
+import com.google.gerrit.server.ExceptionHook;
 import com.google.gerrit.server.config.RepositoryConfig;
 import com.google.inject.Scopes;
 import com.google.inject.TypeLiteral;
@@ -73,5 +76,7 @@
           .to(CustomSharedRefEnforcementByProject.class)
           .in(Scopes.SINGLETON);
     }
+
+    DynamicSet.bind(binder(), ExceptionHook.class).to(SharedRefDbExceptionHook.class);
   }
 }