Merge branch 'stable-2.16' into stable-3.0

* stable-2.16:
  Do not synchronize replication config shutdown

Change-Id: Ia8870aa9b4692825b3d878d7546e8c1d7cf45726
diff --git a/src/main/java/com/googlesource/gerrit/plugins/replication/AutoReloadConfigDecorator.java b/src/main/java/com/googlesource/gerrit/plugins/replication/AutoReloadConfigDecorator.java
index 21c3960..945f869 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/replication/AutoReloadConfigDecorator.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/replication/AutoReloadConfigDecorator.java
@@ -41,7 +41,7 @@
   private static final long RELOAD_DELAY = 120;
   private static final long RELOAD_INTERVAL = 60;
 
-  private ReplicationFileBasedConfig currentConfig;
+  private volatile ReplicationFileBasedConfig currentConfig;
   private long currentConfigTs;
   private long lastFailedConfigTs;
 
@@ -54,6 +54,8 @@
   private final ScheduledExecutorService autoReloadExecutor;
   private ScheduledFuture<?> autoReloadRunnable;
 
+  private volatile boolean shuttingDown;
+
   @Inject
   public AutoReloadConfigDecorator(
       SitePaths site,
@@ -111,7 +113,8 @@
       long lastModified = getLastModified(currentConfig);
       try {
         if (force
-            || (lastModified > currentConfigTs
+            || (!shuttingDown
+                && lastModified > currentConfigTs
                 && lastModified > lastFailedConfigTs
                 && queue.isRunning()
                 && !queue.isReplaying())) {
@@ -159,8 +162,22 @@
     return currentConfig.getEventsDirectory();
   }
 
+  /* shutdown() cannot be set as a synchronized method because
+   * it may need to wait for pending events to complete;
+   * e.g. when enabling the drain of replication events before
+   * shutdown.
+   *
+   * As a rule of thumb for synchronized methods, because they
+   * implicitly define a critical section and associated lock,
+   * they should never hold waiting for another resource, otherwise
+   * the risk of deadlock is very high.
+   *
+   * See more background about deadlocks, what they are and how to
+   * prevent them at: https://en.wikipedia.org/wiki/Deadlock
+   */
   @Override
-  public synchronized int shutdown() {
+  public int shutdown() {
+    this.shuttingDown = true;
     if (autoReloadRunnable != null) {
       autoReloadRunnable.cancel(false);
       autoReloadRunnable = null;
@@ -170,6 +187,7 @@
 
   @Override
   public synchronized void startup(WorkQueue workQueue) {
+    shuttingDown = false;
     currentConfig.startup(workQueue);
     autoReloadRunnable =
         autoReloadExecutor.scheduleAtFixedRate(