1use std::sync::Arc;
4use std::time::Instant;
5
6use super::chunk::DataChunk;
7use super::runtime::{ExecutionRuntime, OperatorProfile, OperatorProfileKey};
8use super::slot::SlotLayout;
9use crate::executor::base::{MemoryTracker, Spillable};
10use linkrs_core::error::QueryError;
11use linkrs_core::Value;
12
13pub use super::context::ValueRowContext;
14pub use super::helpers::{comparison, conversion};
15pub use super::operators::base::OperatorBase;
16use super::operators::base::OperatorLifecycle;
17use super::operators::source_operator::OperatorConfig;
18
19use super::operators::apply_operator::ApplyOperator;
20use super::operators::blocking::BlockingOperator;
21use super::operators::blocking::BlockingOperatorKind;
22use super::operators::ddl_operator::DdlOperator;
23use super::operators::exchange_operator::ExchangeOperator;
24use super::operators::fulltext_operator::FulltextOperator;
25use super::operators::gather_operator::GatherOperator;
26use super::operators::graph_operator::GraphOperator;
27use super::operators::graph_operator::GraphOperatorKind;
28use super::operators::join_operator::JoinOperator;
29use super::operators::recursive_fragment_operator::RecursiveFragmentOperator;
30use super::operators::set_operator::SetOperator;
31use super::operators::set_operator::SetOperatorKind;
32use super::operators::shuffle_join_operator::HashShuffleJoinOperator;
33use super::operators::sink_operator::SinkOperator;
34use super::operators::source_operator::SourceOperator;
35use super::operators::source_operator::SourceOperatorKind;
36use super::operators::txn_operator::TxnOperator;
37use super::operators::unary_operator::UnaryOperator;
38use super::operators::unary_operator::UnaryOperatorKind;
39use super::operators::vector_operator::VectorOperator;
40use super::operators::wco_operator::WcoIntersectOperator;
41
42mod operator_name;
43
44#[derive(Debug, Clone, Copy, PartialEq, Eq)]
46pub enum SortDirection {
47 Ascending,
48 Descending,
49}
50
51#[derive(Debug, Clone, Copy, PartialEq, Eq)]
53pub enum FullOuterJoinPhase {
54 BuildingRight,
55 ProbeLeft,
56 EmitUnmatchedRight,
57}
58
59#[derive(Debug)]
69pub enum StreamingExecutor {
70 Source(OperatorBase, SourceOperator),
71 Unary(OperatorBase, Box<StreamingExecutor>, UnaryOperator),
72 Join(
73 OperatorBase,
74 Box<StreamingExecutor>,
75 Box<StreamingExecutor>,
76 Box<JoinOperator>,
77 ),
78 Set(
79 OperatorBase,
80 Box<StreamingExecutor>,
81 Box<StreamingExecutor>,
82 SetOperator,
83 ),
84 Apply(
85 OperatorBase,
86 Box<StreamingExecutor>,
87 Box<StreamingExecutor>,
88 ApplyOperator,
89 ),
90 Blocking(OperatorBase, Box<StreamingExecutor>, BlockingOperator),
91 Graph(OperatorBase, Box<StreamingExecutor>, GraphOperator),
92 RecursiveFragment(
95 OperatorBase,
96 Box<StreamingExecutor>,
97 RecursiveFragmentOperator,
98 ),
99 Sink(OperatorBase, Box<StreamingExecutor>, SinkOperator),
100 Ddl(OperatorBase, Box<StreamingExecutor>, DdlOperator),
101 Fulltext(OperatorBase, Box<StreamingExecutor>, FulltextOperator),
102 Vector(OperatorBase, Box<StreamingExecutor>, VectorOperator),
103 Txn(OperatorBase, Box<StreamingExecutor>, TxnOperator),
104 Gather(OperatorBase, Vec<StreamingExecutor>, GatherOperator),
105 Exchange(OperatorBase, Vec<StreamingExecutor>, ExchangeOperator),
108 HashShuffleJoin(
111 OperatorBase,
112 Vec<StreamingExecutor>,
113 Vec<StreamingExecutor>,
114 HashShuffleJoinOperator,
115 ),
116 Wco(
119 OperatorBase,
120 Box<StreamingExecutor>,
121 Vec<StreamingExecutor>,
122 WcoIntersectOperator,
123 ),
124}
125
126macro_rules! dispatch_open {
128 ($self:expr) => {
129 match $self {
130 Self::Source(_, op) => op.open(),
131 Self::Unary(_, input, op) => op.open(input),
132 Self::Join(_, left, right, op) => op.open(left, right),
133 Self::Set(_, left, right, op) => op.open(left, right),
134 Self::Apply(_, left, right, op) => op.open(left, right),
135 Self::Blocking(_, input, op) => op.open(input),
136 Self::Graph(_, input, op) => op.open(input),
137 Self::RecursiveFragment(_, input, op) => op.open(input),
138 Self::Sink(_, input, op) => op.open(input),
139 Self::Ddl(_, input, op) => op.open(input),
140 Self::Fulltext(_, input, op) => op.open(input),
141 Self::Vector(_, input, op) => op.open(input),
142 Self::Txn(_, input, op) => op.open(input),
143 Self::Gather(_, children, op) => op.open(children),
144 Self::Exchange(_, children, op) => op.open(children),
145 Self::HashShuffleJoin(_, left, right, op) => op.open(left, right),
146 Self::Wco(_, probe, builds, op) => op.open(probe, builds),
147 }
148 };
149}
150
151macro_rules! dispatch_next {
153 ($self:expr) => {
154 match $self {
155 Self::Source(_, op) => op.next(),
156 Self::Unary(_, input, op) => op.next(input),
157 Self::Join(_, left, right, op) => op.next(left, right),
158 Self::Set(_, left, right, op) => op.next(left, right),
159 Self::Apply(_, left, right, op) => op.next(left, right),
160 Self::Blocking(_, input, op) => op.next(input),
161 Self::Graph(_, input, op) => op.next(input),
162 Self::RecursiveFragment(_, input, op) => op.next(input),
163 Self::Sink(_, input, op) => op.next(input),
164 Self::Ddl(_, input, op) => op.next(input),
165 Self::Fulltext(_, input, op) => op.next(input),
166 Self::Vector(_, input, op) => op.next(input),
167 Self::Txn(_, input, op) => op.next(input),
168 Self::Gather(_, children, op) => op.next(children),
169 Self::Exchange(_, children, op) => op.next(children),
170 Self::HashShuffleJoin(_, left, right, op) => op.next(left, right),
171 Self::Wco(_, probe, builds, op) => op.next(probe, builds),
172 }
173 };
174}
175
176macro_rules! dispatch_reset {
182 ($self:expr) => {
183 match $self {
184 Self::Source(_, op) => op.reset(),
185 Self::Unary(_, input, op) => op.reset(input),
186 Self::Join(_, left, right, op) => op.reset(left, right),
187 Self::Set(_, left, right, op) => op.reset(left, right),
188 Self::Apply(_, left, right, op) => op.reset(left, right),
189 Self::Graph(_, input, op) => op.reset(input),
190 Self::RecursiveFragment(_, input, op) => op.reset(input),
191 Self::Wco(_, probe, builds, op) => op.reset(probe, builds),
192 _ => $self.fallback_reset(),
193 }
194 };
195}
196
197macro_rules! dispatch_stop {
199 ($self:expr) => {
200 match $self {
201 Self::Source(_, op) => op.stop(),
202 Self::Unary(_, _, op) => op.stop(),
203 Self::Join(_, _, _, op) => op.stop(),
204 Self::Set(_, _, _, op) => op.stop(),
205 Self::Apply(_, _, _, op) => op.stop(),
206 Self::Blocking(_, _, op) => op.stop(),
207 Self::Graph(_, _, op) => op.stop(),
208 Self::RecursiveFragment(_, _, op) => op.stop(),
209 Self::Sink(_, _, op) => op.stop(),
210 Self::Ddl(_, _, op) => op.stop(),
211 Self::Fulltext(_, _, op) => op.stop(),
212 Self::Vector(_, _, op) => op.stop(),
213 Self::Txn(_, _, op) => op.stop(),
214 Self::Gather(_, _, op) => op.stop(),
215 Self::Exchange(_, _, op) => op.stop(),
216 Self::HashShuffleJoin(_, _, _, op) => op.stop(),
217 Self::Wco(_, _, _, op) => op.stop(),
218 }
219 };
220}
221
222macro_rules! dispatch_close {
224 ($self:expr) => {
225 match $self {
226 Self::Source(_, op) => op.close(),
227 Self::Unary(_, _, op) => op.close(),
228 Self::Join(_, _, _, op) => op.close(),
229 Self::Set(_, _, _, op) => op.close(),
230 Self::Apply(_, _, _, op) => op.close(),
231 Self::Blocking(_, _, op) => op.close(),
232 Self::Graph(_, _, op) => op.close(),
233 Self::RecursiveFragment(_, _, op) => op.close(),
234 Self::Sink(_, _, op) => op.close(),
235 Self::Ddl(_, _, op) => op.close(),
236 Self::Fulltext(_, _, op) => op.close(),
237 Self::Vector(_, _, op) => op.close(),
238 Self::Txn(_, _, op) => op.close(),
239 Self::Gather(_, _, op) => op.close(),
240 Self::Exchange(_, _, op) => op.close(),
241 Self::HashShuffleJoin(_, _, _, op) => op.close(),
242 Self::Wco(_, _, _, op) => op.close(),
243 }
244 };
245}
246
247impl StreamingExecutor {
248 pub fn inject_context(
253 &mut self,
254 runtime: Option<Arc<ExecutionRuntime>>,
255 config: OperatorConfig,
256 ) {
257 let runtime_ref = runtime.as_ref();
258 match self {
259 Self::Source(_, op) => op.inject_context(runtime_ref, config),
260 Self::Unary(_, _, op) => op.inject_context(runtime_ref, config),
261 Self::Join(_, _, _, op) => op.inject_context(runtime_ref, config),
262 Self::Set(_, _, _, op) => op.inject_context(runtime_ref, config),
263 Self::Apply(_, _, _, op) => op.inject_context(runtime_ref, config),
264 Self::Blocking(_, _, op) => op.inject_context(runtime_ref, config),
265 Self::Graph(_, _, op) => op.inject_context(runtime_ref, config),
266 Self::RecursiveFragment(_, _, op) => op.inject_context(runtime_ref, config),
267 Self::Sink(_, _, op) => op.inject_context(runtime_ref, config),
268 Self::Ddl(_, _, op) => op.inject_context(runtime_ref, config),
269 Self::Fulltext(_, _, op) => op.inject_context(runtime_ref, config),
270 Self::Vector(_, _, op) => op.inject_context(runtime_ref, config),
271 Self::Txn(_, _, op) => op.inject_context(runtime_ref, config),
272 Self::Gather(_, _, op) => op.inject_context(runtime_ref, config),
273 Self::Exchange(_, _, op) => op.inject_context(runtime_ref, config),
274 Self::HashShuffleJoin(_, _, _, op) => op.inject_context(runtime_ref, config),
275 Self::Wco(_, _, _, op) => op.inject_context(runtime_ref, config),
276 }
277 for child in self.children_mut() {
278 child.inject_context(runtime.clone(), config);
279 }
280 }
281
282 pub fn set_runtime(&mut self, rt: Option<Arc<ExecutionRuntime>>) {
284 if let (Self::Graph(_, _, operator), Some(runtime)) = (&mut *self, rt.as_ref()) {
285 operator.bind_runtime(runtime);
286 }
287 if let (Self::RecursiveFragment(_, _, operator), Some(runtime)) = (&mut *self, rt.as_ref())
288 {
289 operator.bind_runtime(runtime);
290 }
291 self.base_mut().runtime = rt.clone();
292 for child in self.children_mut() {
293 child.set_runtime(rt.clone());
294 }
295 }
296
297 pub fn set_chunk_size(&mut self, chunk_size: usize) {
299 self.base_mut().chunk_size = chunk_size;
300 for child in self.children_mut() {
301 child.set_chunk_size(chunk_size);
302 }
303 }
304
305 pub fn plan_node_id(&self) -> i64 {
307 self.base().plan_node_id
308 }
309
310 pub fn profile_key(&self) -> OperatorProfileKey {
312 self.base().profile_key()
313 }
314
315 pub fn set_partition_id(&mut self, partition_id: usize) {
317 self.base_mut().partition_id = Some(partition_id);
318 self.base_mut().is_global = false;
319 for child in self.children_mut() {
320 child.set_partition_id(partition_id);
321 }
322 }
323
324 pub fn set_global(&mut self) {
328 self.base_mut().partition_id = None;
329 self.base_mut().is_global = true;
330 for child in self.children_mut() {
331 child.set_global();
332 }
333 }
334
335 pub fn is_partition_local(&self) -> bool {
342 match self {
343 Self::Source(_, op) => matches!(
344 &op.kind,
345 SourceOperatorKind::ScanVertices { .. }
346 | SourceOperatorKind::StorageScanVertices { .. }
347 | SourceOperatorKind::ScanEdges { .. }
348 | SourceOperatorKind::StorageScanEdges { .. }
349 ),
350 Self::Unary(_, input, op) => {
351 matches!(
352 &op.kind,
353 UnaryOperatorKind::Filter { .. }
354 | UnaryOperatorKind::Project { .. }
355 | UnaryOperatorKind::Assign { .. }
356 | UnaryOperatorKind::Unwind { .. }
357 | UnaryOperatorKind::AppendVertices { .. }
358 ) && input.is_partition_local()
359 }
360 Self::Blocking(_, input, op) => {
361 matches!(
362 &op.kind,
363 BlockingOperatorKind::PartialAggregate { .. }
370 | BlockingOperatorKind::Sort { .. }
371 | BlockingOperatorKind::Distinct { .. }
372 | BlockingOperatorKind::TopN { .. }
373 | BlockingOperatorKind::GroupBy { .. }
374 | BlockingOperatorKind::Aggregate { .. }
375 ) && input.is_partition_local()
376 }
377 Self::Graph(_, input, op) => {
378 matches!(
382 &op.kind,
383 GraphOperatorKind::Expand { .. }
384 | GraphOperatorKind::BiExpand { .. }
385 | GraphOperatorKind::ExpandAll { .. }
386 ) && input.is_partition_local()
387 }
388 Self::HashShuffleJoin(..) | Self::Exchange(..) | Self::RecursiveFragment(..) => false,
389 _ => false,
390 }
391 }
392
393 pub fn get_runtime(&self) -> Option<&ExecutionRuntime> {
395 self.base().runtime.as_deref()
396 }
397
398 pub fn ensure_not_cancelled(&self) -> Result<(), QueryError> {
400 self.base().ensure_not_cancelled()
401 }
402
403 pub fn operator_name(&self) -> &'static str {
405 operator_name::operator_name(self)
406 }
407
408 pub fn record_profile_timing(&self, phase: &str, elapsed_us: u64) {
413 let Some(rt) = &self.base().runtime else {
414 return;
415 };
416 let entry = rt.profile().get_entry(&self.profile_key());
417 let entry = entry.unwrap_or_else(|| {
418 let name = self.operator_name();
420 let op = OperatorProfile {
421 physical_operator_id: self.base().physical_operator_id,
422 node_id: self.plan_node_id(),
423 partition_id: self.base().partition_id,
424 name: name.to_string(),
425 ..OperatorProfile::default()
426 };
427 rt.register_operator(&op)
428 });
429 let ordering = std::sync::atomic::Ordering::Relaxed;
430 if phase == "open" {
431 entry.open_time_us.fetch_add(elapsed_us, ordering);
432 } else if phase == "next" {
433 entry.next_time_us.fetch_add(elapsed_us, ordering);
434 } else if phase == "close" {
435 entry.close_time_us.fetch_add(elapsed_us, ordering);
436 }
437 }
438
439 pub fn peak_memory_bytes(&self) -> u64 {
441 self.memory_tracker().map_or(0, |mt| mt.peak() as u64)
442 }
443
444 pub fn parallel_fallback_reason(&self) -> Option<String> {
447 match self {
448 Self::Gather(_, children, _) | Self::Exchange(_, children, _) => {
449 children.iter().find_map(|c| c.parallel_fallback_reason())
450 }
451 Self::Unary(_, child, _)
452 | Self::Blocking(_, child, _)
453 | Self::Graph(_, child, _)
454 | Self::RecursiveFragment(_, child, _)
455 | Self::Sink(_, child, _)
456 | Self::Ddl(_, child, _)
457 | Self::Fulltext(_, child, _)
458 | Self::Vector(_, child, _)
459 | Self::Txn(_, child, _) => child.parallel_fallback_reason(),
460 Self::Join(_, left, right, _) => left
461 .parallel_fallback_reason()
462 .or_else(|| right.parallel_fallback_reason()),
463 Self::Set(_, left, right, _) => left
464 .parallel_fallback_reason()
465 .or_else(|| right.parallel_fallback_reason()),
466 Self::Apply(_, outer, inner, _) => outer
467 .parallel_fallback_reason()
468 .or_else(|| inner.parallel_fallback_reason()),
469 Self::HashShuffleJoin(_, left, right, _) => left
470 .iter()
471 .find_map(|c| c.parallel_fallback_reason())
472 .or_else(|| right.iter().find_map(|c| c.parallel_fallback_reason())),
473 Self::Wco(_, probe, builds, _) => probe
474 .parallel_fallback_reason()
475 .or_else(|| builds.iter().find_map(|c| c.parallel_fallback_reason())),
476 Self::Source(..) => None,
477 }
478 }
479
480 pub fn record_profile_rows(&self, count: u64) {
482 self.base().record_profile_rows(count);
483 }
484
485 pub fn record_profile_peak_memory(&self, bytes: u64) {
487 let Some(rt) = &self.base().runtime else {
488 return;
489 };
490 let Some(entry) = rt.profile().get_entry(&self.profile_key()) else {
491 return;
492 };
493 let prev = entry
494 .peak_memory_bytes
495 .fetch_max(bytes, std::sync::atomic::Ordering::Relaxed);
496 if bytes > prev {
497 entry
498 .peak_memory_bytes
499 .store(bytes, std::sync::atomic::Ordering::Relaxed);
500 }
501 }
502
503 pub fn record_profile_spill(&self, spilled_bytes: u64, spill_count: u64, spilled_rows: u64) {
505 let Some(rt) = &self.base().runtime else {
506 return;
507 };
508 let Some(entry) = rt.profile().get_entry(&self.profile_key()) else {
509 return;
510 };
511 entry
512 .spilled_bytes
513 .fetch_add(spilled_bytes, std::sync::atomic::Ordering::Relaxed);
514 entry
515 .spill_count
516 .fetch_add(spill_count, std::sync::atomic::Ordering::Relaxed);
517 entry
518 .spilled_rows
519 .fetch_add(spilled_rows, std::sync::atomic::Ordering::Relaxed);
520 }
521
522 pub fn register_resource<F>(&self, f: F)
524 where
525 F: FnOnce() + Send + 'static,
526 {
527 self.base().register_resource(f);
528 }
529
530 pub fn base(&self) -> &OperatorBase {
532 match self {
533 Self::Source(base, _) => base,
534 Self::Unary(base, _, _) => base,
535 Self::Join(base, _, _, _) | Self::Set(base, _, _, _) | Self::Apply(base, _, _, _) => {
536 base
537 }
538 Self::Blocking(base, _, _) => base,
539 Self::Graph(base, _, _) | Self::RecursiveFragment(base, _, _) => base,
540 Self::Sink(base, _, _) => base,
541 Self::Ddl(base, _, _) | Self::Fulltext(base, _, _) | Self::Vector(base, _, _) => base,
542 Self::Txn(base, _, _) => base,
543 Self::Gather(base, _, _) | Self::Exchange(base, _, _) => base,
544 Self::HashShuffleJoin(base, _, _, _) => base,
545 Self::Wco(base, _, _, _) => base,
546 }
547 }
548
549 pub fn base_mut(&mut self) -> &mut OperatorBase {
551 match self {
552 Self::Source(base, _) => base,
553 Self::Unary(base, _, _) => base,
554 Self::Join(base, _, _, _) | Self::Set(base, _, _, _) | Self::Apply(base, _, _, _) => {
555 base
556 }
557 Self::Blocking(base, _, _) => base,
558 Self::Graph(base, _, _) | Self::RecursiveFragment(base, _, _) => base,
559 Self::Sink(base, _, _) => base,
560 Self::Ddl(base, _, _) | Self::Fulltext(base, _, _) | Self::Vector(base, _, _) => base,
561 Self::Txn(base, _, _) => base,
562 Self::Gather(base, _, _) | Self::Exchange(base, _, _) => base,
563 Self::HashShuffleJoin(base, _, _, _) => base,
564 Self::Wco(base, _, _, _) => base,
565 }
566 }
567
568 pub fn children_mut(&mut self) -> Vec<&mut Self> {
570 match self {
571 Self::Source(..) => vec![],
572 Self::Unary(_, input, _)
573 | Self::Blocking(_, input, _)
574 | Self::Graph(_, input, _)
575 | Self::RecursiveFragment(_, input, _)
576 | Self::Sink(_, input, _)
577 | Self::Txn(_, input, _) => vec![input.as_mut()],
578 Self::Join(_, left, right, _)
579 | Self::Set(_, left, right, _)
580 | Self::Apply(_, left, right, _) => vec![left.as_mut(), right.as_mut()],
581 Self::Ddl(_, input, _) | Self::Fulltext(_, input, _) | Self::Vector(_, input, _) => {
582 vec![input.as_mut()]
583 }
584 Self::Gather(_, children, _) | Self::Exchange(_, children, _) => {
585 children.iter_mut().collect()
586 }
587 Self::HashShuffleJoin(_, left, right, _) => {
588 let mut all: Vec<&mut Self> = left.iter_mut().collect();
589 all.extend(right.iter_mut());
590 all
591 }
592 Self::Wco(_, probe, builds, _) => {
593 let mut all = vec![probe.as_mut()];
594 all.extend(builds.iter_mut());
595 all
596 }
597 }
598 }
599
600 pub fn memory_tracker(&self) -> Option<&MemoryTracker> {
602 match self {
603 Self::Source(..)
604 | Self::Unary(..)
605 | Self::Graph(..)
606 | Self::RecursiveFragment(..)
607 | Self::Sink(..)
608 | Self::Txn(..)
609 | Self::Ddl(..)
610 | Self::Fulltext(..)
611 | Self::Vector(..)
612 | Self::Gather(..)
613 | Self::Exchange(..) => None,
614 Self::Blocking(_, _, op) => Some(op.memory_tracker()),
615 Self::Join(_, _, _, op) => Some(op.memory_tracker()),
616 Self::Set(_, _, _, op) => {
617 if matches!(&op.kind, SetOperatorKind::UnionAll { .. }) {
618 None
619 } else {
620 Some(op.memory_tracker())
621 }
622 }
623 Self::Apply(_, _, _, op) => Some(op.memory_tracker()),
624 Self::HashShuffleJoin(_, _, _, op) => Some(op.memory_tracker()),
625 Self::Wco(_, _, _, op) => Some(op.memory_tracker()),
626 }
627 }
628
629 pub fn opened(&self) -> bool {
631 self.base().lifecycle.is_opened()
632 }
633
634 pub fn reset(&mut self) -> Result<(), QueryError> {
644 let used_fallback = dispatch_reset!(self)?;
645 self.base_mut().reset_used_fallback |= used_fallback;
646 self.restore_opened_lifecycle();
647 Ok(())
648 }
649
650 fn fallback_reset(&mut self) -> Result<bool, QueryError> {
655 self.close_tree()?;
656 self.mark_tree_new();
657 self.open()?;
658 Ok(true)
659 }
660
661 fn mark_tree_new(&mut self) {
663 self.base_mut().mark_new();
664 for child in self.children_mut() {
665 child.mark_tree_new();
666 }
667 }
668
669 fn mark_tree_opened(&mut self) {
673 self.base_mut().lifecycle = OperatorLifecycle::Opened;
674 for child in self.children_mut() {
675 child.mark_tree_opened();
676 }
677 }
678
679 fn restore_opened_lifecycle(&mut self) {
682 if matches!(
683 self.base().lifecycle,
684 OperatorLifecycle::Opened | OperatorLifecycle::Exhausted
685 ) {
686 self.base_mut().lifecycle = OperatorLifecycle::Opened;
687 }
688 for child in self.children_mut() {
689 child.restore_opened_lifecycle();
690 }
691 }
692
693 pub fn inject_correlation_frame(&mut self, layout: Arc<SlotLayout>, row: Vec<Value>) {
698 if let Self::Source(_, op) = self {
699 if matches!(&op.kind, SourceOperatorKind::Argument) {
700 op.frame = Some((layout, row));
701 return;
702 }
703 }
704 for child in self.children_mut() {
705 child.inject_correlation_frame(layout.clone(), row.clone());
706 }
707 }
708
709 pub fn open(&mut self) -> Result<(), QueryError> {
713 self.ensure_not_cancelled()?;
714 if let Some(rt) = &self.base().runtime {
717 let name = self.operator_name();
718 let op = OperatorProfile {
719 physical_operator_id: self.base().physical_operator_id,
720 node_id: self.plan_node_id(),
721 partition_id: self.base().partition_id,
722 name: name.to_string(),
723 ..OperatorProfile::default()
724 };
725 rt.register_operator(&op);
726 }
727 let runtime = self.base().runtime.clone();
730 let config = OperatorConfig {
731 chunk_size: self.base().chunk_size,
732 partition_id: self.base().partition_id,
733 physical_operator_id: self.base().physical_operator_id,
734 };
735 self.inject_context(runtime, config);
736 let start = Instant::now();
737 let result = dispatch_open!(self);
738 let elapsed = start.elapsed().as_micros() as u64;
739 self.record_profile_timing("open", elapsed);
740 if let Err(error) = result {
741 if let Err(close_error) = self.close_tree() {
742 log::warn!(
743 "Failed to close streaming executor tree after open error: {}",
744 close_error
745 );
746 }
747 return Err(error);
748 }
749 self.mark_tree_opened();
750 Ok(())
751 }
752
753 pub fn advance(&mut self) -> Result<Option<DataChunk>, QueryError> {
755 self.ensure_not_cancelled()?;
756 if self.base().lifecycle.is_exhausted() || !self.base().lifecycle.is_opened() {
759 return Ok(None);
760 }
761 let one_shot = matches!(self, Self::Ddl(..) | Self::Fulltext(..) | Self::Vector(..));
762 let start = Instant::now();
763 let result = dispatch_next!(self);
764 let elapsed = start.elapsed().as_micros() as u64;
765 if let Ok(Some(ref chunk)) = result {
766 self.record_profile_rows(chunk.logical_len());
768 }
769 if matches!(&result, Ok(None)) || (one_shot && matches!(&result, Ok(Some(_)))) {
770 self.base_mut().lifecycle.mark_exhausted();
771 self.base().mark_profile_exhausted();
775 }
776 self.record_profile_timing("next", elapsed);
777 if result.is_err() {
778 self.base_mut().lifecycle.mark_failed();
779 if let Err(close_error) = self.close_tree() {
780 log::warn!(
781 "Failed to close streaming executor tree after next error: {}",
782 close_error
783 );
784 }
785 }
786 result
787 }
788
789 pub fn stop(&mut self) -> Result<(), QueryError> {
791 if matches!(
792 self.base().lifecycle,
793 OperatorLifecycle::Stopped | OperatorLifecycle::Closed
794 ) {
795 return Ok(());
796 }
797 let start = Instant::now();
798 let result = dispatch_stop!(self);
799 let elapsed = start.elapsed().as_micros() as u64;
800 self.record_profile_timing("stop", elapsed);
801 if result.is_ok() {
802 self.base_mut().lifecycle.mark_stopped();
803 }
804 result
805 }
806
807 pub fn close(&mut self) -> Result<(), QueryError> {
809 if matches!(self.base().lifecycle, OperatorLifecycle::Closed) {
810 return Ok(());
811 }
812 let peak = self.peak_memory_bytes();
814 let spilled = self.spilled_size();
815 let sc = self.spill_count();
816 let rows = self.spilled_rows();
817 let start = Instant::now();
818 let result = dispatch_close!(self);
819 let elapsed = start.elapsed().as_micros() as u64;
820 self.record_profile_timing("close", elapsed);
821 if peak > 0 {
822 self.record_profile_peak_memory(peak);
823 }
824 if spilled > 0 || sc > 0 || rows > 0 {
825 self.record_profile_spill(spilled, sc, rows);
826 }
827 if result.is_ok() {
828 self.base_mut().lifecycle.mark_closed();
829 }
830 result
831 }
832
833 pub fn close_tree(&mut self) -> Result<(), QueryError> {
836 let mut first_error = None;
837 for child in self.children_mut() {
838 if let Err(error) = child.close_tree() {
839 if first_error.is_none() {
840 first_error = Some(error);
841 }
842 }
843 }
844 if let Err(error) = self.close() {
845 if first_error.is_none() {
846 first_error = Some(error);
847 }
848 }
849 first_error.map_or(Ok(()), Err)
850 }
851
852 pub fn stop_tree(&mut self) -> Result<(), QueryError> {
855 let mut first_error = self.stop().err();
856 for child in self.children_mut() {
857 if let Err(error) = child.stop_tree() {
858 if first_error.is_none() {
859 first_error = Some(error);
860 }
861 }
862 }
863 first_error.map_or(Ok(()), Err)
864 }
865}
866
867impl Spillable for StreamingExecutor {
868 fn spill_to_disk(&mut self) -> Result<(), QueryError> {
869 let sm = self
870 .base()
871 .spill_manager()
872 .ok_or_else(|| QueryError::execution("Spill manager not configured"))?;
873 match self {
874 Self::Blocking(_, _, op) => op.spill_with_manager(&sm),
875 Self::Join(_, _, _, op) => op.spill_with_manager(&sm),
876 Self::Set(_, _, _, op) => op.spill_with_manager(&sm),
877 Self::Apply(_, _, _, _op) => {
878 for child in self.children_mut() {
881 child.spill_to_disk()?;
882 }
883 Ok(())
884 }
885 Self::Wco(_, _, _, op) => op.spill_with_manager(&sm),
886 Self::Source(..)
890 | Self::Unary(..)
891 | Self::Graph(..)
892 | Self::RecursiveFragment(..)
893 | Self::Sink(..)
894 | Self::Ddl(..)
895 | Self::Fulltext(..)
896 | Self::Vector(..)
897 | Self::Txn(..)
898 | Self::Gather(..)
899 | Self::Exchange(..)
900 | Self::HashShuffleJoin(..) => {
901 for child in self.children_mut() {
902 child.spill_to_disk()?;
903 }
904 Ok(())
905 }
906 }
907 }
908
909 fn spilled_size(&self) -> u64 {
910 match self {
911 Self::Blocking(_, _, op) => op.spilled_bytes(),
912 Self::Join(_, _, _, op) => op.spilled_bytes(),
913 Self::Set(_, _, _, op) => op.spilled_bytes(),
914 Self::Wco(_, _, _, op) => op.spilled_bytes(),
915 _ => 0,
916 }
917 }
918
919 fn spill_count(&self) -> u64 {
920 match self {
921 Self::Blocking(_, _, op) => op.spill_count(),
922 Self::Join(_, _, _, op) => op.spill_count(),
923 Self::Set(_, _, _, op) => op.spill_count(),
924 Self::Wco(_, _, _, _op) => 0,
925 _ => 0,
926 }
927 }
928
929 fn spilled_rows(&self) -> u64 {
930 match self {
931 Self::Blocking(_, _, op) => op.spilled_rows(),
932 Self::Join(_, _, _, op) => op.spilled_rows(),
933 Self::Set(_, _, _, op) => op.spilled_rows(),
934 Self::Wco(_, _, _, op) => op.spilled_rows(),
935 _ => 0,
936 }
937 }
938}
939
940#[cfg(test)]
941mod tests;