ReceiveCommits: Use ConcurrentLinkedQueue for messages to allow concurrent access

ReceiveCommits is not a singleton, but a new instance is created for
each push. However the messages in ReceiveCommits maybe be accessed
concurrently from 2 different threads. If this happens, we get a
ConcurrentModificationException.

Accessing the messages in ReceiveCommits concurrently from 2 different
threads can happen if the execution of ReceiveCommits in
AsyncReceiveCommits is aborted due to a timeout and AsyncReceiveCommits
tries to send the messages that have been collected so far:

1. AsyncReceiveCommits runs ReceiveCommits with a timeout (by executing
   ReceiveCommits with a timeout via an executor).

2. If ReceiveCommits takes too long, AsyncReceiveCommits gets a timeout.

3a. ReceiveCommits may still run in the background, which may add
    further messages to the message list.

3b. AsyncReceiveCommits tries to send all messages that have been
    collected so far from a finally block.  For sending the message we
    need to iterate over the message list, if this access to the message
    list happens at the same time as 3a. adds further messages to the
    message list we fail with a ConcurrentModificationException [1].

Fix this by using a ConcurrentLinkedQueue for storing the messages.

[1]
Caused by: java.util.ConcurrentModificationException
        at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:910)
        at java.util.ArrayList$Itr.next(ArrayList.java:860)
        at com.google.gerrit.server.git.receive.ReceiveCommits.sendMessages(ReceiveCommits.java:534)
        at com.google.gerrit.server.git.receive.AsyncReceiveCommits$Worker.sendMessages(AsyncReceiveCommits.java:161)
        at com.google.gerrit.server.git.receive.AsyncReceiveCommits.onPreReceive(AsyncReceiveCommits.java:379)
        ...

Signed-off-by: Edwin Kempin <ekempin@google.com>
Change-Id: I5816fec6351c351e6bf140fc61e4b06dbb9ffc43
diff --git a/java/com/google/gerrit/server/git/receive/ReceiveCommits.java b/java/com/google/gerrit/server/git/receive/ReceiveCommits.java
index c05ef0c..e991318 100644
--- a/java/com/google/gerrit/server/git/receive/ReceiveCommits.java
+++ b/java/com/google/gerrit/server/git/receive/ReceiveCommits.java
@@ -194,8 +194,10 @@
 import java.util.Map;
 import java.util.Objects;
 import java.util.Optional;
+import java.util.Queue;
 import java.util.Set;
 import java.util.TreeSet;
+import java.util.concurrent.ConcurrentLinkedQueue;
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.Future;
 import java.util.stream.Collectors;
@@ -358,7 +360,7 @@
 
   // Collections populated during processing.
   private final List<UpdateGroupsRequest> updateGroups;
-  private final List<ValidationMessage> messages;
+  private final Queue<ValidationMessage> messages;
   /** Multimap of error text to refnames that produced that error. */
   private final ListMultimap<String, String> errors;
 
@@ -485,7 +487,7 @@
 
     // Collections populated during processing.
     errors = MultimapBuilder.linkedHashKeys().arrayListValues().build();
-    messages = new ArrayList<>();
+    messages = new ConcurrentLinkedQueue<>();
     pushOptions = LinkedListMultimap.create();
     replaceByChange = new LinkedHashMap<>();
     updateGroups = new ArrayList<>();