Implement asynchronous Build Event Service (BES) upload.

We introduce a flag to control the flow of invocations w.r.t. BES upload. This new flag is called --bes_upload_mode and it currently has two possible values:
- WAIT_FOR_UPLOAD_COMPLETE (default, present in before this commit): In this mode Bazel will wait for the communication with the BES to finish.
- NOWAIT_FOR_UPLOAD_COMPLETE (new mode): In this mode Bazel *won't* wait for the BES upload to finish, instead it will finish the invocation as soon as it can. The upload continues in the background and if a new invocation starts Bazel will wait five seconds for the previous upload to finish before (abruptly) cancelling it.

PiperOrigin-RevId: 243591454
diff --git a/src/main/java/com/google/devtools/build/lib/buildeventservice/BuildEventServiceUploader.java b/src/main/java/com/google/devtools/build/lib/buildeventservice/BuildEventServiceUploader.java
index 2535091..c69ff9a 100644
--- a/src/main/java/com/google/devtools/build/lib/buildeventservice/BuildEventServiceUploader.java
+++ b/src/main/java/com/google/devtools/build/lib/buildeventservice/BuildEventServiceUploader.java
@@ -148,6 +148,9 @@
   @GuardedBy("lock")
   private boolean interruptCausedByTimeout;
 
+  @GuardedBy("lock")
+  private boolean interruptCausedByCancel;
+
   private StreamContext streamContext;
 
   private BuildEventServiceUploader(
@@ -239,22 +242,34 @@
     }
   }
 
-  /** Stops the upload immediately. Enqueued events that have not been sent yet will be lost. */
   private void closeOnTimeout() {
     synchronized (lock) {
+      interruptCausedByTimeout = true;
+      closeNow();
+    }
+  }
+
+  void closeOnCancel() {
+    synchronized (lock) {
+      interruptCausedByCancel = true;
+      closeNow();
+    }
+  }
+
+  /** Stops the upload immediately. Enqueued events that have not been sent yet will be lost. */
+  private void closeNow() {
+    synchronized (lock) {
       if (uploadThread != null) {
         if (uploadThread.isInterrupted()) {
           return;
         }
-
-        interruptCausedByTimeout = true;
         uploadThread.interrupt();
       }
     }
   }
 
   private void logAndExitAbruptly(String message, ExitCode exitCode, Throwable cause) {
-    checkState(exitCode != ExitCode.SUCCESS);
+    checkState(!exitCode.equals(ExitCode.SUCCESS));
     logger.info(message);
     abruptExitCallback.accept(new AbruptExitException(message, exitCode, cause));
   }
@@ -291,11 +306,14 @@
         logger.info("Aborting the BES upload due to having received an interrupt");
         synchronized (lock) {
           Preconditions.checkState(
-              interruptCausedByTimeout, "Unexpected interrupt on BES uploader thread");
-          logAndExitAbruptly(
-              "The Build Event Protocol upload timed out",
-              ExitCode.TRANSIENT_BUILD_EVENT_SERVICE_UPLOAD_ERROR,
-              e);
+              interruptCausedByTimeout || interruptCausedByCancel,
+              "Unexpected interrupt on BES uploader thread");
+          if (interruptCausedByTimeout) {
+            logAndExitAbruptly(
+                "The Build Event Protocol upload timed out",
+                ExitCode.TRANSIENT_BUILD_EVENT_SERVICE_UPLOAD_ERROR,
+                e);
+          }
         }
       } finally {
         // TODO(buchgr): Due to b/113035235 exitFunc needs to be called before the close future