Add runnable that gets notified that it was canceled while running

Issue description:
Canceling task that is already started means that it will be not
able to finish (opening any resource will fail) and it will throw the
exception. Inside the runnable handling logic might be implemented (in
fact this is the case for replication) that it reschedules the task if
such error happens.
This is not expected if one decides to kill the task...

Solution:
Extend task handling so that it will propagate to specific runnable that
it was killed while running.

Change-Id: I2e44407f68ebcf0aa92e1e9e30e10f26feed7182
Signed-off-by: Jacek Centkowski <geminica.programs@gmail.com>
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/WorkQueue.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/WorkQueue.java
index ea863d2..3a0db3e 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/git/WorkQueue.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/WorkQueue.java
@@ -240,12 +240,29 @@
     }
   }
 
-  /** Runnable needing to know it was canceled. */
+  /**
+   * Runnable needing to know it was canceled.
+   * Note that cancel is called only in case the task is not in
+   * progress already.
+   */
   public interface CancelableRunnable extends Runnable {
     /** Notifies the runnable it was canceled. */
     void cancel();
   }
 
+  /**
+   * Base interface handles the case when task was canceled before
+   * actual execution and in case it was started cancel method is
+   * not called yet the task itself will be destroyed anyway (it
+   * will result in resource opening errors).
+   * This interface gives a chance to implementing classes for
+   * handling such scenario and act accordingly.
+   */
+  public interface CanceledWhileRunning extends CancelableRunnable {
+    /** Notifies the runnable it was canceled during execution. **/
+    void setCanceledWhileRunning();
+  }
+
   /** A wrapper around a scheduled Runnable, as maintained in the queue. */
   public static class Task<V> implements RunnableScheduledFuture<V> {
     /**
@@ -317,9 +334,12 @@
         // as running and allow it to clean up. This ensures we do
         // not invoke cancel twice.
         //
-        if (runnable instanceof CancelableRunnable
-            && running.compareAndSet(false, true)) {
-          ((CancelableRunnable) runnable).cancel();
+        if (runnable instanceof CancelableRunnable) {
+          if (running.compareAndSet(false, true)) {
+            ((CancelableRunnable) runnable).cancel();
+          } else if (runnable instanceof CanceledWhileRunning) {
+            ((CanceledWhileRunning) runnable).setCanceledWhileRunning();
+          }
         }
         executor.remove(this);
         executor.purge();