1717################################################################################
1818import collections
1919import threading
20- from abc import ABC
20+ from abc import ABC , abstractmethod
2121from typing import Generic , TypeVar , List
2222
2323from pyflink .datastream import ResultFuture
@@ -34,12 +34,14 @@ class StreamElementQueueEntry(ABC, ResultFuture, Generic[OUT]):
3434 allows to set the result of a completed entry through ResultFuture.
3535 """
3636
37+ @abstractmethod
3738 def is_done (self ) -> bool :
3839 """
3940 True if the stream element queue entry has been completed; otherwise false.
4041 """
4142 pass
4243
44+ @abstractmethod
4345 def emit_result (self , output_processor ) -> int :
4446 """
4547 Emits the results associated with this queue entry.
@@ -109,6 +111,7 @@ def complete(self, result: List[OUT]):
109111
110112class StreamElementQueue (ABC , Generic [OUT ]):
111113
114+ @abstractmethod
112115 def put (self , windowed_value , timestamp , watermark , record ) -> ResultFuture [OUT ]:
113116 """
114117 Put the given record in the queue. This operation blocks until the queue has
@@ -125,6 +128,7 @@ def put(self, windowed_value, timestamp, watermark, record) -> ResultFuture[OUT]
125128 """
126129 pass
127130
131+ @abstractmethod
128132 def advance_watermark (self , watermark ):
129133 """
130134 Tries to put the given watermark in the queue. This operation succeeds if the queue has
@@ -134,6 +138,7 @@ def advance_watermark(self, watermark):
134138 """
135139 pass
136140
141+ @abstractmethod
137142 def emit_completed_element (self , output_processor ):
138143 """
139144 Emits one completed element from the head of this queue into the given output.
@@ -142,30 +147,35 @@ def emit_completed_element(self, output_processor):
142147 """
143148 pass
144149
150+ @abstractmethod
145151 def has_completed_elements (self ) -> bool :
146152 """
147153 Checks if there is at least one completed head element.
148154 """
149155 pass
150156
157+ @abstractmethod
151158 def wait_for_completed_elements (self ):
152159 """
153160 Waits until there is completed elements.
154161 """
155162 pass
156163
157- def wait_for_in_flight_elements_processed (self ):
164+ @abstractmethod
165+ def wait_for_in_flight_elements_processed (self , timeout = 1 ):
158166 """
159167 Waits until any inflight elements have been processed.
160168 """
161169 pass
162170
171+ @abstractmethod
163172 def is_empty (self ) -> bool :
164173 """
165174 True if the queue is empty; otherwise false.
166175 """
167176 pass
168177
178+ @abstractmethod
169179 def size (self ) -> int :
170180 """
171181 Return the size of the queue.
@@ -265,9 +275,10 @@ def put(self, windowed_value, timestamp, watermark, record) -> ResultFuture[OUT]
265275 return entry
266276
267277 def advance_watermark (self , watermark ):
268- with self ._lock :
269- if watermark > self ._current_watermark :
270- self ._current_watermark = watermark
278+ if watermark > self ._current_watermark :
279+ self ._current_watermark = watermark
280+
281+ with self ._lock :
271282 self ._add_watermark (watermark )
272283
273284 def emit_completed_element (self , output_processor ):
@@ -343,3 +354,67 @@ def _add_segment(self, capacity) -> 'UnorderedStreamElementQueue.Segment':
343354 new_segment = UnorderedStreamElementQueue .Segment (capacity )
344355 self ._segments .append (new_segment )
345356 return new_segment
357+
358+
359+ class OrderedStreamElementQueue (StreamElementQueue ):
360+
361+ def __init__ (self , capacity : int , exception_checker ):
362+ self ._capacity = capacity
363+ self ._exception_checker = exception_checker
364+ self ._queue = collections .deque ()
365+ self ._lock = threading .RLock ()
366+ self ._not_full = threading .Condition (self ._lock )
367+ self ._not_empty = threading .Condition (self ._lock )
368+ self ._number_of_pending_entries = 0
369+
370+ def put (self , windowed_value , timestamp , watermark , record ) -> ResultFuture [OUT ]:
371+ with self ._not_full :
372+ while self .size () >= self ._capacity :
373+ self ._not_full .wait (1 )
374+ self ._exception_checker ()
375+
376+ entry = StreamRecordQueueEntry (windowed_value , timestamp , watermark , record )
377+ entry .on_complete (self .on_complete_handler )
378+ self ._queue .append (entry )
379+ self ._number_of_pending_entries += 1
380+ return entry
381+
382+ def advance_watermark (self , watermark ):
383+ # do nothing in ordered mode
384+ pass
385+
386+ def emit_completed_element (self , output_processor ):
387+ with self ._not_full :
388+ if not self .has_completed_elements ():
389+ return
390+
391+ self ._queue .popleft ().emit_result (output_processor )
392+ self ._number_of_pending_entries -= 1
393+ self ._not_full .notify_all ()
394+
395+ def has_completed_elements (self ) -> bool :
396+ with self ._lock :
397+ return len (self ._queue ) > 0 and self ._queue [0 ].is_done ()
398+
399+ def wait_for_completed_elements (self ):
400+ with self ._not_empty :
401+ while not self .has_completed_elements ():
402+ self ._not_empty .wait ()
403+
404+ def wait_for_in_flight_elements_processed (self , timeout = 1 ):
405+ with self ._not_full :
406+ if self ._number_of_pending_entries != 0 :
407+ self ._not_full .wait (timeout )
408+
409+ def is_empty (self ) -> bool :
410+ with self ._lock :
411+ return self ._number_of_pending_entries == 0
412+
413+ def size (self ) -> int :
414+ with self ._lock :
415+ return self ._number_of_pending_entries
416+
417+ def on_complete_handler (self , entry ):
418+ with self ._not_empty :
419+ if self .has_completed_elements ():
420+ self ._not_empty .notify ()
0 commit comments