1010// See the License for the specific language governing permissions and
1111// limitations under the License.
1212
13- use crate :: runtime:: streaming:: memory:: MemoryPool ;
14- use crate :: runtime:: streaming:: network:: endpoint:: PhysicalSender ;
15- use crate :: runtime:: streaming:: protocol:: event:: StreamEvent ;
16- use crate :: runtime:: streaming:: protocol:: event:: TrackedEvent ;
13+ use std:: sync:: Arc ;
14+ use std:: time:: { Duration , SystemTime } ;
1715
16+ use anyhow:: { Context , Result } ;
1817use arrow_array:: RecordBatch ;
19- use std:: sync:: Arc ;
20- use std:: time:: Duration ;
2118
22- /// 与单个子任务绑定的运行时参数(可由 `TaskContext::new` 默认填充,后续可扩展为从 Job 配置注入)。
19+ use crate :: runtime:: streaming:: memory:: MemoryPool ;
20+ use crate :: runtime:: streaming:: network:: endpoint:: PhysicalSender ;
21+ use crate :: runtime:: streaming:: protocol:: event:: { StreamEvent , TrackedEvent } ;
22+
2323#[ derive( Debug , Clone ) ]
2424pub struct TaskContextConfig {
25- /// Source 在无数据(`SourceEvent::Idle`)时的退避休眠时长。
2625 pub source_idle_timeout : Duration ,
2726}
2827
@@ -34,110 +33,168 @@ impl Default for TaskContextConfig {
3433 }
3534}
3635
36+ /// Task execution context.
37+ ///
38+ /// Acts as the sole bridge between operators and engine infrastructure (network, memory,
39+ /// configuration) for a single subtask.
3740pub struct TaskContext {
41+ /// Job identifier.
3842 pub job_id : String ,
39- pub vertex_id : u32 ,
40- pub subtask_idx : u32 ,
43+ /// Logical pipeline (vertex) index within the job graph.
44+ pub pipeline_id : u32 ,
45+ /// This subtask's index within the pipeline's parallelism.
46+ pub subtask_index : u32 ,
47+ /// Number of parallel subtasks for this pipeline.
4148 pub parallelism : u32 ,
4249
43- pub outboxes : Vec < PhysicalSender > ,
50+ /// Precomputed display string for high-frequency logging without per-call allocation.
51+ task_name : String ,
4452
53+ /// Downstream physical senders (outbound edges).
54+ downstream_senders : Vec < PhysicalSender > ,
55+
56+ /// Global memory pool for back-pressure and accounting.
4557 memory_pool : Arc < MemoryPool > ,
4658
47- current_watermark : Option < std:: time:: SystemTime > ,
59+ /// Latest aligned event-time watermark for this subtask.
60+ current_watermark : Option < SystemTime > ,
4861
62+ /// Subtask-level tunables.
4963 config : TaskContextConfig ,
5064}
5165
5266impl TaskContext {
5367 pub fn new (
5468 job_id : String ,
55- vertex_id : u32 ,
56- subtask_idx : u32 ,
69+ pipeline_id : u32 ,
70+ subtask_index : u32 ,
5771 parallelism : u32 ,
58- outboxes : Vec < PhysicalSender > ,
72+ downstream_senders : Vec < PhysicalSender > ,
5973 memory_pool : Arc < MemoryPool > ,
6074 ) -> Self {
75+ let task_name = format ! (
76+ "Task-[{}]-Pipe[{}]-Sub[{}/{}]" ,
77+ job_id, pipeline_id, subtask_index, parallelism
78+ ) ;
79+
6180 Self {
6281 job_id,
63- vertex_id ,
64- subtask_idx ,
82+ pipeline_id ,
83+ subtask_index ,
6584 parallelism,
66- outboxes,
85+ task_name,
86+ downstream_senders,
6787 memory_pool,
6888 current_watermark : None ,
6989 config : TaskContextConfig :: default ( ) ,
7090 }
7191 }
7292
93+ #[ inline]
7394 pub fn config ( & self ) -> & TaskContextConfig {
7495 & self . config
7596 }
7697
77- // ========================================================================
78- // ========================================================================
98+ #[ inline]
99+ pub fn task_name ( & self ) -> & str {
100+ & self . task_name
101+ }
102+
103+ // -------------------------------------------------------------------------
104+ // Watermark
105+ // -------------------------------------------------------------------------
79106
80- pub fn last_present_watermark ( & self ) -> Option < std:: time:: SystemTime > {
107+ #[ inline]
108+ pub fn current_watermark ( & self ) -> Option < SystemTime > {
81109 self . current_watermark
82110 }
83111
84- pub fn advance_watermark ( & mut self , watermark : std :: time :: SystemTime ) {
112+ pub fn advance_watermark ( & mut self , watermark : SystemTime ) {
85113 if let Some ( current) = self . current_watermark {
86- if watermark > current {
87- self . current_watermark = Some ( watermark) ;
88- }
114+ self . current_watermark = Some ( current. max ( watermark) ) ;
89115 } else {
90116 self . current_watermark = Some ( watermark) ;
91117 }
92118 }
93119
94- // ========================================================================
95- // ========================================================================
96-
97- pub fn task_identity ( & self ) -> String {
98- format ! (
99- "Job[{}], Vertex[{}], Subtask[{}/{}]" ,
100- self . job_id, self . vertex_id, self . subtask_idx, self . parallelism
101- )
102- }
103-
104- // ========================================================================
105- // ========================================================================
120+ // -------------------------------------------------------------------------
121+ // Data emission
122+ // -------------------------------------------------------------------------
106123
107- pub async fn collect ( & self , batch : RecordBatch ) -> anyhow:: Result < ( ) > {
108- if self . outboxes . is_empty ( ) {
124+ /// Fan-out a data batch to all downstreams (forward / broadcast).
125+ pub async fn collect ( & self , batch : RecordBatch ) -> Result < ( ) > {
126+ if self . downstream_senders . is_empty ( ) {
109127 return Ok ( ( ) ) ;
110128 }
111129
112130 let bytes_required = batch. get_array_memory_size ( ) ;
113131 let ticket = self . memory_pool . request_memory ( bytes_required) . await ;
114132 let tracked_event = TrackedEvent :: new ( StreamEvent :: Data ( batch) , Some ( ticket) ) ;
115133
116- for outbox in & self . outboxes {
117- outbox. send ( tracked_event. clone ( ) ) . await ?;
118- }
119- Ok ( ( ) )
134+ self . broadcast_event ( tracked_event) . await
120135 }
121136
122- pub async fn collect_keyed ( & self , key_hash : u64 , batch : RecordBatch ) -> anyhow:: Result < ( ) > {
123- if self . outboxes . is_empty ( ) {
137+ /// Route a batch to one downstream by hash partitioning (shuffle).
138+ pub async fn collect_keyed ( & self , key_hash : u64 , batch : RecordBatch ) -> Result < ( ) > {
139+ let num_downstreams = self . downstream_senders . len ( ) ;
140+ if num_downstreams == 0 {
124141 return Ok ( ( ) ) ;
125142 }
126143
127144 let bytes_required = batch. get_array_memory_size ( ) ;
128145 let ticket = self . memory_pool . request_memory ( bytes_required) . await ;
129- let tracked_event = TrackedEvent :: new ( StreamEvent :: Data ( batch) , Some ( ticket) ) ;
146+ let event = TrackedEvent :: new ( StreamEvent :: Data ( batch) , Some ( ticket) ) ;
147+
148+ let target_idx = ( key_hash as usize ) % num_downstreams;
149+
150+ self . downstream_senders [ target_idx]
151+ . send ( event)
152+ . await
153+ . with_context ( || {
154+ format ! (
155+ "{} failed to route keyed data to downstream index {}" ,
156+ self . task_name, target_idx
157+ )
158+ } ) ?;
130159
131- let target_idx = ( key_hash as usize ) % self . outboxes . len ( ) ;
132- self . outboxes [ target_idx] . send ( tracked_event) . await ?;
133160 Ok ( ( ) )
134161 }
135162
136- pub async fn broadcast ( & self , event : StreamEvent ) -> anyhow:: Result < ( ) > {
163+ /// Broadcast a control event (watermark, barrier, end-of-stream).
164+ pub async fn broadcast ( & self , event : StreamEvent ) -> Result < ( ) > {
165+ if self . downstream_senders . is_empty ( ) {
166+ return Ok ( ( ) ) ;
167+ }
137168 let tracked_event = TrackedEvent :: control ( event) ;
138- for outbox in & self . outboxes {
139- outbox. send ( tracked_event. clone ( ) ) . await ?;
169+ self . broadcast_event ( tracked_event) . await
170+ }
171+
172+ // -------------------------------------------------------------------------
173+ // Internal dispatch
174+ // -------------------------------------------------------------------------
175+
176+ async fn broadcast_event ( & self , event : TrackedEvent ) -> Result < ( ) > {
177+ let mut iter = self . downstream_senders . iter ( ) . enumerate ( ) . peekable ( ) ;
178+
179+ while let Some ( ( idx, sender) ) = iter. next ( ) {
180+ if iter. peek ( ) . is_some ( ) {
181+ sender. send ( event. clone ( ) ) . await . with_context ( || {
182+ format ! (
183+ "{} failed to broadcast event to downstream index {}" ,
184+ self . task_name, idx
185+ )
186+ } ) ?;
187+ } else {
188+ sender. send ( event) . await . with_context ( || {
189+ format ! (
190+ "{} failed to send final event to downstream index {}" ,
191+ self . task_name, idx
192+ )
193+ } ) ?;
194+ break ;
195+ }
140196 }
197+
141198 Ok ( ( ) )
142199 }
143200}
0 commit comments