1use std::any::Any;
104use std::cell::RefCell;
105use std::collections::{BTreeMap, BTreeSet};
106use std::convert::Infallible;
107use std::future::Future;
108use std::pin::Pin;
109use std::rc::{Rc, Weak};
110use std::sync::Arc;
111use std::task::Poll;
112
113use differential_dataflow::dynamic::pointstamp::PointStamp;
114use differential_dataflow::lattice::Lattice;
115use differential_dataflow::operators::arrange::Arranged;
116use differential_dataflow::operators::arrange::ShutdownButton;
117use differential_dataflow::operators::iterate::Variable;
118use differential_dataflow::trace::cursor::{BatchCursor, BatchDiff, BatchKey, BatchVal};
119use differential_dataflow::trace::{BatchReader, Cursor, Navigable, TraceReader};
120use differential_dataflow::{AsCollection, Data, VecCollection};
121use futures::FutureExt;
122use futures::channel::oneshot;
123use itertools::Itertools;
124use mz_compute_types::dataflows::{DataflowDescription, IndexDesc};
125use mz_compute_types::dyncfgs::{
126 COMPUTE_APPLY_COLUMN_DEMANDS, COMPUTE_LOGICAL_BACKPRESSURE_INFLIGHT_SLACK,
127 COMPUTE_LOGICAL_BACKPRESSURE_MAX_RETAINED_CAPABILITIES, ENABLE_COMPUTE_LOGICAL_BACKPRESSURE,
128 ENABLE_COMPUTE_TEMPORAL_BUCKETING, SUBSCRIBE_SNAPSHOT_OPTIMIZATION, TEMPORAL_BUCKETING_SUMMARY,
129};
130use mz_compute_types::plan::render_plan::{
131 self, BindStage, LetBind, LetFreePlan, RecBind, RenderPlan,
132};
133use mz_compute_types::plan::scalar::LirScalarExpr;
134use mz_compute_types::plan::{ArrangementStrategy, LirId};
135use mz_expr::{EvalError, Id, LocalId, permutation_for_arrangement};
136use mz_persist_client::operators::shard_source::{ErrorHandler, SnapshotMode};
137use mz_repr::explain::DummyHumanizer;
138use mz_repr::fixed_length::ExtendDatums;
139use mz_repr::{Datum, DatumVec, Diff, GlobalId, ReprRelationType, Row, RowArena, SharedRow};
140use mz_storage_operators::persist_source;
141use mz_storage_types::controller::CollectionMetadata;
142use mz_timely_util::columnation::ColumnationChunker;
143use mz_timely_util::operator::{CollectionExt, StreamExt};
144use mz_timely_util::probe::{Handle as MzProbeHandle, ProbeNotify};
145use mz_timely_util::scope_label::ScopeExt;
146use timely::PartialOrder;
147use timely::container::CapacityContainerBuilder;
148use timely::dataflow::channels::pact::Pipeline;
149use timely::dataflow::operators::vec::ToStream;
150use timely::dataflow::operators::vec::{BranchWhen, Filter};
151use timely::dataflow::operators::{Capability, Operator, Probe, probe};
152use timely::dataflow::{Scope, Stream, StreamVec};
153use timely::order::{Product, TotalOrder};
154use timely::progress::timestamp::Refines;
155use timely::progress::{Antichain, Timestamp};
156use timely::scheduling::ActivateOnDrop;
157use timely::worker::Worker as TimelyWorker;
158
159use crate::arrangement::manager::TraceBundle;
160use crate::compute_state::ComputeState;
161use crate::extensions::arrange::{KeyCollection, MzArrange};
162use crate::extensions::reduce::MzReduce;
163use crate::extensions::temporal_bucket::TemporalBucketing;
164use crate::logging::compute::{
165 ComputeEvent, DataflowGlobal, LirMapping, LirMetadata, LogDataflowErrors, OperatorHydration,
166};
167use crate::render::columnar::CollectionEdge;
168use crate::render::context::{ArrangementFlavor, Context};
169use crate::render::errors::DataflowErrorSer;
170use crate::typedefs::{ErrBatcher, ErrBuilder, ErrSpine, KeyBatcher, MzTimestamp};
171use mz_row_spine::{DatumSeq, RowRowBatcher, RowRowBuilder};
172
173pub(crate) mod columnar;
174pub mod context;
175pub(crate) mod errors;
176mod flat_map;
177mod join;
178mod reduce;
179pub mod sinks;
180mod threshold;
181mod top_k;
182
183pub use context::CollectionBundle;
184pub use join::LinearJoinSpec;
185
186struct PressOnDrop<T>(ShutdownButton<T>);
190
191impl<T> Drop for PressOnDrop<T> {
192 fn drop(&mut self) {
193 self.0.press();
194 }
195}
196
197pub fn build_compute_dataflow(
203 timely_worker: &mut TimelyWorker,
204 compute_state: &mut ComputeState,
205 dataflow: DataflowDescription<RenderPlan, CollectionMetadata>,
206 start_signal: StartSignal,
207 until: Antichain<mz_repr::Timestamp>,
208 dataflow_expiration: Antichain<mz_repr::Timestamp>,
209) {
210 let recursive = dataflow
212 .objects_to_build
213 .iter()
214 .any(|object| object.plan.is_recursive());
215
216 let indexes = dataflow
218 .index_exports
219 .iter()
220 .map(|(idx_id, (idx, _typ))| (*idx_id, dataflow.depends_on(idx.on_id), idx.as_lir()))
221 .collect::<Vec<_>>();
222
223 let sinks = dataflow
225 .sink_exports
226 .iter()
227 .map(|(sink_id, sink)| (*sink_id, dataflow.depends_on(sink.from), sink.clone()))
228 .collect::<Vec<_>>();
229
230 let worker_logging = timely_worker.logger_for("timely").map(Into::into);
231 let apply_demands = COMPUTE_APPLY_COLUMN_DEMANDS.get(&compute_state.worker_config);
232 let subscribe_snapshot_optimization =
233 SUBSCRIBE_SNAPSHOT_OPTIMIZATION.get(&compute_state.worker_config);
234
235 let name = format!("Dataflow: {}", &dataflow.debug_name);
236 let input_name = format!("InputRegion: {}", &dataflow.debug_name);
237 let build_name = format!("BuildRegion: {}", &dataflow.debug_name);
238
239 timely_worker.dataflow_core(&name, worker_logging, Box::new(()), |_, scope| {
240 let scope = scope.with_label();
241
242 let mut imported_sources = Vec::new();
247 let mut tokens: BTreeMap<_, Rc<dyn Any>> = BTreeMap::new();
248 let output_probe = MzProbeHandle::default();
249
250 scope.clone().region_named(&input_name, |region| {
251 for (source_id, import) in dataflow.source_imports.iter() {
253 region.region_named(&format!("Source({:?})", source_id), |inner| {
254 let mut read_schema = None;
255 let mut mfp = import.desc.arguments.operators.clone().map(|mut ops| {
256 if apply_demands {
259 let demands = ops.demand();
260 let new_desc = import
261 .desc
262 .storage_metadata
263 .relation_desc
264 .apply_demand(&demands);
265 let new_arity = demands.len();
266 let remap: BTreeMap<_, _> = demands
267 .into_iter()
268 .enumerate()
269 .map(|(new, old)| (old, new))
270 .collect();
271 ops.permute_fn(|old_idx| remap[&old_idx], new_arity);
272 read_schema = Some(new_desc);
273 }
274
275 mz_expr::MfpPlan::create_from(ops)
276 .expect("Linear operators should always be valid")
277 });
278
279 let snapshot_mode = if import.with_snapshot || !subscribe_snapshot_optimization
280 {
281 SnapshotMode::Include
282 } else {
283 compute_state.metrics.inc_subscribe_snapshot_optimization();
284 SnapshotMode::Exclude
285 };
286 let suppress_early_progress_as_of = dataflow.as_of.clone();
287
288 let (mut ok_stream, err_stream, token) =
291 persist_source::persist_source::<DataflowErrorSer>(
292 inner,
293 *source_id,
294 Arc::clone(&compute_state.persist_clients),
295 &compute_state.txns_ctx,
296 import.desc.storage_metadata.clone(),
297 read_schema,
298 dataflow.as_of.clone(),
299 snapshot_mode,
300 until.clone(),
301 mfp.as_mut(),
302 compute_state.dataflow_max_inflight_bytes(),
303 start_signal.clone().into_send_future(),
304 ErrorHandler::Halt("compute_import"),
305 );
306
307 assert!(mfp.map(|x| x.is_identity()).unwrap_or(true));
310
311 if let Some(as_of) = suppress_early_progress_as_of {
315 ok_stream = suppress_early_progress(ok_stream, as_of);
316 }
317
318 if ENABLE_COMPUTE_LOGICAL_BACKPRESSURE.get(&compute_state.worker_config) {
319 let limit = COMPUTE_LOGICAL_BACKPRESSURE_MAX_RETAINED_CAPABILITIES
321 .get(&compute_state.worker_config);
322 let slack = COMPUTE_LOGICAL_BACKPRESSURE_INFLIGHT_SLACK
323 .get(&compute_state.worker_config)
324 .as_millis()
325 .try_into()
326 .expect("must fit");
327
328 let stream = ok_stream.limit_progress(
329 output_probe.clone(),
330 slack,
331 limit,
332 import.upper.clone(),
333 name.clone(),
334 );
335 ok_stream = stream;
336 }
337
338 let input_probe =
340 compute_state.input_probe_for(*source_id, dataflow.export_ids());
341 ok_stream = ok_stream.probe_with(&input_probe);
342
343 let (oks, errs) = (
344 ok_stream
345 .as_collection()
346 .leave_region(region)
347 .leave_region(scope),
348 err_stream
349 .as_collection()
350 .leave_region(region)
351 .leave_region(scope),
352 );
353
354 imported_sources.push((mz_expr::Id::Global(*source_id), (oks, errs)));
355
356 tokens.insert(*source_id, Rc::new(token));
358 });
359 }
360 });
361
362 if recursive {
365 scope.clone().iterative::<PointStamp<u64>, _, _>(|region| {
366 let mut context = Context::for_dataflow_in(
367 &dataflow,
368 region.clone(),
369 compute_state,
370 until,
371 dataflow_expiration,
372 );
373
374 for (id, (oks, errs)) in imported_sources.into_iter() {
375 let bundle = crate::render::CollectionBundle::from_collections(
376 oks.enter(region),
377 errs.enter(region),
378 );
379 context.insert_id(id, bundle);
381 }
382
383 for (idx_id, idx) in &dataflow.index_imports {
385 let input_probe = compute_state.input_probe_for(*idx_id, dataflow.export_ids());
386 let snapshot_mode = if idx.with_snapshot || !subscribe_snapshot_optimization {
387 SnapshotMode::Include
388 } else {
389 compute_state.metrics.inc_subscribe_snapshot_optimization();
390 SnapshotMode::Exclude
391 };
392 context.import_index(
393 scope,
394 compute_state,
395 &mut tokens,
396 input_probe,
397 *idx_id,
398 &idx.desc.as_lir(),
399 &idx.typ,
400 snapshot_mode,
401 start_signal.clone(),
402 );
403 }
404
405 for object in dataflow.objects_to_build {
407 let bundle = context.scope.clone().region_named(
408 &format!("BuildingObject({:?})", object.id),
409 |region| {
410 let depends = object.plan.depends();
411 let in_let = object.plan.is_recursive();
412 context
413 .enter_region(region, Some(&depends))
414 .render_recursive_plan(
415 object.id,
416 0,
417 object.plan,
418 BindingInfo::Body { in_let },
420 )
421 .leave_region(context.scope)
422 },
423 );
424 let global_id = object.id;
425
426 context.log_dataflow_global_id(
427 *bundle
428 .scope()
429 .addr()
430 .first()
431 .expect("Dataflow root id must exist"),
432 global_id,
433 );
434 context.insert_id(Id::Global(object.id), bundle);
435 }
436
437 for (idx_id, dependencies, idx) in indexes {
439 context.export_index_iterative(
440 scope,
441 compute_state,
442 &tokens,
443 dependencies,
444 idx_id,
445 &idx,
446 &output_probe,
447 );
448 }
449
450 for (sink_id, dependencies, sink) in sinks {
452 context.export_sink(
453 compute_state,
454 &tokens,
455 dependencies,
456 sink_id,
457 &sink,
458 start_signal.clone(),
459 &output_probe,
460 scope,
461 );
462 }
463 });
464 } else {
465 scope.clone().region_named(&build_name, |region| {
466 let mut context = Context::for_dataflow_in(
467 &dataflow,
468 region.clone(),
469 compute_state,
470 until,
471 dataflow_expiration,
472 );
473
474 for (id, (oks, errs)) in imported_sources.into_iter() {
475 let bundle = crate::render::CollectionBundle::from_collections(
476 oks.enter_region(region),
477 errs.enter_region(region),
478 );
479 context.insert_id(id, bundle);
481 }
482
483 for (idx_id, idx) in &dataflow.index_imports {
485 let input_probe = compute_state.input_probe_for(*idx_id, dataflow.export_ids());
486 let snapshot_mode = if idx.with_snapshot || !subscribe_snapshot_optimization {
487 SnapshotMode::Include
488 } else {
489 compute_state.metrics.inc_subscribe_snapshot_optimization();
490 SnapshotMode::Exclude
491 };
492 context.import_index(
493 scope,
494 compute_state,
495 &mut tokens,
496 input_probe,
497 *idx_id,
498 &idx.desc.as_lir(),
499 &idx.typ,
500 snapshot_mode,
501 start_signal.clone(),
502 );
503 }
504
505 for object in dataflow.objects_to_build {
507 let bundle = context.scope.clone().region_named(
508 &format!("BuildingObject({:?})", object.id),
509 |region| {
510 let depends = object.plan.depends();
511 context
512 .enter_region(region, Some(&depends))
513 .render_plan(object.id, object.plan)
514 .leave_region(context.scope)
515 },
516 );
517 let global_id = object.id;
518 context.log_dataflow_global_id(
519 *bundle
520 .scope()
521 .addr()
522 .first()
523 .expect("Dataflow root id must exist"),
524 global_id,
525 );
526 context.insert_id(Id::Global(object.id), bundle);
527 }
528
529 for (idx_id, dependencies, idx) in indexes {
531 context.export_index(
532 compute_state,
533 &tokens,
534 dependencies,
535 idx_id,
536 &idx,
537 &output_probe,
538 );
539 }
540
541 for (sink_id, dependencies, sink) in sinks {
543 context.export_sink(
544 compute_state,
545 &tokens,
546 dependencies,
547 sink_id,
548 &sink,
549 start_signal.clone(),
550 &output_probe,
551 scope,
552 );
553 }
554 });
555 }
556 });
557}
558
559impl<'g, T> Context<'g, T>
562where
563 T: Refines<mz_repr::Timestamp> + RenderTimestamp,
564{
565 fn import_filtered_index_collection<
569 'outer,
570 Tr: TraceReader<Time = mz_repr::Timestamp, Batch: Navigable> + Clone,
571 V: Data,
572 >(
573 &self,
574 arranged: Arranged<'outer, Tr>,
575 start_signal: StartSignal,
576 mut logic: impl FnMut(BatchKey<'_, Tr>, BatchVal<'_, Tr>) -> V + 'static,
577 ) -> VecCollection<'g, T, V, BatchDiff<Tr>>
578 where
579 mz_repr::Timestamp: TotalOrder,
582 BatchCursor<Tr>: Cursor<Time = mz_repr::Timestamp>,
583 {
584 let oks = arranged.stream.with_start_signal(start_signal).filter({
585 let as_of = self.as_of_frontier.clone();
586 move |b| !<Antichain<mz_repr::Timestamp> as PartialOrder>::less_equal(b.upper(), &as_of)
587 });
588 Arranged::<'outer, Tr>::flat_map_batches(oks, move |a, b| [logic(a, b)]).enter(self.scope)
589 }
590
591 pub(crate) fn import_index<'outer>(
592 &mut self,
593 outer: Scope<'outer, mz_repr::Timestamp>,
594 compute_state: &mut ComputeState,
595 tokens: &mut BTreeMap<GlobalId, Rc<dyn std::any::Any>>,
596 input_probe: probe::Handle<mz_repr::Timestamp>,
597 idx_id: GlobalId,
598 idx: &IndexDesc<LirScalarExpr>,
599 typ: &ReprRelationType,
600 snapshot_mode: SnapshotMode,
601 start_signal: StartSignal,
602 ) {
603 if let Some(traces) = compute_state.traces.get_mut(&idx_id) {
604 assert!(
605 PartialOrder::less_equal(&traces.compaction_frontier(), &self.as_of_frontier),
606 "Index {idx_id} has been allowed to compact beyond the dataflow as_of"
607 );
608
609 let token = traces.to_drop().clone();
610
611 let (mut oks, ok_button) = traces.oks_mut().import_frontier_core(
612 outer,
613 &format!("Index({}, {:?})", idx.on_id, idx.key),
614 self.as_of_frontier.clone(),
615 self.until.clone(),
616 );
617
618 oks.stream = oks.stream.probe_with(&input_probe);
619
620 let (err_arranged, err_button) = traces.errs_mut().import_frontier_core(
621 outer,
622 &format!("ErrIndex({}, {:?})", idx.on_id, idx.key),
623 self.as_of_frontier.clone(),
624 self.until.clone(),
625 );
626
627 let bundle = match snapshot_mode {
628 SnapshotMode::Include => {
629 let ok_arranged = oks
630 .enter(self.scope)
631 .with_start_signal(start_signal.clone());
632 let err_arranged = err_arranged
633 .enter(self.scope)
634 .with_start_signal(start_signal);
635 CollectionBundle::from_expressions(
636 idx.key.clone(),
637 ArrangementFlavor::Trace(idx_id, ok_arranged, err_arranged),
638 )
639 }
640 SnapshotMode::Exclude => {
641 let oks = {
648 let mut datums = DatumVec::new();
649 let (permutation, _thinning) =
650 permutation_for_arrangement(&idx.key, typ.arity());
651 self.import_filtered_index_collection(
652 oks,
653 start_signal.clone(),
654 move |k: DatumSeq, v: DatumSeq| {
655 let temp_storage = RowArena::new();
656 let mut datums_borrow = datums.borrow();
657 k.extend_datums(&temp_storage, &mut datums_borrow, None);
658 v.extend_datums(&temp_storage, &mut datums_borrow, None);
659 SharedRow::pack(permutation.iter().map(|i| datums_borrow[*i]))
660 },
661 )
662 };
663 let errs = self.import_filtered_index_collection(
664 err_arranged,
665 start_signal,
666 |e, _| e.clone(),
667 );
668 CollectionBundle::from_collections(oks, errs)
669 }
670 };
671 self.update_id(Id::Global(idx.on_id), bundle);
672 tokens.insert(
673 idx_id,
674 Rc::new((PressOnDrop(ok_button), PressOnDrop(err_button), token)),
675 );
676 } else {
677 panic!(
678 "import of index {} failed while building dataflow {}",
679 idx_id, self.dataflow_id
680 );
681 }
682 }
683}
684
685impl<'g> Context<'g, mz_repr::Timestamp> {
688 pub(crate) fn export_index(
689 &self,
690 compute_state: &mut ComputeState,
691 tokens: &BTreeMap<GlobalId, Rc<dyn std::any::Any>>,
692 dependency_ids: BTreeSet<GlobalId>,
693 idx_id: GlobalId,
694 idx: &IndexDesc<LirScalarExpr>,
695 output_probe: &MzProbeHandle<mz_repr::Timestamp>,
696 ) {
697 let mut needed_tokens = Vec::new();
699 for dep_id in dependency_ids {
700 if let Some(token) = tokens.get(&dep_id) {
701 needed_tokens.push(Rc::clone(token));
702 }
703 }
704 let bundle = self.lookup_id(Id::Global(idx_id)).unwrap_or_else(|| {
705 panic!(
706 "Arrangement alarmingly absent! id: {:?}",
707 Id::Global(idx_id)
708 )
709 });
710
711 let key = &idx.key;
712 match bundle.arrangement(key) {
713 Some(ArrangementFlavor::Local(mut oks, mut errs)) => {
714 if let Some(&expiration) = self.dataflow_expiration.as_option() {
717 oks.stream = oks.stream.expire_stream_at(
718 &format!("{}_export_index_oks", self.debug_name),
719 expiration,
720 );
721 errs.stream = errs.stream.expire_stream_at(
722 &format!("{}_export_index_errs", self.debug_name),
723 expiration,
724 );
725 }
726
727 oks.stream = oks.stream.probe_notify_with(vec![output_probe.clone()]);
728
729 if let Some(logger) = compute_state.compute_logger.clone() {
731 errs.stream = errs.stream.log_dataflow_errors(logger, idx_id);
732 }
733
734 compute_state.traces.set(
735 idx_id,
736 TraceBundle::new(oks.trace, errs.trace).with_drop(needed_tokens),
737 );
738 }
739 Some(ArrangementFlavor::Trace(gid, _, _)) => {
740 let trace = compute_state.traces.get(&gid).unwrap().clone();
743 compute_state.traces.set(idx_id, trace);
744 }
745 None => {
746 println!("collection available: {:?}", bundle.collection.is_none());
747 println!(
748 "keys available: {:?}",
749 bundle.arranged.keys().collect::<Vec<_>>()
750 );
751 panic!(
752 "Arrangement alarmingly absent! id: {:?}, keys: {:?}",
753 Id::Global(idx_id),
754 &key
755 );
756 }
757 };
758 }
759}
760
761impl<'g, T> Context<'g, T>
764where
765 T: RenderTimestamp,
766{
767 pub(crate) fn export_index_iterative<'outer>(
768 &self,
769 outer: Scope<'outer, mz_repr::Timestamp>,
770 compute_state: &mut ComputeState,
771 tokens: &BTreeMap<GlobalId, Rc<dyn std::any::Any>>,
772 dependency_ids: BTreeSet<GlobalId>,
773 idx_id: GlobalId,
774 idx: &IndexDesc<LirScalarExpr>,
775 output_probe: &MzProbeHandle<mz_repr::Timestamp>,
776 ) {
777 let mut needed_tokens = Vec::new();
779 for dep_id in dependency_ids {
780 if let Some(token) = tokens.get(&dep_id) {
781 needed_tokens.push(Rc::clone(token));
782 }
783 }
784 let bundle = self.lookup_id(Id::Global(idx_id)).unwrap_or_else(|| {
785 panic!(
786 "Arrangement alarmingly absent! id: {:?}",
787 Id::Global(idx_id)
788 )
789 });
790
791 let key = &idx.key;
792 match bundle.arrangement(key) {
793 Some(ArrangementFlavor::Local(oks, errs)) => {
794 let mut oks = oks
798 .as_collection(|k, v| (k.to_row(), v.to_row()))
799 .leave(outer)
800 .mz_arrange::<
801 ColumnationChunker<_>,
802 RowRowBatcher<_, _>,
803 RowRowBuilder<_, _>,
804 _,
805 >(
806 "Arrange export iterative",
807 );
808
809 let mut errs = errs
810 .as_collection(|k, v| (k.clone(), v.clone()))
811 .leave(outer)
812 .mz_arrange::<ColumnationChunker<_>, ErrBatcher<_, _>, ErrBuilder<_, _>, _>(
813 "Arrange export iterative err",
814 );
815
816 if let Some(&expiration) = self.dataflow_expiration.as_option() {
819 oks.stream = oks.stream.expire_stream_at(
820 &format!("{}_export_index_iterative_oks", self.debug_name),
821 expiration,
822 );
823 errs.stream = errs.stream.expire_stream_at(
824 &format!("{}_export_index_iterative_err", self.debug_name),
825 expiration,
826 );
827 }
828
829 oks.stream = oks.stream.probe_notify_with(vec![output_probe.clone()]);
830
831 if let Some(logger) = compute_state.compute_logger.clone() {
833 errs.stream = errs.stream.log_dataflow_errors(logger, idx_id);
834 }
835
836 compute_state.traces.set(
837 idx_id,
838 TraceBundle::new(oks.trace, errs.trace).with_drop(needed_tokens),
839 );
840 }
841 Some(ArrangementFlavor::Trace(gid, _, _)) => {
842 let trace = compute_state.traces.get(&gid).unwrap().clone();
845 compute_state.traces.set(idx_id, trace);
846 }
847 None => {
848 println!("collection available: {:?}", bundle.collection.is_none());
849 println!(
850 "keys available: {:?}",
851 bundle.arranged.keys().collect::<Vec<_>>()
852 );
853 panic!(
854 "Arrangement alarmingly absent! id: {:?}, keys: {:?}",
855 Id::Global(idx_id),
856 &key,
857 );
858 }
859 };
860 }
861}
862
863enum BindingInfo {
869 Body { in_let: bool },
870 Let { id: LocalId, last: bool },
871 LetRec { id: LocalId, last: bool },
872}
873
874impl<'scope> Context<'scope, Product<mz_repr::Timestamp, PointStamp<u64>>> {
875 fn render_recursive_plan(
888 &mut self,
889 object_id: GlobalId,
890 level: usize,
891 plan: RenderPlan,
892 binding: BindingInfo,
893 ) -> CollectionBundle<'scope, Product<mz_repr::Timestamp, PointStamp<u64>>> {
894 for BindStage { lets, recs } in plan.binds {
895 let mut let_iter = lets.into_iter().peekable();
897 while let Some(LetBind { id, value }) = let_iter.next() {
898 let bundle =
899 self.scope
900 .clone()
901 .region_named(&format!("Binding({:?})", id), |region| {
902 let depends = value.depends();
903 let last = let_iter.peek().is_none();
904 let binding = BindingInfo::Let { id, last };
905 self.enter_region(region, Some(&depends))
906 .render_letfree_plan(object_id, value, binding)
907 .leave_region(self.scope)
908 });
909 self.insert_id(Id::Local(id), bundle);
910 }
911
912 let rec_ids: Vec<_> = recs.iter().map(|r| r.id).collect();
913
914 let mut variables = BTreeMap::new();
918 for id in rec_ids.iter() {
919 use differential_dataflow::dynamic::feedback_summary;
920 let inner = feedback_summary::<u64>(level + 1, 1);
921 let (oks_v, oks_collection) =
922 Variable::new(self.scope, Product::new(Default::default(), inner.clone()));
923 let (err_v, err_collection) =
924 Variable::new(self.scope, Product::new(Default::default(), inner));
925
926 self.insert_id(
927 Id::Local(*id),
928 CollectionBundle::from_collections(oks_collection, err_collection),
929 );
930 variables.insert(Id::Local(*id), (oks_v, err_v));
931 }
932 let mut rec_iter = recs.into_iter().peekable();
934 while let Some(RecBind { id, value, limit }) = rec_iter.next() {
935 let last = rec_iter.peek().is_none();
936 let binding = BindingInfo::LetRec { id, last };
937 let bundle = self.render_recursive_plan(object_id, level + 1, value, binding);
938 let (oks, mut err) = bundle.collection.clone().unwrap();
941 let oks = oks.into_vec();
942 self.insert_id(Id::Local(id), bundle);
943 let (oks_v, err_v) = variables.remove(&Id::Local(id)).unwrap();
944
945 let mut oks = CollectionExt::consolidate_named::<KeyBatcher<_, _, _>>(
947 oks,
948 "LetRecConsolidation",
949 );
950
951 if let Some(limit) = limit {
952 let (in_limit, over_limit) =
955 oks.inner.branch_when(move |Product { inner: ps, .. }| {
956 let iteration_index = *ps.get(level).unwrap_or(&0);
958 iteration_index + 1 >= limit.max_iters.into()
960 });
961 oks = VecCollection::new(in_limit);
962 if !limit.return_at_limit {
963 err = err.concat(VecCollection::new(over_limit).map(move |_data| {
964 DataflowErrorSer::from(EvalError::LetRecLimitExceeded(
965 format!("{}", limit.max_iters.get()).into(),
966 ))
967 }));
968 }
969 }
970
971 let err: KeyCollection<_, _, _> = err.into();
977 let errs = err
978 .mz_arrange::<
979 ColumnationChunker<_>,
980 ErrBatcher<_, _>,
981 ErrBuilder<_, _>,
982 ErrSpine<_, _>,
983 >("Arrange recursive err")
984 .mz_reduce_abelian::<_, ErrBuilder<_, _>, ErrSpine<_, _>, _>(
985 "Distinct recursive err",
986 move |_k, _s, t| t.push(((), Diff::ONE)),
987 )
988 .as_collection(|k, _| k.clone());
989
990 oks_v.set(oks);
991 err_v.set(errs);
992 }
993 for id in rec_ids.into_iter() {
995 let bundle = self.remove_id(Id::Local(id)).unwrap();
996 let (oks, err) = bundle.collection.unwrap();
997 let oks = oks.into_vec();
998 self.insert_id(
999 Id::Local(id),
1000 CollectionBundle::from_collections(
1001 oks.leave_dynamic(level + 1),
1002 err.leave_dynamic(level + 1),
1003 ),
1004 );
1005 }
1006 }
1007
1008 self.render_letfree_plan(object_id, plan.body, binding)
1009 }
1010}
1011
1012impl<'scope, T: RenderTimestamp + MaybeBucketByTime> Context<'scope, T> {
1013 fn render_plan(
1024 &mut self,
1025 object_id: GlobalId,
1026 plan: RenderPlan,
1027 ) -> CollectionBundle<'scope, T> {
1028 let mut in_let = false;
1029 for BindStage { lets, recs } in plan.binds {
1030 assert!(recs.is_empty());
1031
1032 let mut let_iter = lets.into_iter().peekable();
1033 while let Some(LetBind { id, value }) = let_iter.next() {
1034 in_let = true;
1036 let bundle =
1037 self.scope
1038 .clone()
1039 .region_named(&format!("Binding({:?})", id), |region| {
1040 let depends = value.depends();
1041 let last = let_iter.peek().is_none();
1042 let binding = BindingInfo::Let { id, last };
1043 self.enter_region(region, Some(&depends))
1044 .render_letfree_plan(object_id, value, binding)
1045 .leave_region(self.scope)
1046 });
1047 self.insert_id(Id::Local(id), bundle);
1048 }
1049 }
1050
1051 self.scope.clone().region_named("Main Body", |region| {
1052 let depends = plan.body.depends();
1053 self.enter_region(region, Some(&depends))
1054 .render_letfree_plan(object_id, plan.body, BindingInfo::Body { in_let })
1055 .leave_region(self.scope)
1056 })
1057 }
1058
1059 fn render_letfree_plan(
1061 &self,
1062 object_id: GlobalId,
1063 plan: LetFreePlan,
1064 binding: BindingInfo,
1065 ) -> CollectionBundle<'scope, T> {
1066 let (mut nodes, root_id, topological_order) = plan.destruct();
1067
1068 let mut collections = BTreeMap::new();
1070
1071 let should_compute_lir_metadata = self.compute_logger.is_some();
1077 let mut lir_mapping_metadata = if should_compute_lir_metadata {
1078 Some(Vec::with_capacity(nodes.len()))
1079 } else {
1080 None
1081 };
1082
1083 let mut topo_iter = topological_order.into_iter().peekable();
1084 while let Some(lir_id) = topo_iter.next() {
1085 let node = nodes.remove(&lir_id).unwrap();
1086
1087 let metadata = if should_compute_lir_metadata {
1091 let operator = node.expr.humanize(&DummyHumanizer);
1092
1093 let operator = if topo_iter.peek().is_none() {
1095 match &binding {
1096 BindingInfo::Body { in_let: true } => format!("Returning {operator}"),
1097 BindingInfo::Body { in_let: false } => operator,
1098 BindingInfo::Let { id, last: true } => {
1099 format!("With {id} = {operator}")
1100 }
1101 BindingInfo::Let { id, last: false } => {
1102 format!("{id} = {operator}")
1103 }
1104 BindingInfo::LetRec { id, last: true } => {
1105 format!("With Recursive {id} = {operator}")
1106 }
1107 BindingInfo::LetRec { id, last: false } => {
1108 format!("{id} = {operator}")
1109 }
1110 }
1111 } else {
1112 operator
1113 };
1114
1115 let operator_id_start = self.scope.worker().peek_identifier();
1116 Some((operator, operator_id_start))
1117 } else {
1118 None
1119 };
1120
1121 let mut bundle = self.render_plan_expr(node.expr, &collections);
1122
1123 if let Some((operator, operator_id_start)) = metadata {
1124 let operator_id_end = self.scope.worker().peek_identifier();
1125 let operator_span = (operator_id_start, operator_id_end);
1126
1127 if let Some(lir_mapping_metadata) = &mut lir_mapping_metadata {
1128 lir_mapping_metadata.push((
1129 lir_id,
1130 LirMetadata::new(operator, node.parent, node.nesting, operator_span),
1131 ))
1132 }
1133 }
1134
1135 self.log_operator_hydration(&mut bundle, lir_id);
1136
1137 collections.insert(lir_id, bundle);
1138 }
1139
1140 if let Some(lir_mapping_metadata) = lir_mapping_metadata {
1141 self.log_lir_mapping(object_id, lir_mapping_metadata);
1142 }
1143
1144 collections
1145 .remove(&root_id)
1146 .expect("LetFreePlan invariant (1)")
1147 }
1148
1149 fn render_plan_expr(
1156 &self,
1157 expr: render_plan::Expr,
1158 collections: &BTreeMap<LirId, CollectionBundle<'scope, T>>,
1159 ) -> CollectionBundle<'scope, T> {
1160 use render_plan::Expr::*;
1161
1162 let expect_input = |id| {
1163 collections
1164 .get(&id)
1165 .cloned()
1166 .unwrap_or_else(|| panic!("missing input collection: {id}"))
1167 };
1168
1169 match expr {
1170 Constant { rows } => {
1171 let (rows, errs) = match rows {
1173 Ok(rows) => (rows, Vec::new()),
1174 Err(e) => (Vec::new(), vec![e]),
1175 };
1176
1177 let as_of_frontier = self.as_of_frontier.clone();
1179 let until = self.until.clone();
1180 let ok_collection = rows
1181 .into_iter()
1182 .filter_map(move |(row, mut time, diff)| {
1183 time.advance_by(as_of_frontier.borrow());
1184 if !until.less_equal(&time) {
1185 Some((
1186 row,
1187 <T as Refines<mz_repr::Timestamp>>::to_inner(time),
1188 diff,
1189 ))
1190 } else {
1191 None
1192 }
1193 })
1194 .to_stream(self.scope)
1195 .as_collection();
1196
1197 let mut error_time: mz_repr::Timestamp = Timestamp::minimum();
1198 error_time.advance_by(self.as_of_frontier.borrow());
1199 let err_collection = errs
1200 .into_iter()
1201 .map(move |e| {
1202 (
1203 DataflowErrorSer::from(e),
1204 <T as Refines<mz_repr::Timestamp>>::to_inner(error_time),
1205 Diff::ONE,
1206 )
1207 })
1208 .to_stream(self.scope)
1209 .as_collection();
1210
1211 CollectionBundle::from_collections(ok_collection, err_collection)
1212 }
1213 Get { id, keys, plan } => {
1214 let mut collection = self
1217 .lookup_id(id)
1218 .unwrap_or_else(|| panic!("Get({:?}) not found at render time", id));
1219 match plan {
1220 mz_compute_types::plan::GetPlan::PassArrangements => {
1221 assert!(
1223 keys.arranged
1224 .iter()
1225 .all(|(key, _, _)| collection.arranged.contains_key(key))
1226 );
1227 assert!(keys.raw <= collection.collection.is_some());
1228 collection.arranged.retain(|key, _value| {
1230 keys.arranged.iter().any(|(key2, _, _)| key2 == key)
1231 });
1232 collection
1233 }
1234 mz_compute_types::plan::GetPlan::Arrangement(key, row, mfp) => {
1235 let (oks, errs) = collection.as_collection_core(
1236 mfp,
1237 Some((key, row)),
1238 self.until.clone(),
1239 &self.config_set,
1240 );
1241 CollectionBundle::from_collections(oks, errs)
1242 }
1243 mz_compute_types::plan::GetPlan::Collection(mfp) => {
1244 let (oks, errs) = collection.as_collection_core(
1245 mfp,
1246 None,
1247 self.until.clone(),
1248 &self.config_set,
1249 );
1250 CollectionBundle::from_collections(oks, errs)
1251 }
1252 }
1253 }
1254 Mfp {
1255 input,
1256 mfp,
1257 input_key_val,
1258 } => {
1259 let input = expect_input(input);
1260 if mfp.is_identity() {
1262 input
1263 } else {
1264 let (oks, errs) = input.as_collection_core(
1265 mfp,
1266 input_key_val,
1267 self.until.clone(),
1268 &self.config_set,
1269 );
1270 CollectionBundle::from_collections(oks, errs)
1271 }
1272 }
1273 FlatMap {
1274 input_key,
1275 input,
1276 exprs,
1277 func,
1278 mfp_after: mfp,
1279 } => {
1280 let input = expect_input(input);
1281 self.render_flat_map(input_key, input, exprs, func, mfp)
1282 }
1283 Join { inputs, plan } => {
1284 let inputs = inputs.into_iter().map(expect_input).collect();
1285 match plan {
1286 mz_compute_types::plan::join::JoinPlan::Linear(linear_plan) => {
1287 self.render_join(inputs, linear_plan)
1288 }
1289 mz_compute_types::plan::join::JoinPlan::Delta(delta_plan) => {
1290 self.render_delta_join(inputs, delta_plan)
1291 }
1292 }
1293 }
1294 Reduce {
1295 input_key,
1296 input,
1297 key_val_plan,
1298 plan,
1299 mfp_after,
1300 temporal_bucketing_strategy,
1301 } => {
1302 let input = expect_input(input);
1303 let mfp_option = (!mfp_after.is_identity()).then_some(mfp_after);
1304 self.render_reduce(
1305 input_key,
1306 input,
1307 key_val_plan,
1308 plan,
1309 mfp_option,
1310 temporal_bucketing_strategy,
1311 )
1312 }
1313 TopK {
1314 input,
1315 top_k_plan,
1316 temporal_bucketing_strategy,
1317 } => {
1318 let input = expect_input(input);
1319 self.render_topk(input, top_k_plan, temporal_bucketing_strategy)
1320 }
1321 Negate { input } => {
1322 let input = expect_input(input);
1323 let (oks, errs) = input
1324 .collection
1325 .clone()
1326 .expect("Negate input must be an unarranged collection");
1327 CollectionBundle::from_edge(oks.negate(), errs)
1328 }
1329 Threshold {
1330 input,
1331 threshold_plan,
1332 } => {
1333 let input = expect_input(input);
1334 self.render_threshold(input, threshold_plan)
1335 }
1336 Union {
1337 inputs,
1338 consolidate_output,
1339 temporal_bucketing_strategies,
1340 } => {
1341 let mut oks = Vec::new();
1342 let mut errs = Vec::new();
1343 for (input, strategy) in inputs.into_iter().zip_eq(temporal_bucketing_strategies) {
1344 let (os, es) = expect_input(input)
1345 .collection
1346 .clone()
1347 .expect("Union input must be an unarranged collection");
1348 let os = if matches!(strategy, ArrangementStrategy::TemporalBucketing)
1352 && ENABLE_COMPUTE_TEMPORAL_BUCKETING.get(&self.config_set)
1353 {
1354 let summary: mz_repr::Timestamp = TEMPORAL_BUCKETING_SUMMARY
1355 .get(&self.config_set)
1356 .try_into()
1357 .expect("must fit");
1358 let os = os.into_vec();
1359 CollectionEdge::Vec(T::maybe_apply_temporal_bucketing(
1360 os.inner,
1361 self.as_of_frontier.clone(),
1362 summary,
1363 ))
1364 } else {
1365 os
1366 };
1367 oks.push(os);
1368 errs.push(es);
1369 }
1370 let oks = CollectionEdge::concat_many(self.scope, oks);
1371 let oks = if consolidate_output {
1372 oks.consolidate_named("UnionConsolidation")
1373 } else {
1374 oks
1375 };
1376 let errs = differential_dataflow::collection::concatenate(self.scope, errs);
1377 CollectionBundle::from_edge(oks, errs)
1378 }
1379 ArrangeBy {
1380 input_key,
1381 input,
1382 input_mfp,
1383 forms: keys,
1384 strategy,
1385 } => {
1386 let input = expect_input(input);
1387 input.ensure_collections(
1388 keys,
1389 input_key,
1390 input_mfp,
1391 self.as_of_frontier.clone(),
1392 self.until.clone(),
1393 &self.config_set,
1394 strategy,
1395 )
1396 }
1397 }
1398 }
1399
1400 fn log_dataflow_global_id(&self, dataflow_index: usize, global_id: GlobalId) {
1401 if let Some(logger) = &self.compute_logger {
1402 logger.log(&ComputeEvent::DataflowGlobal(DataflowGlobal {
1403 dataflow_index,
1404 global_id,
1405 }));
1406 }
1407 }
1408
1409 fn log_lir_mapping(&self, global_id: GlobalId, mapping: Vec<(LirId, LirMetadata)>) {
1410 if let Some(logger) = &self.compute_logger {
1411 logger.log(&ComputeEvent::LirMapping(LirMapping { global_id, mapping }));
1412 }
1413 }
1414
1415 fn log_operator_hydration(&self, bundle: &mut CollectionBundle<'scope, T>, lir_id: LirId) {
1416 match bundle.arranged.values_mut().next() {
1436 Some(arrangement) => {
1437 use ArrangementFlavor::*;
1438
1439 match arrangement {
1440 Local(a, _) => {
1441 a.stream = self.log_operator_hydration_inner(a.stream.clone(), lir_id);
1442 }
1443 Trace(_, a, _) => {
1444 a.stream = self.log_operator_hydration_inner(a.stream.clone(), lir_id);
1445 }
1446 }
1447 }
1448 None => {
1449 let (oks, _) = bundle
1450 .collection
1451 .as_mut()
1452 .expect("CollectionBundle invariant");
1453 match oks {
1454 CollectionEdge::Vec(c) => {
1455 let stream = self.log_operator_hydration_inner(c.inner.clone(), lir_id);
1456 *c = stream.as_collection();
1457 }
1458 CollectionEdge::Columnar(c) => {
1459 let stream = self.log_operator_hydration_inner(c.inner.clone(), lir_id);
1460 *c = stream.as_collection();
1461 }
1462 }
1463 }
1464 }
1465 }
1466
1467 fn log_operator_hydration_inner<D>(
1468 &self,
1469 stream: Stream<'scope, T, D>,
1470 lir_id: LirId,
1471 ) -> Stream<'scope, T, D>
1472 where
1473 D: timely::Container + Clone + 'static,
1474 {
1475 let Some(logger) = self.compute_logger.clone() else {
1476 return stream.clone(); };
1478
1479 let export_ids = self.export_ids.clone();
1480
1481 let mut hydration_frontier = Antichain::new();
1489 for time in self.as_of_frontier.iter() {
1490 if let Some(time) = time.try_step_forward() {
1491 hydration_frontier.insert(Refines::to_inner(time));
1492 }
1493 }
1494
1495 let name = format!("LogOperatorHydration ({lir_id})");
1496 stream.unary_frontier(Pipeline, &name, |_cap, _info| {
1497 let mut hydrated = false;
1498
1499 for &export_id in &export_ids {
1500 logger.log(&ComputeEvent::OperatorHydration(OperatorHydration {
1501 export_id,
1502 lir_id,
1503 hydrated,
1504 }));
1505 }
1506
1507 move |(input, frontier), output| {
1508 input.for_each(|cap, data| {
1510 output.session(&cap).give_container(data);
1511 });
1512
1513 if hydrated {
1514 return;
1515 }
1516
1517 if PartialOrder::less_equal(&hydration_frontier.borrow(), &frontier.frontier()) {
1518 hydrated = true;
1519
1520 for &export_id in &export_ids {
1521 logger.log(&ComputeEvent::OperatorHydration(OperatorHydration {
1522 export_id,
1523 lir_id,
1524 hydrated,
1525 }));
1526 }
1527 }
1528 }
1529 })
1530 }
1531}
1532
1533#[allow(dead_code)] pub trait RenderTimestamp: MzTimestamp + Default + Refines<mz_repr::Timestamp> {
1536 fn system_time(&mut self) -> &mut mz_repr::Timestamp;
1541 fn system_delay(delay: mz_repr::Timestamp) -> <Self as Timestamp>::Summary;
1543 fn event_time(&self) -> mz_repr::Timestamp;
1545 fn event_time_mut(&mut self) -> &mut mz_repr::Timestamp;
1547 fn event_delay(delay: mz_repr::Timestamp) -> <Self as Timestamp>::Summary;
1549 fn step_back(&self) -> Self;
1552}
1553
1554pub trait MaybeBucketByTime: Timestamp {
1561 fn maybe_apply_temporal_bucketing<'scope, D>(
1562 stream: StreamVec<'scope, Self, (D, Self, Diff)>,
1563 as_of: Antichain<mz_repr::Timestamp>,
1564 summary: mz_repr::Timestamp,
1565 ) -> VecCollection<'scope, Self, D, Diff>
1566 where
1567 D: differential_dataflow::ExchangeData
1568 + crate::typedefs::MzData
1569 + differential_dataflow::Hashable;
1570}
1571
1572impl RenderTimestamp for mz_repr::Timestamp {
1573 fn system_time(&mut self) -> &mut mz_repr::Timestamp {
1574 self
1575 }
1576 fn system_delay(delay: mz_repr::Timestamp) -> <Self as Timestamp>::Summary {
1577 delay
1578 }
1579 fn event_time(&self) -> mz_repr::Timestamp {
1580 *self
1581 }
1582 fn event_time_mut(&mut self) -> &mut mz_repr::Timestamp {
1583 self
1584 }
1585 fn event_delay(delay: mz_repr::Timestamp) -> <Self as Timestamp>::Summary {
1586 delay
1587 }
1588 fn step_back(&self) -> Self {
1589 self.saturating_sub(1)
1590 }
1591}
1592
1593impl MaybeBucketByTime for mz_repr::Timestamp {
1594 fn maybe_apply_temporal_bucketing<'scope, D>(
1595 stream: StreamVec<'scope, Self, (D, Self, Diff)>,
1596 as_of: Antichain<mz_repr::Timestamp>,
1597 summary: mz_repr::Timestamp,
1598 ) -> VecCollection<'scope, Self, D, Diff>
1599 where
1600 D: differential_dataflow::ExchangeData
1601 + crate::typedefs::MzData
1602 + differential_dataflow::Hashable,
1603 {
1604 stream
1605 .bucket::<CapacityContainerBuilder<_>>(as_of, summary)
1606 .as_collection()
1607 }
1608}
1609
1610impl RenderTimestamp for Product<mz_repr::Timestamp, PointStamp<u64>> {
1611 fn system_time(&mut self) -> &mut mz_repr::Timestamp {
1612 &mut self.outer
1613 }
1614 fn system_delay(delay: mz_repr::Timestamp) -> <Self as Timestamp>::Summary {
1615 Product::new(delay, Default::default())
1616 }
1617 fn event_time(&self) -> mz_repr::Timestamp {
1618 self.outer
1619 }
1620 fn event_time_mut(&mut self) -> &mut mz_repr::Timestamp {
1621 &mut self.outer
1622 }
1623 fn event_delay(delay: mz_repr::Timestamp) -> <Self as Timestamp>::Summary {
1624 Product::new(delay, Default::default())
1625 }
1626 fn step_back(&self) -> Self {
1627 let inner = self.inner.clone();
1631 let mut vec = inner.into_inner();
1632 for item in vec.iter_mut() {
1633 *item = item.saturating_sub(1);
1634 }
1635 Product::new(self.outer.saturating_sub(1), PointStamp::new(vec))
1636 }
1637}
1638
1639impl MaybeBucketByTime for Product<mz_repr::Timestamp, PointStamp<u64>> {
1640 fn maybe_apply_temporal_bucketing<'scope, D>(
1641 stream: StreamVec<'scope, Self, (D, Self, Diff)>,
1642 _as_of: Antichain<mz_repr::Timestamp>,
1643 _summary: mz_repr::Timestamp,
1644 ) -> VecCollection<'scope, Self, D, Diff>
1645 where
1646 D: differential_dataflow::ExchangeData
1647 + crate::typedefs::MzData
1648 + differential_dataflow::Hashable,
1649 {
1650 stream.as_collection()
1652 }
1653}
1654
1655#[derive(Clone)]
1665pub(crate) struct StartSignal {
1666 fut: futures::future::Shared<oneshot::Receiver<Infallible>>,
1671 token_ref: Weak<RefCell<Box<dyn Any>>>,
1673}
1674
1675impl StartSignal {
1676 pub fn new() -> (Self, Rc<dyn Any>) {
1679 let (tx, rx) = oneshot::channel::<Infallible>();
1680 let token: Rc<RefCell<Box<dyn Any>>> = Rc::new(RefCell::new(Box::new(tx)));
1681 let signal = Self {
1682 fut: rx.shared(),
1683 token_ref: Rc::downgrade(&token),
1684 };
1685 (signal, token)
1686 }
1687
1688 pub fn has_fired(&self) -> bool {
1689 self.token_ref.strong_count() == 0
1690 }
1691
1692 pub fn into_send_future(self) -> impl Future<Output = ()> + Send {
1697 use futures::FutureExt;
1698 self.fut.map(|_| ())
1699 }
1700
1701 pub fn drop_on_fire(&self, to_drop: Box<dyn Any>) {
1702 if let Some(token) = self.token_ref.upgrade() {
1703 let mut token = token.borrow_mut();
1704 let inner = std::mem::replace(&mut *token, Box::new(()));
1705 *token = Box::new((inner, to_drop));
1706 }
1707 }
1708}
1709
1710impl Future for StartSignal {
1711 type Output = ();
1712
1713 fn poll(mut self: Pin<&mut Self>, cx: &mut std::task::Context<'_>) -> Poll<Self::Output> {
1714 self.fut.poll_unpin(cx).map(|_| ())
1715 }
1716}
1717
1718pub(crate) trait WithStartSignal {
1720 fn with_start_signal(self, signal: StartSignal) -> Self;
1725}
1726
1727impl<'scope, Tr> WithStartSignal for Arranged<'scope, Tr>
1728where
1729 Tr: TraceReader<Time: RenderTimestamp> + Clone,
1730{
1731 fn with_start_signal(self, signal: StartSignal) -> Self {
1732 Arranged {
1733 stream: self.stream.with_start_signal(signal),
1734 trace: self.trace,
1735 }
1736 }
1737}
1738
1739impl<'scope, T: Timestamp, D> WithStartSignal for Stream<'scope, T, D>
1740where
1741 D: timely::Container + Clone + 'static,
1742{
1743 fn with_start_signal(self, signal: StartSignal) -> Self {
1744 let activations = self.scope().activations();
1745 self.unary(Pipeline, "StartSignal", |_cap, info| {
1746 let token = Box::new(ActivateOnDrop::new((), info.address, activations));
1747 signal.drop_on_fire(token);
1748
1749 let mut stash = Vec::new();
1750
1751 move |input, output| {
1752 if !signal.has_fired() {
1754 input.for_each(|cap, data| stash.push((cap, std::mem::take(data))));
1755 return;
1756 }
1757
1758 for (cap, mut data) in std::mem::take(&mut stash) {
1760 output.session(&cap).give_container(&mut data);
1761 }
1762
1763 input.for_each(|cap, data| {
1765 output.session(&cap).give_container(data);
1766 });
1767 }
1768 })
1769 }
1770}
1771
1772fn suppress_early_progress<'scope, T: Timestamp, D>(
1794 stream: Stream<'scope, T, D>,
1795 as_of: Antichain<T>,
1796) -> Stream<'scope, T, D>
1797where
1798 D: Data + timely::Container,
1799{
1800 stream.unary_frontier(Pipeline, "SuppressEarlyProgress", |default_cap, _info| {
1801 let mut early_cap = Some(default_cap);
1802
1803 move |(input, frontier), output| {
1804 input.for_each_time(|data_cap, data| {
1805 if as_of.less_than(data_cap.time()) {
1806 let mut session = output.session(&data_cap);
1807 for data in data {
1808 session.give_container(data);
1809 }
1810 } else {
1811 let cap = early_cap.as_ref().expect("early_cap can't be dropped yet");
1812 let mut session = output.session(&cap);
1813 for data in data {
1814 session.give_container(data);
1815 }
1816 }
1817 });
1818
1819 if !PartialOrder::less_equal(&frontier.frontier(), &as_of.borrow()) {
1820 early_cap.take();
1821 }
1822 }
1823 })
1824}
1825
1826trait LimitProgress<T: Timestamp> {
1828 fn limit_progress(
1856 self,
1857 handle: MzProbeHandle<T>,
1858 slack_ms: u64,
1859 limit: Option<usize>,
1860 upper: Antichain<T>,
1861 name: String,
1862 ) -> Self;
1863}
1864
1865impl<'scope, D, R> LimitProgress<mz_repr::Timestamp>
1868 for StreamVec<'scope, mz_repr::Timestamp, (D, mz_repr::Timestamp, R)>
1869where
1870 D: Clone + 'static,
1871 R: Clone + 'static,
1872{
1873 fn limit_progress(
1874 self,
1875 handle: MzProbeHandle<mz_repr::Timestamp>,
1876 slack_ms: u64,
1877 limit: Option<usize>,
1878 upper: Antichain<mz_repr::Timestamp>,
1879 name: String,
1880 ) -> Self {
1881 let scope = self.scope();
1882 let stream =
1883 self.unary_frontier(Pipeline, &format!("LimitProgress({name})"), |_cap, info| {
1884 let mut pending_times: BTreeSet<mz_repr::Timestamp> = BTreeSet::new();
1886 let mut retained_cap: Option<Capability<mz_repr::Timestamp>> = None;
1888
1889 let activator = scope.activator_for(info.address);
1890 handle.activate(activator.clone());
1891
1892 move |(input, frontier), output| {
1893 input.for_each(|cap, data| {
1894 for time in data
1895 .iter()
1896 .flat_map(|(_, time, _)| u64::from(time).checked_add(slack_ms))
1897 {
1898 let rounded_time = if slack_ms == 0 {
1902 time
1903 } else {
1904 (time / slack_ms).saturating_add(1).saturating_mul(slack_ms)
1905 };
1906 if !upper.less_than(&rounded_time.into()) {
1907 pending_times.insert(rounded_time.into());
1908 }
1909 }
1910 output.session(&cap).give_container(data);
1911 if retained_cap.as_ref().is_none_or(|c| {
1912 !c.time().less_than(cap.time()) && !upper.less_than(cap.time())
1913 }) {
1914 retained_cap = Some(cap.retain(0));
1915 }
1916 });
1917
1918 handle.with_frontier(|f| {
1919 while pending_times
1920 .first()
1921 .map_or(false, |retained_time| !f.less_than(&retained_time))
1922 {
1923 let _ = pending_times.pop_first();
1924 }
1925 });
1926
1927 while limit.map_or(false, |limit| pending_times.len() > limit) {
1928 let _ = pending_times.pop_first();
1929 }
1930
1931 match (retained_cap.as_mut(), pending_times.first()) {
1932 (Some(cap), Some(first)) => cap.downgrade(first),
1933 (_, None) => retained_cap = None,
1934 _ => {}
1935 }
1936
1937 if frontier.is_empty() {
1938 retained_cap = None;
1939 pending_times.clear();
1940 }
1941
1942 if !pending_times.is_empty() {
1943 tracing::debug!(
1944 name,
1945 info.global_id,
1946 pending_times = %PendingTimesDisplay(pending_times.iter().cloned()),
1947 frontier = ?frontier.frontier().get(0),
1948 probe = ?handle.with_frontier(|f| f.get(0).cloned()),
1949 ?upper,
1950 "pending times",
1951 );
1952 }
1953 }
1954 });
1955 stream
1956 }
1957}
1958
1959struct PendingTimesDisplay<T>(T);
1962
1963impl<T> std::fmt::Display for PendingTimesDisplay<T>
1964where
1965 T: IntoIterator<Item = mz_repr::Timestamp> + Clone,
1966{
1967 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1968 let mut iter = self.0.clone().into_iter();
1969 write!(f, "[")?;
1970 if let Some(first) = iter.next() {
1971 write!(f, "{}", first)?;
1972 let mut last = u64::from(first);
1973 for time in iter {
1974 write!(f, ", +{}", u64::from(time) - last)?;
1975 last = u64::from(time);
1976 }
1977 }
1978 write!(f, "]")?;
1979 Ok(())
1980 }
1981}
1982
1983#[derive(Clone, Copy, Debug)]
1986struct Pairer {
1987 split_arity: usize,
1988}
1989
1990impl Pairer {
1991 fn new(split_arity: usize) -> Self {
1993 Self { split_arity }
1994 }
1995
1996 fn merge<'a, I1, I2>(&self, first: I1, second: I2) -> Row
1998 where
1999 I1: IntoIterator<Item = Datum<'a>>,
2000 I2: IntoIterator<Item = Datum<'a>>,
2001 {
2002 SharedRow::pack(first.into_iter().chain(second))
2003 }
2004
2005 fn split<'a>(&self, datum_iter: impl IntoIterator<Item = Datum<'a>>) -> (Row, Row) {
2007 let mut datum_iter = datum_iter.into_iter();
2008 let mut row_builder = SharedRow::get();
2009 let first = row_builder.pack_using(datum_iter.by_ref().take(self.split_arity));
2010 let second = row_builder.pack_using(datum_iter);
2011 (first, second)
2012 }
2013}