Skip to content

Commit fe01a3d

Browse files
committed
Consolidate the buildProcessingTimeBundle for stateful and aggregate kinds into one code path.
1 parent 3b1db11 commit fe01a3d

1 file changed

Lines changed: 29 additions & 76 deletions

File tree

sdks/go/pkg/beam/runners/prism/internal/engine/elementmanager.go

Lines changed: 29 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -1985,7 +1985,8 @@ func (ss *stageState) startProcessingTimeBundle(em *ElementManager, emNow mtime.
19851985
return bundID, true, stillSchedulable
19861986
}
19871987

1988-
func (*statefulStageKind) buildProcessingTimeBundle(ss *stageState, em *ElementManager, emNow mtime.Time) (elementHeap, mtime.Time, set[string], map[mtime.Time]int, bool) {
1988+
func handleProcessingTimeTimer(ss *stageState, em *ElementManager, emNow mtime.Time,
1989+
processTimerFn func(e element, toProcess []element, holdsInBundle map[mtime.Time]int)) (elementHeap, mtime.Time, set[string], map[mtime.Time]int, bool) {
19891990
// TODO: Determine if it's possible and a good idea to treat all EventTime processing as a MinTime
19901991
// Special Case for ProcessingTime handling.
19911992
// Eg. Always queue EventTime elements at minTime.
@@ -2027,10 +2028,8 @@ func (*statefulStageKind) buildProcessingTimeBundle(ss *stageState, em *ElementM
20272028
if e.timestamp < minTs {
20282029
minTs = e.timestamp
20292030
}
2030-
holdsInBundle[e.holdTimestamp]++
20312031

2032-
// We're going to process this timer!
2033-
toProcess = append(toProcess, e)
2032+
processTimerFn(e, toProcess, holdsInBundle)
20342033
}
20352034

20362035
nextTime = ss.processingTimeTimers.Peek()
@@ -2054,83 +2053,37 @@ func (*statefulStageKind) buildProcessingTimeBundle(ss *stageState, em *ElementM
20542053
return toProcess, minTs, newKeys, holdsInBundle, stillSchedulable
20552054
}
20562055

2057-
func (*ordinaryStageKind) buildProcessingTimeBundle(ss *stageState, em *ElementManager, emNow mtime.Time) (elementHeap, mtime.Time, set[string], map[mtime.Time]int, bool) {
2058-
slog.Error("ordinary stages can't have processing time elements")
2059-
return nil, mtime.MinTimestamp, nil, nil, false
2056+
func (*statefulStageKind) buildProcessingTimeBundle(ss *stageState, em *ElementManager, emNow mtime.Time) (elementHeap, mtime.Time, set[string], map[mtime.Time]int, bool) {
2057+
return handleProcessingTimeTimer(ss, em, emNow, func(e element, toProcess []element, holdsInBundle map[mtime.Time]int) {
2058+
holdsInBundle[e.holdTimestamp]++
2059+
// We're going to process this timer!
2060+
toProcess = append(toProcess, e)
2061+
})
20602062
}
20612063

20622064
func (*aggregateStageKind) buildProcessingTimeBundle(ss *stageState, em *ElementManager, emNow mtime.Time) (elementHeap, mtime.Time, set[string], map[mtime.Time]int, bool) {
2063-
var toProcess []element
2064-
minTs := mtime.MaxTimestamp
2065-
holdsInBundle := map[mtime.Time]int{}
2066-
2067-
var notYet []fireElement
2068-
2069-
nextTime := ss.processingTimeTimers.Peek()
2070-
keyCounts := map[string]int{}
2071-
newKeys := set[string]{}
2072-
2073-
for nextTime <= emNow {
2074-
elems := ss.processingTimeTimers.FireAt(nextTime)
2075-
for _, e := range elems {
2076-
// Check if we're already executing this timer's key.
2077-
if ss.inprogressKeys.present(string(e.keyBytes)) {
2078-
notYet = append(notYet, fireElement{firing: nextTime, timer: e})
2079-
continue
2080-
}
2081-
2082-
// If we are set to have OneKeyPerBundle, and we already have a key for this bundle, we process it later.
2083-
if len(keyCounts) > 0 && OneKeyPerBundle {
2084-
notYet = append(notYet, fireElement{firing: nextTime, timer: e})
2085-
continue
2086-
}
2087-
// If we are set to have OneElementPerKey, and we already have an element for this key we set this to process later.
2088-
if v := keyCounts[string(e.keyBytes)]; v > 0 && OneElementPerKey {
2089-
notYet = append(notYet, fireElement{firing: nextTime, timer: e})
2090-
continue
2091-
}
2092-
keyCounts[string(e.keyBytes)]++
2093-
newKeys.insert(string(e.keyBytes))
2094-
if e.timestamp < minTs {
2095-
minTs = e.timestamp
2096-
}
2097-
// TODO: how to deal with watermark holds for this implicit processing time timer
2098-
// holdsInBundle[e.holdTimestamp]++
2099-
2100-
state := ss.state[LinkID{}][e.window][string(e.keyBytes)]
2101-
endOfWindowReached := e.window.MaxTimestamp() < ss.input
2102-
ready := ss.strat.IsTriggerReady(triggerInput{
2103-
newElementCount: 0,
2104-
endOfWindowReached: endOfWindowReached,
2105-
emNow: emNow,
2106-
}, &state)
2107-
2108-
if ready {
2109-
// We're going to process this trigger!
2110-
elems, _ := ss.buildTriggeredBundle(em, string(e.keyBytes), e.window)
2111-
toProcess = append(toProcess, elems...)
2112-
}
2065+
return handleProcessingTimeTimer(ss, em, emNow, func(e element, toProcess []element, holdsInBundle map[mtime.Time]int) {
2066+
// TODO: how to deal with watermark holds for this implicit processing time timer
2067+
// holdsInBundle[e.holdTimestamp]++
2068+
state := ss.state[LinkID{}][e.window][string(e.keyBytes)]
2069+
endOfWindowReached := e.window.MaxTimestamp() < ss.input
2070+
ready := ss.strat.IsTriggerReady(triggerInput{
2071+
newElementCount: 0,
2072+
endOfWindowReached: endOfWindowReached,
2073+
emNow: emNow,
2074+
}, &state)
2075+
2076+
if ready {
2077+
// We're going to process this trigger!
2078+
elems, _ := ss.buildTriggeredBundle(em, string(e.keyBytes), e.window)
2079+
toProcess = append(toProcess, elems...)
21132080
}
2081+
})
2082+
}
21142083

2115-
nextTime = ss.processingTimeTimers.Peek()
2116-
if nextTime == mtime.MaxTimestamp {
2117-
// Escape the loop if there are no more events.
2118-
break
2119-
}
2120-
}
2121-
2122-
// Reschedule unfired timers.
2123-
notYetHolds := map[mtime.Time]int{}
2124-
for _, v := range notYet {
2125-
ss.processingTimeTimers.Persist(v.firing, v.timer, notYetHolds)
2126-
em.processTimeEvents.Schedule(v.firing, ss.ID)
2127-
em.wakeUpAt(v.firing)
2128-
}
2129-
2130-
// Add a refresh if there are still processing time events to process.
2131-
stillSchedulable := (nextTime < emNow && nextTime != mtime.MaxTimestamp || len(notYet) > 0)
2132-
2133-
return toProcess, minTs, newKeys, holdsInBundle, stillSchedulable
2084+
func (*ordinaryStageKind) buildProcessingTimeBundle(ss *stageState, em *ElementManager, emNow mtime.Time) (elementHeap, mtime.Time, set[string], map[mtime.Time]int, bool) {
2085+
slog.Error("ordinary stages can't have processing time elements")
2086+
return nil, mtime.MinTimestamp, nil, nil, false
21342087
}
21352088

21362089
// makeInProgressBundle is common code to store a set of elements as a bundle in progress.

0 commit comments

Comments
 (0)