1#![warn(unused_imports)]
18
19use std::collections::BTreeMap;
20use std::sync::Arc;
21use std::time::{Duration, Instant, SystemTime};
22
23use api::v1::{RowDeleteRequest, RowDeleteRequests, RowInsertRequest, RowInsertRequests};
24use common_base::memory_limit::MemoryLimit;
25use common_config::Configurable;
26use common_error::ext::BoxedError;
27use common_meta::key::TableMetadataManagerRef;
28use common_options::memory::MemoryOptions;
29use common_runtime::JoinHandle;
30use common_stat::get_total_cpu_cores;
31use common_telemetry::logging::{LoggingOptions, TracingOptions};
32use common_telemetry::{debug, info, trace};
33use datatypes::schema::ColumnSchema;
34use datatypes::value::Value;
35use greptime_proto::v1;
36use itertools::{EitherOrBoth, Itertools};
37use meta_client::MetaClientOptions;
38use query::QueryEngine;
39use query::options::QueryOptions;
40use serde::{Deserialize, Serialize};
41use servers::grpc::GrpcOptions;
42use servers::http::HttpOptions;
43use session::context::QueryContext;
44use snafu::{OptionExt, ResultExt, ensure};
45use store_api::storage::{ConcreteDataType, RegionId};
46use table::metadata::TableId;
47use tokio::sync::broadcast::error::TryRecvError;
48use tokio::sync::{Mutex, RwLock, broadcast, watch};
49
50pub(crate) use crate::adapter::node_context::FlownodeContext;
51use crate::adapter::refill::RefillTask;
52use crate::adapter::table_source::ManagedTableSource;
53use crate::adapter::util::relation_desc_to_column_schemas_with_fallback;
54pub(crate) use crate::adapter::worker::{Worker, WorkerHandle, create_worker};
55use crate::batching_mode::BatchingModeOptions;
56use crate::compute::ErrCollector;
57use crate::df_optimizer::sql_to_flow_plan;
58use crate::error::{EvalSnafu, ExternalSnafu, InternalSnafu, InvalidQuerySnafu, UnexpectedSnafu};
59use crate::expr::Batch;
60use crate::metrics::{METRIC_FLOW_INSERT_ELAPSED, METRIC_FLOW_ROWS, METRIC_FLOW_RUN_INTERVAL_MS};
61use crate::repr::{self, BATCH_SIZE, DiffRow, RelationDesc, Row};
62use crate::{CreateFlowArgs, FlowId, TableName};
63
64pub(crate) mod flownode_impl;
65mod parse_expr;
66pub(crate) mod refill;
67mod stat;
68#[cfg(test)]
69mod tests;
70pub(crate) mod util;
71mod worker;
72
73pub(crate) mod node_context;
74pub(crate) mod table_source;
75
76use crate::FrontendInvoker;
77use crate::error::Error;
78
79fn expire_after_secs_to_millis(expire_after_secs: i64) -> Result<repr::Duration, Error> {
80 ensure!(
81 expire_after_secs >= 0,
82 InvalidQuerySnafu {
83 reason: format!("EXPIRE AFTER must be non-negative, got {expire_after_secs} seconds"),
84 }
85 );
86
87 expire_after_secs
88 .checked_mul(1_000)
89 .with_context(|| InvalidQuerySnafu {
90 reason: format!(
91 "EXPIRE AFTER value {expire_after_secs} seconds cannot be represented in milliseconds"
92 ),
93 })
94}
95
96pub const AUTO_CREATED_PLACEHOLDER_TS_COL: &str = "__ts_placeholder";
98
99pub const AUTO_CREATED_UPDATE_AT_TS_COL: &str = "update_at";
100
101#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
103#[serde(default)]
104pub struct FlowConfig {
105 pub num_workers: usize,
106 pub batching_mode: BatchingModeOptions,
107}
108
109impl Default for FlowConfig {
110 fn default() -> Self {
111 Self {
112 num_workers: (get_total_cpu_cores() / 2).max(1),
113 batching_mode: BatchingModeOptions::default(),
114 }
115 }
116}
117
118#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
120#[serde(default)]
121pub struct FlownodeOptions {
122 pub node_id: Option<u64>,
123 pub flow: FlowConfig,
124 pub grpc: GrpcOptions,
125 pub http: HttpOptions,
126 pub meta_client: Option<MetaClientOptions>,
127 pub logging: LoggingOptions,
128 pub tracing: TracingOptions,
129 pub query: QueryOptions,
130 pub memory: MemoryOptions,
131}
132
133impl Default for FlownodeOptions {
134 fn default() -> Self {
135 Self {
136 node_id: None,
137 flow: FlowConfig::default(),
138 grpc: GrpcOptions::default().with_bind_addr("127.0.0.1:3004"),
139 http: HttpOptions::default(),
140 meta_client: None,
141 logging: LoggingOptions::default(),
142 tracing: TracingOptions::default(),
143 query: QueryOptions {
146 parallelism: 1,
147 allow_query_fallback: false,
148 memory_pool_size: MemoryLimit::default(),
149 enable_per_region_metrics: false,
150 ..Default::default()
151 },
152 memory: MemoryOptions::default(),
153 }
154 }
155}
156
157impl Configurable for FlownodeOptions {
158 fn validate_sanitize(&mut self) -> common_config::error::Result<()> {
159 if self.flow.num_workers == 0 {
160 self.flow.num_workers = (get_total_cpu_cores() / 2).max(1);
161 }
162 Ok(())
163 }
164}
165
166pub type FlowStreamingEngineRef = Arc<StreamingEngine>;
168
169pub struct StreamingEngine {
174 pub worker_handles: Vec<WorkerHandle>,
177 worker_selector: Mutex<usize>,
179 pub query_engine: Arc<dyn QueryEngine>,
181 table_info_source: ManagedTableSource,
183 frontend_invoker: RwLock<Option<FrontendInvoker>>,
184 node_context: RwLock<FlownodeContext>,
186 refill_tasks: RwLock<BTreeMap<FlowId, RefillTask>>,
188 flow_err_collectors: RwLock<BTreeMap<FlowId, ErrCollector>>,
189 src_send_buf_lens: RwLock<BTreeMap<TableId, watch::Receiver<usize>>>,
190 tick_manager: FlowTickManager,
191 pub node_id: Option<u32>,
193 flush_lock: RwLock<()>,
197}
198
199impl StreamingEngine {
201 pub async fn set_frontend_invoker(&self, frontend: FrontendInvoker) {
203 *self.frontend_invoker.write().await = Some(frontend);
204 }
205
206 pub fn new(
208 node_id: Option<u32>,
209 query_engine: Arc<dyn QueryEngine>,
210 table_meta: TableMetadataManagerRef,
211 ) -> Self {
212 let srv_map = ManagedTableSource::new(
213 table_meta.table_info_manager().clone(),
214 table_meta.table_name_manager().clone(),
215 );
216 let node_context = FlownodeContext::new(Box::new(srv_map.clone()) as _);
217 let tick_manager = FlowTickManager::new();
218 let worker_handles = Vec::new();
219 StreamingEngine {
220 worker_handles,
221 worker_selector: Mutex::new(0),
222 query_engine,
223 table_info_source: srv_map,
224 frontend_invoker: RwLock::new(None),
225 node_context: RwLock::new(node_context),
226 refill_tasks: Default::default(),
227 flow_err_collectors: Default::default(),
228 src_send_buf_lens: Default::default(),
229 tick_manager,
230 node_id,
231 flush_lock: RwLock::new(()),
232 }
233 }
234
235 pub fn new_with_workers<'s>(
237 node_id: Option<u32>,
238 query_engine: Arc<dyn QueryEngine>,
239 table_meta: TableMetadataManagerRef,
240 num_workers: usize,
241 ) -> (Self, Vec<Worker<'s>>) {
242 let mut zelf = Self::new(node_id, query_engine, table_meta);
243
244 let workers: Vec<_> = (0..num_workers)
245 .map(|_| {
246 let (handle, worker) = create_worker();
247 zelf.add_worker_handle(handle);
248 worker
249 })
250 .collect();
251 (zelf, workers)
252 }
253
254 pub fn add_worker_handle(&mut self, handle: WorkerHandle) {
256 self.worker_handles.push(handle);
257 }
258}
259
260#[derive(Debug)]
261pub enum DiffRequest {
262 Insert(Vec<(Row, repr::Timestamp)>),
263 Delete(Vec<(Row, repr::Timestamp)>),
264}
265
266impl DiffRequest {
267 pub fn len(&self) -> usize {
268 match self {
269 Self::Insert(v) => v.len(),
270 Self::Delete(v) => v.len(),
271 }
272 }
273
274 pub fn is_empty(&self) -> bool {
275 self.len() == 0
276 }
277}
278
279pub fn batches_to_rows_req(batches: Vec<Batch>) -> Result<Vec<DiffRequest>, Error> {
280 let mut reqs = Vec::new();
281 for batch in batches {
282 let mut rows = Vec::with_capacity(batch.row_count());
283 for i in 0..batch.row_count() {
284 let row = batch.get_row(i).context(EvalSnafu)?;
285 rows.push((Row::new(row), 0));
286 }
287 reqs.push(DiffRequest::Insert(rows));
288 }
289 Ok(reqs)
290}
291
292impl StreamingEngine {
294 pub async fn send_writeback_requests(&self) -> Result<usize, Error> {
296 let all_reqs = self.generate_writeback_request().await?;
297 if all_reqs.is_empty() || all_reqs.iter().all(|v| v.1.is_empty()) {
298 return Ok(0);
299 }
300 let mut req_cnt = 0;
301 for (table_name, reqs) in all_reqs {
302 if reqs.is_empty() {
303 continue;
304 }
305 let (catalog, schema) = (table_name[0].clone(), table_name[1].clone());
306 let ctx = Arc::new(QueryContext::with(&catalog, &schema));
307
308 let (is_ts_placeholder, proto_schema) = match self
309 .try_fetch_existing_table(&table_name)
310 .await?
311 .context(UnexpectedSnafu {
312 reason: format!("Table not found: {}", table_name.join(".")),
313 }) {
314 Ok(r) => r,
315 Err(e) => {
316 if self
317 .table_info_source
318 .get_opt_table_id_from_name(&table_name)
319 .await?
320 .is_none()
321 {
322 common_telemetry::warn!(e; "Table `{}` no longer exists, skip writeback", table_name.join("."));
325 continue;
326 } else {
327 return Err(e);
328 }
329 }
330 };
331 let schema_len = proto_schema.len();
332
333 let total_rows = reqs.iter().map(|r| r.len()).sum::<usize>();
334 trace!(
335 "Sending {} writeback requests to table {}, reqs total rows={}",
336 reqs.len(),
337 table_name.join("."),
338 reqs.iter().map(|r| r.len()).sum::<usize>()
339 );
340
341 METRIC_FLOW_ROWS
342 .with_label_values(&["out-streaming"])
343 .inc_by(total_rows as u64);
344
345 let now = self.tick_manager.tick();
346 for req in reqs {
347 match req {
348 DiffRequest::Insert(insert) => {
349 let rows_proto: Vec<v1::Row> = insert
350 .into_iter()
351 .map(|(mut row, _ts)| {
352 if row.len() < proto_schema.len()
355 && proto_schema[row.len()].datatype
356 == greptime_proto::v1::ColumnDataType::TimestampMillisecond
357 as i32
358 {
359 row.extend([Value::from(
360 common_time::Timestamp::new_millisecond(now),
361 )]);
362 }
363 if is_ts_placeholder {
365 ensure!(
366 row.len() == schema_len - 1,
367 InternalSnafu {
368 reason: format!(
369 "Row len mismatch, expect {} got {}",
370 schema_len - 1,
371 row.len()
372 )
373 }
374 );
375 row.extend([Value::from(
376 common_time::Timestamp::new_millisecond(0),
377 )]);
378 }
379 if row.len() != proto_schema.len() {
380 UnexpectedSnafu {
381 reason: format!(
382 "Flow output row length mismatch, expect {} got {}, the columns in schema are: {:?}",
383 proto_schema.len(),
384 row.len(),
385 proto_schema.iter().map(|c|&c.column_name).collect_vec()
386 ),
387 }
388 .fail()?;
389 }
390 Ok(row.into())
391 })
392 .collect::<Result<Vec<_>, Error>>()?;
393 let table_name = table_name.last().unwrap().clone();
394 let req = RowInsertRequest {
395 table_name,
396 rows: Some(v1::Rows {
397 schema: proto_schema.clone(),
398 rows: rows_proto,
399 }),
400 };
401 req_cnt += 1;
402 self.frontend_invoker
403 .read()
404 .await
405 .as_ref()
406 .with_context(|| UnexpectedSnafu {
407 reason: "Expect a frontend invoker for flownode to write back",
408 })?
409 .row_inserts(RowInsertRequests { inserts: vec![req] }, ctx.clone())
410 .await
411 .map_err(BoxedError::new)
412 .with_context(|_| ExternalSnafu {})?;
413 }
414 DiffRequest::Delete(remove) => {
415 info!("original remove rows={:?}", remove);
416 let rows_proto: Vec<v1::Row> = remove
417 .into_iter()
418 .map(|(mut row, _ts)| {
419 row.extend(Some(Value::from(
420 common_time::Timestamp::new_millisecond(0),
421 )));
422 row.into()
423 })
424 .collect::<Vec<_>>();
425 let table_name = table_name.last().unwrap().clone();
426 let req = RowDeleteRequest {
427 table_name,
428 rows: Some(v1::Rows {
429 schema: proto_schema.clone(),
430 rows: rows_proto,
431 }),
432 };
433
434 req_cnt += 1;
435 self.frontend_invoker
436 .read()
437 .await
438 .as_ref()
439 .with_context(|| UnexpectedSnafu {
440 reason: "Expect a frontend invoker for flownode to write back",
441 })?
442 .row_deletes(RowDeleteRequests { deletes: vec![req] }, ctx.clone())
443 .await
444 .map_err(BoxedError::new)
445 .with_context(|_| ExternalSnafu {})?;
446 }
447 }
448 }
449 }
450 Ok(req_cnt)
451 }
452
453 pub async fn generate_writeback_request(
455 &self,
456 ) -> Result<BTreeMap<TableName, Vec<DiffRequest>>, Error> {
457 trace!("Start to generate writeback request");
458 let mut output = BTreeMap::new();
459 let mut total_row_count = 0;
460 for (name, sink_recv) in self
461 .node_context
462 .write()
463 .await
464 .sink_receiver
465 .iter_mut()
466 .map(|(n, (_s, r))| (n, r))
467 {
468 let mut batches = Vec::new();
469 while let Ok(batch) = sink_recv.try_recv() {
470 total_row_count += batch.row_count();
471 batches.push(batch);
472 }
473 let reqs = batches_to_rows_req(batches)?;
474 output.insert(name.clone(), reqs);
475 }
476 trace!("Prepare writeback req: total row count={}", total_row_count);
477 Ok(output)
478 }
479
480 async fn fetch_table_pk_schema(
482 &self,
483 table_name: &TableName,
484 ) -> Result<Option<(Vec<String>, Option<usize>, Vec<ColumnSchema>)>, Error> {
485 if let Some(table_id) = self
486 .table_info_source
487 .get_opt_table_id_from_name(table_name)
488 .await?
489 {
490 let table_info = self
491 .table_info_source
492 .get_table_info_value(&table_id)
493 .await?
494 .unwrap();
495 let meta = table_info.table_info.meta;
496 let schema = meta.schema.column_schemas().to_vec();
497 let primary_keys = meta
498 .primary_key_indices
499 .into_iter()
500 .map(|i| schema[i].name.clone())
501 .collect_vec();
502 let time_index = meta.schema.timestamp_index();
503 Ok(Some((primary_keys, time_index, schema)))
504 } else {
505 Ok(None)
506 }
507 }
508
509 async fn adjust_auto_created_table_schema(
514 &self,
515 schema: &RelationDesc,
516 ) -> Result<(Vec<String>, Vec<ColumnSchema>, bool), Error> {
517 let primary_keys = schema
521 .typ()
522 .keys
523 .first()
524 .map(|v| {
525 v.column_indices
526 .iter()
527 .map(|i| {
528 schema
529 .get_name(*i)
530 .clone()
531 .unwrap_or_else(|| format!("col_{i}"))
532 })
533 .collect_vec()
534 })
535 .unwrap_or_default();
536 let update_at = ColumnSchema::new(
537 AUTO_CREATED_UPDATE_AT_TS_COL,
538 ConcreteDataType::timestamp_millisecond_datatype(),
539 true,
540 );
541
542 let original_schema = relation_desc_to_column_schemas_with_fallback(schema);
543
544 let mut with_auto_added_col = original_schema.clone();
545 with_auto_added_col.push(update_at);
546
547 let no_time_index = schema.typ().time_index.is_none();
549 if no_time_index {
550 let ts_col = ColumnSchema::new(
551 AUTO_CREATED_PLACEHOLDER_TS_COL,
552 ConcreteDataType::timestamp_millisecond_datatype(),
553 true,
554 )
555 .with_time_index(true);
556 with_auto_added_col.push(ts_col);
557 }
558
559 Ok((primary_keys, with_auto_added_col, no_time_index))
560 }
561}
562
563impl StreamingEngine {
565 pub fn run_background(
567 self: Arc<Self>,
568 shutdown: Option<broadcast::Receiver<()>>,
569 ) -> JoinHandle<()> {
570 info!("Starting flownode manager's background task");
571 common_runtime::spawn_global(async move { self.run(shutdown).await })
572 }
573
574 pub async fn log_all_errors(&self) {
576 for (f_id, f_err) in self.flow_err_collectors.read().await.iter() {
577 let all_errors = f_err.get_all().await;
578 if !all_errors.is_empty() {
579 let all_errors = all_errors
580 .into_iter()
581 .map(|i| format!("{:?}", i))
582 .join("\n");
583 common_telemetry::error!("Flow {} has following errors: {}", f_id, all_errors);
584 }
585 }
586 }
587
588 pub async fn run(&self, mut shutdown: Option<broadcast::Receiver<()>>) {
592 debug!("Starting to run");
593 let default_interval = Duration::from_secs(1);
594 let mut tick_interval = tokio::time::interval(default_interval);
595 tick_interval.set_missed_tick_behavior(tokio::time::MissedTickBehavior::Burst);
597 let mut avg_spd = 0; let mut since_last_run = tokio::time::Instant::now();
599 let run_per_trace = 10;
600 let mut run_cnt = 0;
601 loop {
602 let row_cnt = self.run_available(false).await.unwrap_or_else(|err| {
604 common_telemetry::error!(err;"Run available errors");
605 0
606 });
607
608 if let Err(err) = self.send_writeback_requests().await {
609 common_telemetry::error!(err;"Send writeback request errors");
610 };
611 self.log_all_errors().await;
612
613 match &shutdown.as_mut().map(|s| s.try_recv()) {
615 Some(Ok(())) => {
616 info!("Shutdown flow's main loop");
617 break;
618 }
619 Some(Err(TryRecvError::Empty)) => (),
620 Some(Err(TryRecvError::Closed)) => {
621 common_telemetry::error!("Shutdown channel is closed");
622 break;
623 }
624 Some(Err(TryRecvError::Lagged(num))) => {
625 common_telemetry::error!(
626 "Shutdown channel is lagged by {}, meaning multiple shutdown cmd have been issued",
627 num
628 );
629 break;
630 }
631 None => (),
632 }
633
634 let wait_for = since_last_run.elapsed();
637
638 let cur_spd = row_cnt * 1000 / wait_for.as_millis().max(1) as usize;
640 avg_spd = if cur_spd > avg_spd {
642 cur_spd
643 } else {
644 (9 * avg_spd + cur_spd) / 10
645 };
646 let new_wait = BATCH_SIZE * 1000 / avg_spd.max(1); let new_wait = Duration::from_millis(new_wait as u64).min(default_interval);
648
649 if run_cnt >= run_per_trace {
652 trace!("avg_spd={} r/s, cur_spd={} r/s", avg_spd, cur_spd);
653 trace!("Wait for {} ms, row_cnt={}", new_wait.as_millis(), row_cnt);
654 run_cnt = 0;
655 } else {
656 run_cnt += 1;
657 }
658
659 METRIC_FLOW_RUN_INTERVAL_MS.set(new_wait.as_millis() as i64);
660 since_last_run = tokio::time::Instant::now();
661 tokio::select! {
662 _ = tick_interval.tick() => (),
663 _ = tokio::time::sleep(new_wait) => ()
664 }
665 }
666 self.frontend_invoker.write().await.take();
670 }
671
672 pub async fn run_available(&self, blocking: bool) -> Result<usize, Error> {
680 let mut row_cnt = 0;
681
682 let now = self.tick_manager.tick();
683 for worker in self.worker_handles.iter() {
684 worker.run_available(now, blocking).await?;
686 }
687 let flush_res = if blocking {
689 let ctx = self.node_context.read().await;
690 ctx.flush_all_sender().await
691 } else {
692 match self.node_context.try_read() {
693 Ok(ctx) => ctx.flush_all_sender().await,
694 Err(_) => return Ok(row_cnt),
695 }
696 };
697 match flush_res {
698 Ok(r) => {
699 common_telemetry::trace!("Total flushed {} rows", r);
700 row_cnt += r;
701 }
702 Err(err) => {
703 common_telemetry::error!("Flush send buf errors: {:?}", err);
704 }
705 };
706
707 Ok(row_cnt)
708 }
709
710 pub async fn handle_write_request(
712 &self,
713 region_id: RegionId,
714 rows: Vec<DiffRow>,
715 batch_datatypes: &[ConcreteDataType],
716 ) -> Result<(), Error> {
717 let rows_len = rows.len();
718 let table_id = region_id.table_id();
719 let _timer = METRIC_FLOW_INSERT_ELAPSED
720 .with_label_values(&[table_id.to_string().as_str()])
721 .start_timer();
722 self.node_context
723 .read()
724 .await
725 .send(table_id, rows, batch_datatypes)
726 .await?;
727 trace!(
728 "Handling write request for table_id={} with {} rows",
729 table_id, rows_len
730 );
731 Ok(())
732 }
733}
734
735impl StreamingEngine {
737 pub async fn remove_flow_inner(&self, flow_id: FlowId) -> Result<(), Error> {
739 for handle in self.worker_handles.iter() {
740 if handle.contains_flow(flow_id).await? {
741 handle.remove_flow(flow_id).await?;
742 break;
743 }
744 }
745 self.node_context.write().await.remove_flow(flow_id);
746 Ok(())
747 }
748
749 pub async fn create_flow_inner(&self, args: CreateFlowArgs) -> Result<Option<FlowId>, Error> {
755 let CreateFlowArgs {
756 flow_id,
757 sink_table_name,
758 source_table_ids,
759 create_if_not_exists,
760 or_replace,
761 expire_after: expire_after_secs,
762 eval_interval: _,
763 comment,
764 sql,
765 flow_options,
766 query_ctx,
767 ..
768 } = args;
769 let expire_after = expire_after_secs
770 .map(expire_after_secs_to_millis)
771 .transpose()?;
772
773 let mut node_ctx = self.node_context.write().await;
774 for source in &source_table_ids {
776 node_ctx
777 .assign_global_id_to_table(&self.table_info_source, None, Some(*source))
778 .await?;
779 }
780 node_ctx
781 .assign_global_id_to_table(&self.table_info_source, Some(sink_table_name.clone()), None)
782 .await?;
783
784 node_ctx.register_task_src_sink(flow_id, &source_table_ids, sink_table_name.clone());
785
786 node_ctx.query_context = query_ctx.map(Arc::new);
787 let flow_plan = sql_to_flow_plan(&mut node_ctx, &self.query_engine, &sql).await?;
789
790 debug!("Flow {:?}'s Plan is {:?}", flow_id, flow_plan);
791
792 if let Some((_, _, real_schema)) = self.fetch_table_pk_schema(&sink_table_name).await? {
795 let auto_schema = relation_desc_to_column_schemas_with_fallback(&flow_plan.schema);
796
797 for (idx, zipped) in auto_schema
801 .iter()
802 .zip_longest(real_schema.iter())
803 .enumerate()
804 {
805 match zipped {
806 EitherOrBoth::Both(auto, real) => {
807 if auto.data_type != real.data_type {
808 InvalidQuerySnafu {
809 reason: format!(
810 "Column {}(name is '{}', flow inferred name is '{}')'s data type mismatch, expect {:?} got {:?}",
811 idx,
812 real.name,
813 auto.name,
814 real.data_type,
815 auto.data_type
816 ),
817 }
818 .fail()?;
819 }
820 }
821 EitherOrBoth::Right(real) if real.data_type.is_timestamp() => {
822 continue;
824 }
825 _ => InvalidQuerySnafu {
826 reason: format!(
827 "schema length mismatched, expected {} found {}",
828 real_schema.len(),
829 auto_schema.len()
830 ),
831 }
832 .fail()?,
833 }
834 }
835 } else {
836 let did_create = self
839 .create_table_from_relation(
840 &format!("flow-id={flow_id}"),
841 &sink_table_name,
842 &flow_plan.schema,
843 )
844 .await?;
845 if !did_create {
846 UnexpectedSnafu {
847 reason: format!("Failed to create table {:?}", sink_table_name),
848 }
849 .fail()?;
850 }
851 }
852
853 node_ctx.add_flow_plan(flow_id, flow_plan.clone());
854
855 let _ = comment;
856 let _ = flow_options;
857
858 let sink_id = node_ctx.table_repr.get_by_name(&sink_table_name).unwrap().1;
860 let sink_sender = node_ctx.get_sink_by_global_id(&sink_id)?;
861
862 let source_ids = source_table_ids
863 .iter()
864 .map(|id| node_ctx.table_repr.get_by_table_id(id).unwrap().1)
865 .collect_vec();
866 let source_receivers = source_ids
867 .iter()
868 .map(|id| {
869 node_ctx
870 .get_source_by_global_id(id)
871 .map(|s| s.get_receiver())
872 })
873 .collect::<Result<Vec<_>, _>>()?;
874 let err_collector = ErrCollector::default();
875 self.flow_err_collectors
876 .write()
877 .await
878 .insert(flow_id, err_collector.clone());
879 let handle = self.get_worker_handle_for_create_flow().await;
881 let create_request = worker::Request::Create {
882 flow_id,
883 plan: flow_plan,
884 sink_id,
885 sink_sender,
886 source_ids,
887 src_recvs: source_receivers,
888 expire_after,
889 or_replace,
890 create_if_not_exists,
891 err_collector,
892 };
893
894 handle.create_flow(create_request).await?;
895 info!("Successfully create flow with id={}", flow_id);
896 Ok(Some(flow_id))
897 }
898
899 pub async fn flush_flow_inner(&self, flow_id: FlowId) -> Result<usize, Error> {
900 debug!("Starting to flush flow_id={:?}", flow_id);
901 drop(self.flush_lock.write().await);
904 let flushed_input_rows = self.node_context.read().await.flush_all_sender().await?;
905 let rows_send = self.run_available(true).await?;
906 let row = self.send_writeback_requests().await?;
907 debug!(
908 "Done to flush flow_id={:?} with {} input rows flushed, {} rows sent and {} output rows flushed",
909 flow_id, flushed_input_rows, rows_send, row
910 );
911 Ok(row)
912 }
913
914 pub async fn flow_exist_inner(&self, flow_id: FlowId) -> Result<bool, Error> {
915 let mut exist = false;
916 for handle in self.worker_handles.iter() {
917 if handle.contains_flow(flow_id).await? {
918 exist = true;
919 break;
920 }
921 }
922 Ok(exist)
923 }
924}
925
926#[derive(Clone, Debug)]
931pub struct FlowTickManager {
932 start: Instant,
934 start_timestamp: repr::Timestamp,
936}
937
938impl Default for FlowTickManager {
939 fn default() -> Self {
940 Self::new()
941 }
942}
943
944impl FlowTickManager {
945 pub fn new() -> Self {
946 FlowTickManager {
947 start: Instant::now(),
948 start_timestamp: SystemTime::now()
949 .duration_since(SystemTime::UNIX_EPOCH)
950 .unwrap()
951 .as_millis() as repr::Timestamp,
952 }
953 }
954
955 pub fn tick(&self) -> repr::Timestamp {
959 let current = Instant::now();
960 let since_the_epoch = current - self.start;
961 since_the_epoch.as_millis() as repr::Timestamp + self.start_timestamp
962 }
963}