From af928bb6dcf880853b7a5493a54fc5b61180e172 Mon Sep 17 00:00:00 2001 From: Thomas Groh Date: Wed, 26 Oct 2016 16:35:31 -0700 Subject: [PATCH] Use a NavigableSet Instead of a PriorityQueue in WatermarkManager This removes an O(n) call to remove, replacing it with an O(log(n)) call. This significantly improves scaling behavior of the DirectRunner --- .../beam/runners/direct/WatermarkManager.java | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/runners/direct-java/src/main/java/org/apache/beam/runners/direct/WatermarkManager.java b/runners/direct-java/src/main/java/org/apache/beam/runners/direct/WatermarkManager.java index f8cbc510c909..31b80912968b 100644 --- a/runners/direct-java/src/main/java/org/apache/beam/runners/direct/WatermarkManager.java +++ b/runners/direct-java/src/main/java/org/apache/beam/runners/direct/WatermarkManager.java @@ -39,7 +39,6 @@ import java.util.Map; import java.util.NavigableSet; import java.util.Objects; -import java.util.PriorityQueue; import java.util.Set; import java.util.TreeSet; import java.util.concurrent.ConcurrentLinkedQueue; @@ -388,7 +387,7 @@ private static class SynchronizedProcessingTimeInputWatermark implements Waterma private final Map, NavigableSet> processingTimers; private final Map, NavigableSet> synchronizedProcessingTimers; - private final PriorityQueue pendingTimers; + private final NavigableSet pendingTimers; private AtomicReference earliestHold; @@ -397,7 +396,7 @@ public SynchronizedProcessingTimeInputWatermark(Collection this.pendingBundles = new HashSet<>(); this.processingTimers = new HashMap<>(); this.synchronizedProcessingTimers = new HashMap<>(); - this.pendingTimers = new PriorityQueue<>(); + this.pendingTimers = new TreeSet<>(); Instant initialHold = BoundedWindow.TIMESTAMP_MAX_VALUE; for (Watermark wm : inputWms) { initialHold = INSTANT_ORDERING.min(initialHold, wm.get()); @@ -466,7 +465,7 @@ public synchronized Instant getEarliestTimerTimestamp() { } } if (!pendingTimers.isEmpty()) { - earliest = INSTANT_ORDERING.min(pendingTimers.peek().getTimestamp(), earliest); + earliest = INSTANT_ORDERING.min(pendingTimers.first().getTimestamp(), earliest); } return earliest; } @@ -630,7 +629,7 @@ public Instant get() { private static final Ordering INSTANT_ORDERING = Ordering.natural(); /** - * For each (Object, PriorityQueue) pair in the provided map, remove each Timer that is before the + * For each (Object, NavigableSet) pair in the provided map, remove each Timer that is before the * latestTime argument and put in in the result with the same key, then remove all of the keys * which have no more pending timers. * @@ -1003,11 +1002,11 @@ public String toString() { private static class PerKeyHolds { private final Map keyedHolds; - private final PriorityQueue allHolds; + private final NavigableSet allHolds; private PerKeyHolds() { this.keyedHolds = new HashMap<>(); - this.allHolds = new PriorityQueue<>(); + this.allHolds = new TreeSet<>(); } /** @@ -1015,7 +1014,7 @@ private PerKeyHolds() { * there are no holds within this {@link PerKeyHolds}. */ public Instant getMinHold() { - return allHolds.isEmpty() ? THE_END_OF_TIME.get() : allHolds.peek().getTimestamp(); + return allHolds.isEmpty() ? THE_END_OF_TIME.get() : allHolds.first().getTimestamp(); } /** @@ -1026,7 +1025,7 @@ public void updateHold(@Nullable Object key, Instant newHold) { removeHold(key); KeyedHold newKeyedHold = KeyedHold.of(key, newHold); keyedHolds.put(key, newKeyedHold); - allHolds.offer(newKeyedHold); + allHolds.add(newKeyedHold); } /**