diff --git a/src/main/java/com/google/devtools/build/lib/runtime/BuildEventStreamer.java b/src/main/java/com/google/devtools/build/lib/runtime/BuildEventStreamer.java index 778e7b4d2f7183..4a291c37036042 100644 --- a/src/main/java/com/google/devtools/build/lib/runtime/BuildEventStreamer.java +++ b/src/main/java/com/google/devtools/build/lib/runtime/BuildEventStreamer.java @@ -18,12 +18,12 @@ import static com.google.common.base.Strings.nullToEmpty; import com.google.common.annotations.VisibleForTesting; -import com.google.common.collect.HashMultimap; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Iterables; -import com.google.common.collect.Multimap; +import com.google.common.collect.LinkedHashMultimap; +import com.google.common.collect.SetMultimap; import com.google.common.collect.Sets; import com.google.common.eventbus.AllowConcurrentEvents; import com.google.common.eventbus.Subscribe; @@ -106,8 +106,11 @@ private enum RetentionDecision { @GuardedBy("this") private List> bufferedStdoutStderrPairs = new ArrayList<>(); + // Use LinkedHashMultimap to maintain a FIFO ordering of pending events. + // This is important in case of Skymeld, so that the TestAttempt events are resolved in the + // correct order. @GuardedBy("this") - private final Multimap pendingEvents = HashMultimap.create(); + private final SetMultimap pendingEvents = LinkedHashMultimap.create(); @GuardedBy("this") private int progressCount; @@ -493,11 +496,11 @@ public void buildEvent(BuildEvent event) { } // Reconsider all events blocked by the event just posted. - Collection toReconsider; + Set blockedEventsFifo; synchronized (this) { - toReconsider = pendingEvents.removeAll(event.getEventId()); + blockedEventsFifo = pendingEvents.removeAll(event.getEventId()); } - for (BuildEvent freedEvent : toReconsider) { + for (BuildEvent freedEvent : blockedEventsFifo) { buildEvent(freedEvent); } @@ -558,14 +561,14 @@ private void maybePostPendingEventsBeforeDiscarding(BuildEvent event) { // a lot of extra locking e.g. for every ActionExecutedEvent and it's only necessary to // check for this where events are configured to "post after" events that may be discarded. BuildEventId eventId = event.getEventId(); - Collection toReconsider; + Set blockedEventsFifo; synchronized (this) { - toReconsider = pendingEvents.removeAll(eventId); + blockedEventsFifo = pendingEvents.removeAll(eventId); // Pretend we posted this event so a target summary arriving after this test summary (which // is common) doesn't get erroneously buffered in bufferUntilPrerequisitesReceived(). postedEvents.add(eventId); } - for (BuildEvent freedEvent : toReconsider) { + for (BuildEvent freedEvent : blockedEventsFifo) { buildEvent(freedEvent); } }