1use std::collections::{BTreeMap, VecDeque};
18use std::sync::Arc;
19use std::sync::atomic::{AtomicBool, Ordering};
20
21use common_telemetry::info;
22use dfir_rs::scheduled::graph::Dfir;
23use enum_as_inner::EnumAsInner;
24use snafu::ensure;
25use tokio::sync::{Mutex, broadcast, mpsc, oneshot};
26
27use crate::adapter::FlowId;
28use crate::compute::{Context, DataflowState, ErrCollector};
29use crate::error::{Error, FlowAlreadyExistSnafu, InternalSnafu, UnexpectedSnafu};
30use crate::expr::{Batch, GlobalId};
31use crate::plan::TypedPlan;
32use crate::repr::{self, DiffRow};
33
34pub type SharedBuf = Arc<Mutex<VecDeque<DiffRow>>>;
35
36type ReqId = usize;
37
38pub fn create_worker<'a>() -> (WorkerHandle, Worker<'a>) {
40 let (itc_client, itc_server) = create_inter_thread_call();
41 let worker_handle = WorkerHandle {
42 itc_client,
43 shutdown: AtomicBool::new(false),
44 };
45 let worker = Worker {
46 task_states: BTreeMap::new(),
47 itc_server: Arc::new(Mutex::new(itc_server)),
48 };
49 (worker_handle, worker)
50}
51
52pub(crate) struct ActiveDataflowState<'subgraph> {
54 df: Dfir<'subgraph>,
55 state: DataflowState,
56 err_collector: ErrCollector,
57}
58
59impl std::fmt::Debug for ActiveDataflowState<'_> {
60 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
61 f.debug_struct("ActiveDataflowState")
62 .field("df", &"<Dfir>")
63 .field("state", &self.state)
64 .field("err_collector", &self.err_collector)
65 .finish()
66 }
67}
68
69impl Default for ActiveDataflowState<'_> {
70 fn default() -> Self {
71 ActiveDataflowState {
72 df: Dfir::new(),
73 state: DataflowState::default(),
74 err_collector: ErrCollector::default(),
75 }
76 }
77}
78
79impl<'subgraph> ActiveDataflowState<'subgraph> {
80 pub fn new_ctx<'ctx>(&'ctx mut self, global_id: GlobalId) -> Context<'ctx, 'subgraph>
82 where
83 'subgraph: 'ctx,
84 {
85 Context {
86 id: global_id,
87 df: &mut self.df,
88 compute_state: &mut self.state,
89 err_collector: self.err_collector.clone(),
90 input_collection: Default::default(),
91 local_scope: Default::default(),
92 input_collection_batch: Default::default(),
93 local_scope_batch: Default::default(),
94 }
95 }
96
97 pub fn set_current_ts(&mut self, ts: repr::Timestamp) {
98 self.state.set_current_ts(ts);
99 }
100
101 pub fn set_last_exec_time(&mut self, ts: repr::Timestamp) {
102 self.state.set_last_exec_time(ts);
103 }
104
105 pub fn run_available(&mut self) -> bool {
109 self.state.run_available_with_schedule(&mut self.df)
110 }
111}
112
113#[derive(Debug)]
114pub struct WorkerHandle {
115 itc_client: InterThreadCallClient,
116 shutdown: AtomicBool,
117}
118
119impl WorkerHandle {
120 pub async fn create_flow(&self, create_reqs: Request) -> Result<Option<FlowId>, Error> {
122 ensure!(
123 matches!(create_reqs, Request::Create { .. }),
124 InternalSnafu {
125 reason: format!(
126 "Flow Node/Worker itc failed, expect Request::Create, found {create_reqs:?}"
127 ),
128 }
129 );
130
131 let ret = self.itc_client.call_with_resp(create_reqs).await?;
132 ret.into_create().map_err(|ret| {
133 InternalSnafu {
134 reason: format!(
135 "Flow Node/Worker itc failed, expect Response::Create, found {ret:?}"
136 ),
137 }
138 .build()
139 })?
140 }
141
142 pub async fn remove_flow(&self, flow_id: FlowId) -> Result<bool, Error> {
144 let req = Request::Remove { flow_id };
145
146 let ret = self.itc_client.call_with_resp(req).await?;
147
148 ret.into_remove().map_err(|ret| {
149 InternalSnafu {
150 reason: format!("Flow Node/Worker failed, expect Response::Remove, found {ret:?}"),
151 }
152 .build()
153 })
154 }
155
156 pub async fn run_available(&self, now: repr::Timestamp, blocking: bool) -> Result<(), Error> {
165 common_telemetry::trace!("Running available with blocking={}", blocking);
166 if blocking {
167 let resp = self
168 .itc_client
169 .call_with_resp(Request::RunAvail { now, blocking })
170 .await?;
171 common_telemetry::trace!("Running available with response={:?}", resp);
172 Ok(())
173 } else {
174 self.itc_client
175 .call_no_resp(Request::RunAvail { now, blocking })
176 }
177 }
178
179 pub async fn contains_flow(&self, flow_id: FlowId) -> Result<bool, Error> {
180 let req = Request::ContainTask { flow_id };
181 let ret = self.itc_client.call_with_resp(req).await?;
182
183 ret.into_contain_task().map_err(|ret| {
184 InternalSnafu {
185 reason: format!(
186 "Flow Node/Worker itc failed, expect Response::ContainTask, found {ret:?}"
187 ),
188 }
189 .build()
190 })
191 }
192
193 pub fn shutdown(&self) -> Result<(), Error> {
195 if !self.shutdown.fetch_or(true, Ordering::SeqCst) {
196 self.itc_client.call_no_resp(Request::Shutdown)
197 } else {
198 UnexpectedSnafu {
199 reason: "Worker already shutdown",
200 }
201 .fail()
202 }
203 }
204
205 pub async fn get_full_flow_stat(
206 &self,
207 ) -> Result<
208 (
209 BTreeMap<FlowId, usize>,
210 BTreeMap<FlowId, i64>,
211 BTreeMap<FlowId, i64>,
212 ),
213 Error,
214 > {
215 let ret = self
216 .itc_client
217 .call_with_resp(Request::QueryFullFlowStat)
218 .await?;
219 ret.into_query_full_flow_stat().map_err(|ret| {
220 InternalSnafu {
221 reason: format!(
222 "Flow Node/Worker get_full_flow_stat failed, expected Response::QueryFullFlowStat, found {ret:?}"
223 ),
224 }
225 .build()
226 })
227 }
228}
229
230impl Drop for WorkerHandle {
231 fn drop(&mut self) {
232 if let Err(ret) = self.shutdown() {
233 common_telemetry::error!(
234 ret;
235 "While dropping Worker Handle, failed to shutdown worker, worker might be in inconsistent state."
236 );
237 } else {
238 info!("Flow Worker shutdown due to Worker Handle dropped.")
239 }
240 }
241}
242
243#[derive(Debug)]
245pub struct Worker<'subgraph> {
246 pub(crate) task_states: BTreeMap<FlowId, ActiveDataflowState<'subgraph>>,
248 itc_server: Arc<Mutex<InterThreadCallServer>>,
249}
250
251impl<'s> Worker<'s> {
252 #[allow(clippy::too_many_arguments)]
253 pub fn create_flow(
254 &mut self,
255 flow_id: FlowId,
256 plan: TypedPlan,
257 sink_id: GlobalId,
258 sink_sender: mpsc::UnboundedSender<Batch>,
259 source_ids: &[GlobalId],
260 src_recvs: Vec<broadcast::Receiver<Batch>>,
261 expire_after: Option<repr::Duration>,
263 or_replace: bool,
264 create_if_not_exists: bool,
265 err_collector: ErrCollector,
266 ) -> Result<Option<FlowId>, Error> {
267 let already_exist = self.task_states.contains_key(&flow_id);
268 match (create_if_not_exists, or_replace, already_exist) {
269 (_, true, true) => {
271 info!("Replacing flow with id={}", flow_id);
272 }
273 (false, false, true) => FlowAlreadyExistSnafu { id: flow_id }.fail()?,
274 (true, false, true) => {
276 info!("Flow with id={} already exists, do nothing", flow_id);
277 return Ok(None);
278 }
279 (_, _, false) => (),
281 }
282
283 let mut cur_task_state = ActiveDataflowState::<'s> {
284 err_collector,
285 ..Default::default()
286 };
287 cur_task_state.state.set_expire_after(expire_after);
288
289 {
290 let mut ctx = cur_task_state.new_ctx(sink_id);
291 for (source_id, src_recv) in source_ids.iter().zip(src_recvs) {
292 let bundle = ctx.render_source_batch(src_recv)?;
293 ctx.insert_global_batch(*source_id, bundle);
294 }
295
296 let rendered = ctx.render_plan_batch(plan)?;
297 ctx.render_unbounded_sink_batch(rendered, sink_sender);
298 }
299 self.task_states.insert(flow_id, cur_task_state);
300 Ok(Some(flow_id))
301 }
302
303 pub fn remove_flow(&mut self, flow_id: FlowId) -> bool {
305 self.task_states.remove(&flow_id).is_some()
306 }
307
308 pub fn run(&mut self) {
310 loop {
311 let (req, ret_tx) = if let Some(ret) = self.itc_server.blocking_lock().blocking_recv() {
312 ret
313 } else {
314 common_telemetry::error!(
315 "Worker's itc server has been closed unexpectedly, shutting down worker now."
316 );
317 break;
318 };
319
320 let ret = self.handle_req(req);
321 match (ret, ret_tx) {
322 (Ok(Some(resp)), Some(ret_tx)) => {
323 if let Err(err) = ret_tx.send(resp) {
324 common_telemetry::error!(
325 err;
326 "Result receiver is dropped, can't send result"
327 );
328 };
329 }
330 (Ok(None), None) => continue,
331 (Ok(Some(resp)), None) => {
332 common_telemetry::error!(
333 "Expect no result for current request, but found {resp:?}"
334 )
335 }
336 (Ok(None), Some(_)) => {
337 common_telemetry::error!("Expect result for current request, but found nothing")
338 }
339 (Err(()), _) => {
340 break;
341 }
342 }
343 }
344 }
345
346 pub fn run_tick(&mut self, now: repr::Timestamp) {
349 for (_flow_id, task_state) in self.task_states.iter_mut() {
350 task_state.set_current_ts(now);
351 task_state.set_last_exec_time(now);
352 task_state.run_available();
353 }
354 }
355 fn handle_req(&mut self, req: Request) -> Result<Option<Response>, ()> {
359 let ret = match req {
360 Request::Create {
361 flow_id,
362 plan,
363 sink_id,
364 sink_sender,
365 source_ids,
366 src_recvs,
367 expire_after,
368 or_replace,
369 create_if_not_exists,
370 err_collector,
371 } => {
372 let task_create_result = self.create_flow(
373 flow_id,
374 plan,
375 sink_id,
376 sink_sender,
377 &source_ids,
378 src_recvs,
379 expire_after,
380 or_replace,
381 create_if_not_exists,
382 err_collector,
383 );
384 Some(Response::Create {
385 result: task_create_result,
386 })
387 }
388 Request::Remove { flow_id } => {
389 let ret = self.remove_flow(flow_id);
390 Some(Response::Remove { result: ret })
391 }
392 Request::RunAvail { now, blocking } => {
393 self.run_tick(now);
394 if blocking {
395 Some(Response::RunAvail)
396 } else {
397 None
398 }
399 }
400 Request::ContainTask { flow_id } => {
401 let ret = self.task_states.contains_key(&flow_id);
402 Some(Response::ContainTask { result: ret })
403 }
404 Request::Shutdown => return Err(()),
405 Request::QueryFullFlowStat => {
406 let mut state_size = BTreeMap::new();
407 let mut last_exec_time_map = BTreeMap::new();
408 let mut start_time_map = BTreeMap::new();
409 for (flow_id, task_state) in self.task_states.iter() {
410 state_size.insert(*flow_id, task_state.state.get_state_size());
411 if let Some(t) = task_state.state.last_exec_time() {
412 last_exec_time_map.insert(*flow_id, t);
413 }
414 if let Some(t) = task_state.state.start_time() {
415 start_time_map.insert(*flow_id, t);
416 }
417 }
418 Some(Response::QueryFullFlowStat {
419 state_size,
420 last_exec_time_map,
421 start_time_map,
422 })
423 }
424 };
425 Ok(ret)
426 }
427}
428
429#[derive(Debug, EnumAsInner)]
430pub enum Request {
431 Create {
432 flow_id: FlowId,
433 plan: TypedPlan,
434 sink_id: GlobalId,
435 sink_sender: mpsc::UnboundedSender<Batch>,
436 source_ids: Vec<GlobalId>,
437 src_recvs: Vec<broadcast::Receiver<Batch>>,
438 expire_after: Option<repr::Duration>,
439 or_replace: bool,
440 create_if_not_exists: bool,
441 err_collector: ErrCollector,
442 },
443 Remove {
444 flow_id: FlowId,
445 },
446 RunAvail {
448 now: repr::Timestamp,
449 blocking: bool,
450 },
451 ContainTask {
452 flow_id: FlowId,
453 },
454 Shutdown,
455 QueryFullFlowStat,
456}
457
458#[derive(Debug, EnumAsInner)]
459enum Response {
460 Create {
461 result: Result<Option<FlowId>, Error>,
462 },
464 Remove {
465 result: bool,
466 },
467 ContainTask {
468 result: bool,
469 },
470 RunAvail,
471 QueryFullFlowStat {
472 state_size: BTreeMap<FlowId, usize>,
473 last_exec_time_map: BTreeMap<FlowId, i64>,
474 start_time_map: BTreeMap<FlowId, i64>,
475 },
476}
477
478fn create_inter_thread_call() -> (InterThreadCallClient, InterThreadCallServer) {
479 let (arg_send, arg_recv) = mpsc::unbounded_channel();
480 let client = InterThreadCallClient {
481 arg_sender: arg_send,
482 };
483 let server = InterThreadCallServer { arg_recv };
484 (client, server)
485}
486
487#[derive(Debug)]
488struct InterThreadCallClient {
489 arg_sender: mpsc::UnboundedSender<(Request, Option<oneshot::Sender<Response>>)>,
490}
491
492impl InterThreadCallClient {
493 fn call_no_resp(&self, req: Request) -> Result<(), Error> {
495 self.arg_sender.send((req, None)).map_err(from_send_error)
496 }
497
498 async fn call_with_resp(&self, req: Request) -> Result<Response, Error> {
500 let (tx, rx) = oneshot::channel();
501 self.arg_sender
502 .send((req, Some(tx)))
503 .map_err(from_send_error)?;
504 rx.await.map_err(|_| {
505 InternalSnafu {
506 reason: "Sender is dropped",
507 }
508 .build()
509 })
510 }
511}
512
513#[derive(Debug)]
514struct InterThreadCallServer {
515 pub arg_recv: mpsc::UnboundedReceiver<(Request, Option<oneshot::Sender<Response>>)>,
516}
517
518impl InterThreadCallServer {
519 pub async fn recv(&mut self) -> Option<(Request, Option<oneshot::Sender<Response>>)> {
520 self.arg_recv.recv().await
521 }
522
523 pub fn blocking_recv(&mut self) -> Option<(Request, Option<oneshot::Sender<Response>>)> {
524 self.arg_recv.blocking_recv()
525 }
526}
527
528fn from_send_error<T>(err: mpsc::error::SendError<T>) -> Error {
529 InternalSnafu {
530 reason: format!(
532 "Worker's receiver channel have been closed unexpected: {}",
533 err
534 ),
535 }
536 .build()
537}
538
539#[cfg(test)]
540mod test {
541 use tokio::sync::oneshot;
542
543 use super::*;
544 use crate::expr::Id;
545 use crate::plan::Plan;
546 use crate::repr::RelationType;
547
548 #[test]
549 fn drop_handle() {
550 let (tx, rx) = oneshot::channel();
551 let worker_thread_handle = std::thread::spawn(move || {
552 let (handle, mut worker) = create_worker();
553 tx.send(handle).unwrap();
554 worker.run();
555 });
556 let handle = rx.blocking_recv().unwrap();
557 drop(handle);
558 worker_thread_handle.join().unwrap();
559 }
560
561 #[tokio::test]
562 pub async fn test_simple_get_with_worker_and_handle() {
563 let (tx, rx) = oneshot::channel();
564 let worker_thread_handle = std::thread::spawn(move || {
565 let (handle, mut worker) = create_worker();
566 tx.send(handle).unwrap();
567 worker.run();
568 });
569 let handle = rx.await.unwrap();
570 let src_ids = vec![GlobalId::User(1)];
571 let (tx, rx) = broadcast::channel::<Batch>(1024);
572 let (sink_tx, mut sink_rx) = mpsc::unbounded_channel::<Batch>();
573 let (flow_id, plan) = (
574 1,
575 TypedPlan {
576 plan: Plan::Get {
577 id: Id::Global(GlobalId::User(1)),
578 },
579 schema: RelationType::new(vec![]).into_unnamed(),
580 },
581 );
582 let create_reqs = Request::Create {
583 flow_id,
584 plan,
585 sink_id: GlobalId::User(1),
586 sink_sender: sink_tx,
587 source_ids: src_ids,
588 src_recvs: vec![rx],
589 expire_after: None,
590 or_replace: false,
591 create_if_not_exists: true,
592 err_collector: ErrCollector::default(),
593 };
594 assert_eq!(
595 handle.create_flow(create_reqs).await.unwrap(),
596 Some(flow_id)
597 );
598 tx.send(Batch::empty()).unwrap();
599 handle.run_available(0, true).await.unwrap();
600 let (state_size, _, _) = handle.get_full_flow_stat().await.unwrap();
601 assert_eq!(state_size.len(), 1);
602 assert_eq!(sink_rx.recv().await.unwrap(), Batch::empty());
603 drop(handle);
604 worker_thread_handle.join().unwrap();
605 }
606}