@@ -477,12 +477,15 @@ func (em *ElementManager) Bundles(ctx context.Context, upstreamCancelFn context.
477477 }
478478 }
479479 if ptimeEventsReady {
480- bundleID , ok , reschedule := ss .startProcessingTimeBundle (em , emNow , nextBundID )
480+ bundleID , ok , reschedule , pendingAdjustment := ss .startProcessingTimeBundle (em , emNow , nextBundID )
481481 // Handle the reschedule even when there's no bundle.
482482 if reschedule {
483483 em .changedStages .insert (stageID )
484484 }
485485 if ok {
486+ if pendingAdjustment > 0 {
487+ em .addPending (pendingAdjustment )
488+ }
486489 rb := RunBundle {StageID : stageID , BundleID : bundleID , Watermark : watermark }
487490
488491 em .inprogressBundles .insert (rb .BundleID )
@@ -1218,7 +1221,7 @@ type stageKind interface {
12181221 holdsInBundle map [mtime.Time ]int , panesInBundle []bundlePane , schedulable bool , pendingAdjustment int )
12191222 // buildProcessingTimeBundle handles building processing-time bundles for the stage per it's kind.
12201223 buildProcessingTimeBundle (ss * stageState , em * ElementManager , emNow mtime.Time ) (toProcess elementHeap , minTs mtime.Time , newKeys set [string ],
1221- holdsInBundle map [mtime.Time ]int , panesInBundle []bundlePane , schedulable bool )
1224+ holdsInBundle map [mtime.Time ]int , panesInBundle []bundlePane , schedulable bool , pendingAdjustment int )
12221225 // getPaneOrDefault based on the stage state, element metadata, and bundle id.
12231226 getPaneOrDefault (ss * stageState , defaultPane typex.PaneInfo , w typex.Window , keyBytes []byte , bundID string ) typex.PaneInfo
12241227}
@@ -1983,24 +1986,24 @@ keysPerBundle:
19831986 return toProcess , minTs , newKeys , holdsInBundle , panesInBundle , stillSchedulable , accumulatingPendingAdjustment
19841987}
19851988
1986- func (ss * stageState ) startProcessingTimeBundle (em * ElementManager , emNow mtime.Time , genBundID func () string ) (string , bool , bool ) {
1989+ func (ss * stageState ) startProcessingTimeBundle (em * ElementManager , emNow mtime.Time , genBundID func () string ) (string , bool , bool , int ) {
19871990 ss .mu .Lock ()
19881991 defer ss .mu .Unlock ()
19891992
1990- toProcess , minTs , newKeys , holdsInBundle , panesInBundle , stillSchedulable := ss .kind .buildProcessingTimeBundle (ss , em , emNow )
1993+ toProcess , minTs , newKeys , holdsInBundle , panesInBundle , stillSchedulable , accumulatingPendingAdjustment := ss .kind .buildProcessingTimeBundle (ss , em , emNow )
19911994
19921995 if len (toProcess ) == 0 {
19931996 // If we have nothing
1994- return "" , false , stillSchedulable
1997+ return "" , false , stillSchedulable , accumulatingPendingAdjustment
19951998 }
19961999 bundID := ss .makeInProgressBundle (genBundID , toProcess , minTs , newKeys , holdsInBundle , panesInBundle )
19972000 slog .Debug ("started a processing time bundle" , "stageID" , ss .ID , "bundleID" , bundID , "size" , len (toProcess ), "emNow" , emNow )
1998- return bundID , true , stillSchedulable
2001+ return bundID , true , stillSchedulable , accumulatingPendingAdjustment
19992002}
20002003
20012004// handleProcessingTimeTimer contains the common code for handling processing-time timers for aggregation stages and stateful stages.
20022005func handleProcessingTimeTimer (ss * stageState , em * ElementManager , emNow mtime.Time ,
2003- processTimerFn func (e element , toProcess []element , holdsInBundle map [mtime.Time ]int , panesInBundle []bundlePane ) ([]element , []bundlePane )) (elementHeap , mtime.Time , set [string ], map [mtime.Time ]int , []bundlePane , bool ) {
2006+ processTimerFn func (e element , toProcess []element , holdsInBundle map [mtime.Time ]int , panesInBundle []bundlePane ) ([]element , []bundlePane , int )) (elementHeap , mtime.Time , set [string ], map [mtime.Time ]int , []bundlePane , bool , int ) {
20042007 // TODO: Determine if it's possible and a good idea to treat all EventTime processing as a MinTime
20052008 // Special Case for ProcessingTime handling.
20062009 // Eg. Always queue EventTime elements at minTime.
@@ -2010,6 +2013,8 @@ func handleProcessingTimeTimer(ss *stageState, em *ElementManager, emNow mtime.T
20102013
20112014 var toProcess []element
20122015 var panesInBundle []bundlePane
2016+ var pendingAdjustment int
2017+ accumulatingPendingAdjustment := 0
20132018 minTs := mtime .MaxTimestamp
20142019 holdsInBundle := map [mtime.Time ]int {}
20152020
@@ -2044,7 +2049,8 @@ func handleProcessingTimeTimer(ss *stageState, em *ElementManager, emNow mtime.T
20442049 minTs = e .timestamp
20452050 }
20462051
2047- toProcess , panesInBundle = processTimerFn (e , toProcess , holdsInBundle , panesInBundle )
2052+ toProcess , panesInBundle , pendingAdjustment = processTimerFn (e , toProcess , holdsInBundle , panesInBundle )
2053+ accumulatingPendingAdjustment += pendingAdjustment
20482054 }
20492055
20502056 nextTime = ss .processingTimeTimers .Peek ()
@@ -2065,24 +2071,26 @@ func handleProcessingTimeTimer(ss *stageState, em *ElementManager, emNow mtime.T
20652071 // Add a refresh if there are still processing time events to process.
20662072 stillSchedulable := (nextTime < emNow && nextTime != mtime .MaxTimestamp || len (notYet ) > 0 )
20672073
2068- return toProcess , minTs , newKeys , holdsInBundle , panesInBundle , stillSchedulable
2074+ return toProcess , minTs , newKeys , holdsInBundle , panesInBundle , stillSchedulable , accumulatingPendingAdjustment
20692075}
20702076
20712077// buildProcessingTimeBundle for stateful stages prepares bundles for processing-time timers
2072- func (* statefulStageKind ) buildProcessingTimeBundle (ss * stageState , em * ElementManager , emNow mtime.Time ) (elementHeap , mtime.Time , set [string ], map [mtime.Time ]int , []bundlePane , bool ) {
2073- return handleProcessingTimeTimer (ss , em , emNow , func (e element , toProcess []element , holdsInBundle map [mtime.Time ]int , panesInBundle []bundlePane ) ([]element , []bundlePane ) {
2078+ func (* statefulStageKind ) buildProcessingTimeBundle (ss * stageState , em * ElementManager , emNow mtime.Time ) (elementHeap , mtime.Time , set [string ], map [mtime.Time ]int , []bundlePane , bool , int ) {
2079+ return handleProcessingTimeTimer (ss , em , emNow , func (e element , toProcess []element , holdsInBundle map [mtime.Time ]int , panesInBundle []bundlePane ) ([]element , []bundlePane , int ) {
20742080 holdsInBundle [e .holdTimestamp ]++
20752081 // We're going to process this timer!
20762082 toProcess = append (toProcess , e )
2077- return toProcess , nil
2083+ return toProcess , nil , 0
20782084 })
20792085}
20802086
20812087// buildProcessingTimeBundle for aggregation stages prepares bundles for after-processing-time triggers
2082- func (* aggregateStageKind ) buildProcessingTimeBundle (ss * stageState , em * ElementManager , emNow mtime.Time ) (elementHeap , mtime.Time , set [string ], map [mtime.Time ]int , []bundlePane , bool ) {
2083- return handleProcessingTimeTimer (ss , em , emNow , func (e element , toProcess []element , holdsInBundle map [mtime.Time ]int , panesInBundle []bundlePane ) ([]element , []bundlePane ) {
2088+ func (* aggregateStageKind ) buildProcessingTimeBundle (ss * stageState , em * ElementManager , emNow mtime.Time ) (elementHeap , mtime.Time , set [string ], map [mtime.Time ]int , []bundlePane , bool , int ) {
2089+ return handleProcessingTimeTimer (ss , em , emNow , func (e element , toProcess []element , holdsInBundle map [mtime.Time ]int , panesInBundle []bundlePane ) ([]element , []bundlePane , int ) {
20842090 // Different from `buildProcessingTimeBundle` for stateful stage,
20852091 // triggers don't hold back the watermark, so no holds are in the triggered bundle.
2092+ var pendingAdjustment int
2093+ var elems []element
20862094 state := ss .state [LinkID {}][e .window ][string (e .keyBytes )]
20872095 endOfWindowReached := e .window .MaxTimestamp () < ss .input
20882096 ready := ss .strat .IsTriggerReady (triggerInput {
@@ -2095,22 +2103,22 @@ func (*aggregateStageKind) buildProcessingTimeBundle(ss *stageState, em *Element
20952103 state .Pane = computeNextTriggeredPane (state .Pane , endOfWindowReached )
20962104
20972105 // We're going to process this trigger!
2098- elems , _ : = ss .buildTriggeredBundle (em , string (e .keyBytes ), e .window )
2106+ elems , pendingAdjustment = ss .buildTriggeredBundle (em , string (e .keyBytes ), e .window )
20992107 toProcess = append (toProcess , elems ... )
21002108
21012109 ss .state [LinkID {}][e .window ][string (e .keyBytes )] = state
21022110
21032111 panesInBundle = append (panesInBundle , bundlePane {})
21042112 }
21052113
2106- return toProcess , panesInBundle
2114+ return toProcess , panesInBundle , pendingAdjustment
21072115 })
21082116}
21092117
21102118// buildProcessingTimeBundle for stateless stages is not supposed to be called currently
2111- func (* ordinaryStageKind ) buildProcessingTimeBundle (ss * stageState , em * ElementManager , emNow mtime.Time ) (elementHeap , mtime.Time , set [string ], map [mtime.Time ]int , []bundlePane , bool ) {
2119+ func (* ordinaryStageKind ) buildProcessingTimeBundle (ss * stageState , em * ElementManager , emNow mtime.Time ) (elementHeap , mtime.Time , set [string ], map [mtime.Time ]int , []bundlePane , bool , int ) {
21122120 slog .Error ("ordinary stages can't have processing time elements" )
2113- return nil , mtime .MinTimestamp , nil , nil , nil , false
2121+ return nil , mtime .MinTimestamp , nil , nil , nil , false , 0
21142122}
21152123
21162124// makeInProgressBundle is common code to store a set of elements as a bundle in progress.
0 commit comments