Skip to content

Commit b3cd953

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

1 file changed

Lines changed: 33 additions & 77 deletions

File tree

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

Lines changed: 33 additions & 77 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) []element) (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+
toProcess = processTimerFn(e, toProcess, holdsInBundle)
20342033
}
20352034

20362035
nextTime = ss.processingTimeTimers.Peek()
@@ -2054,83 +2053,40 @@ 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) []element {
2058+
holdsInBundle[e.holdTimestamp]++
2059+
// We're going to process this timer!
2060+
toProcess = append(toProcess, e)
2061+
return toProcess
2062+
})
20602063
}
20612064

20622065
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-
}
2113-
}
2114-
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)
2066+
return handleProcessingTimeTimer(ss, em, emNow, func(e element, toProcess []element, holdsInBundle map[mtime.Time]int) []element {
2067+
// TODO: how to deal with watermark holds for this implicit processing time timer
2068+
// holdsInBundle[e.holdTimestamp]++
2069+
state := ss.state[LinkID{}][e.window][string(e.keyBytes)]
2070+
endOfWindowReached := e.window.MaxTimestamp() < ss.input
2071+
ready := ss.strat.IsTriggerReady(triggerInput{
2072+
newElementCount: 0,
2073+
endOfWindowReached: endOfWindowReached,
2074+
emNow: emNow,
2075+
}, &state)
2076+
2077+
if ready {
2078+
// We're going to process this trigger!
2079+
elems, _ := ss.buildTriggeredBundle(em, string(e.keyBytes), e.window)
2080+
toProcess = append(toProcess, elems...)
2081+
}
2082+
2083+
return toProcess
2084+
})
2085+
}
21322086

2133-
return toProcess, minTs, newKeys, holdsInBundle, stillSchedulable
2087+
func (*ordinaryStageKind) buildProcessingTimeBundle(ss *stageState, em *ElementManager, emNow mtime.Time) (elementHeap, mtime.Time, set[string], map[mtime.Time]int, bool) {
2088+
slog.Error("ordinary stages can't have processing time elements")
2089+
return nil, mtime.MinTimestamp, nil, nil, false
21342090
}
21352091

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

0 commit comments

Comments
 (0)