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 ::columnar::{Columnar as ColumnarData, Index as ColumnarIndex, Push as ColumnarPush};
114use differential_dataflow::dynamic::pointstamp::PointStamp;
115use differential_dataflow::lattice::Lattice;
116use differential_dataflow::operators::arrange::Arranged;
117use differential_dataflow::operators::arrange::ShutdownButton;
118use differential_dataflow::operators::iterate::Variable;
119use differential_dataflow::trace::cursor::{BatchCursor, BatchDiff, BatchKey, BatchVal};
120use differential_dataflow::trace::{BatchReader, Cursor, Navigable, TraceReader};
121use differential_dataflow::{AsCollection, Collection, Data, VecCollection};
122use futures::FutureExt;
123use futures::channel::oneshot;
124use itertools::Itertools;
125use mz_compute_types::dataflows::{IndexDesc, RenderDataflowDescription};
126use mz_compute_types::dyncfgs::{
127 COMPUTE_APPLY_COLUMN_DEMANDS, COMPUTE_LOGICAL_BACKPRESSURE_INFLIGHT_SLACK,
128 COMPUTE_LOGICAL_BACKPRESSURE_MAX_RETAINED_CAPABILITIES, ENABLE_COMPUTE_LOGICAL_BACKPRESSURE,
129 ENABLE_ERROR_DISTINCT, SUBSCRIBE_SNAPSHOT_OPTIMIZATION, TEMPORAL_BUCKETING_SUMMARY,
130};
131use mz_compute_types::plan::render_plan::{
132 self, BindStage, LetBind, LetFreePlan, RecBind, RenderPlan,
133};
134use mz_compute_types::plan::scalar::LirScalarExpr;
135use mz_compute_types::plan::{ArrangementStrategy, LirId};
136use mz_expr::{EvalError, Id, LocalId, permutation_for_arrangement};
137use mz_persist_client::operators::shard_source::{ErrorHandler, SnapshotMode};
138use mz_repr::explain::DummyHumanizer;
139use mz_repr::fixed_length::ExtendDatums;
140use mz_repr::{Datum, DatumVec, Diff, GlobalId, ReprRelationType, Row, RowArena, SharedRow};
141use mz_storage_operators::persist_source;
142use mz_storage_types::controller::CollectionMetadata;
143use mz_timely_util::columnar::Column;
144use mz_timely_util::columnar::builder::ColumnBuilder;
145use mz_timely_util::columnation::ColumnationChunker;
146use mz_timely_util::operator::StreamExt;
147use mz_timely_util::probe::{Handle as MzProbeHandle, ProbeNotify};
148use mz_timely_util::scope_label::ScopeExt;
149use timely::PartialOrder;
150use timely::container::CapacityContainerBuilder;
151use timely::dataflow::channels::pact::Pipeline;
152use timely::dataflow::operators::core::to_stream::ToStreamBuilder;
153use timely::dataflow::operators::vec::Filter;
154use timely::dataflow::operators::vec::ToStream;
155use timely::dataflow::operators::{Capability, Operator, Probe, probe};
156use timely::dataflow::{Scope, Stream, StreamVec};
157use timely::order::{Product, TotalOrder};
158use timely::progress::timestamp::Refines;
159use timely::progress::{Antichain, Timestamp};
160use timely::scheduling::ActivateOnDrop;
161use timely::worker::Worker as TimelyWorker;
162
163use crate::arrangement::manager::TraceBundle;
164use crate::compute_state::ComputeState;
165use crate::extensions::arrange::{KeyCollection, MzArrange};
166use crate::extensions::reduce::MzReduce;
167use crate::extensions::temporal_bucket::TemporalBucketing;
168use crate::logging::compute::{
169 ComputeEvent, DataflowGlobal, LirMapping, LirMetadata, LogDataflowErrors, OperatorHydration,
170};
171use crate::render::columnar::{
172 ColCollection, RecTimestamp, columnar_consolidate, columnar_leave_dynamic, columnar_negate,
173 concat_many, flat_map_datums,
174};
175use crate::render::context::{ArrangementFlavor, Context};
176use crate::render::errors::DataflowErrorSer;
177use crate::typedefs::{ErrBatcher, ErrBuilder, ErrSpine, MzTimestamp};
178use mz_row_spine::{DatumSeq, RowRowBatcher, RowRowBuilder};
179use mz_timely_util::columnar::consolidate::ConsolidatingColumnBuilder;
180
181pub(crate) mod columnar;
182pub mod context;
183pub(crate) mod errors;
184mod flat_map;
185mod join;
186mod reduce;
187pub mod sinks;
188mod threshold;
189mod top_k;
190
191pub use context::CollectionBundle;
192pub use join::LinearJoinSpec;
193
194struct PressOnDrop<T>(ShutdownButton<T>);
198
199impl<T> Drop for PressOnDrop<T> {
200 fn drop(&mut self) {
201 self.0.press();
202 }
203}
204
205pub fn build_compute_dataflow(
211 timely_worker: &mut TimelyWorker,
212 compute_state: &mut ComputeState,
213 dataflow: RenderDataflowDescription<CollectionMetadata>,
214 start_signal: StartSignal,
215 until: Antichain<mz_repr::Timestamp>,
216 dataflow_expiration: Antichain<mz_repr::Timestamp>,
217) {
218 let recursive = dataflow
220 .objects_to_build
221 .iter()
222 .any(|object| object.plan.is_recursive());
223
224 let indexes = dataflow
226 .index_exports
227 .iter()
228 .map(|(idx_id, (idx, _typ))| (*idx_id, dataflow.depends_on(idx.on_id), idx.as_lir()))
229 .collect::<Vec<_>>();
230
231 let sinks = dataflow
233 .sink_exports
234 .iter()
235 .map(|(sink_id, sink)| (*sink_id, dataflow.depends_on(sink.from), sink.clone()))
236 .collect::<Vec<_>>();
237
238 let worker_logging = timely_worker.logger_for("timely").map(Into::into);
239 let apply_demands = COMPUTE_APPLY_COLUMN_DEMANDS.get(&compute_state.worker_config);
240 let subscribe_snapshot_optimization =
241 SUBSCRIBE_SNAPSHOT_OPTIMIZATION.get(&compute_state.worker_config);
242
243 let name = format!("Dataflow: {}", dataflow.debug_name);
244 let input_name = format!("InputRegion: {}", dataflow.debug_name);
245 let build_name = format!("BuildRegion: {}", dataflow.debug_name);
246
247 timely_worker.dataflow_core(&name, worker_logging, Box::new(()), |_, scope| {
248 let scope = scope.with_label();
249
250 let mut imported_sources = Vec::new();
255 let mut tokens: BTreeMap<_, Rc<dyn Any>> = BTreeMap::new();
256 let output_probe = MzProbeHandle::default();
257
258 scope.clone().region_named(&input_name, |region| {
259 for (source_id, import) in dataflow.source_imports.iter() {
261 region.region_named(&format!("Source({:?})", source_id), |inner| {
262 let mut read_schema = None;
263 let mut mfp = import.desc.arguments.operators.clone().map(|mut ops| {
264 if apply_demands {
267 let demands = ops.demand();
268 let new_desc = import
269 .desc
270 .storage_metadata
271 .relation_desc
272 .apply_demand(&demands);
273 let new_arity = demands.len();
274 let remap: BTreeMap<_, _> = demands
275 .into_iter()
276 .enumerate()
277 .map(|(new, old)| (old, new))
278 .collect();
279 ops.permute_fn(|old_idx| remap[&old_idx], new_arity);
280 read_schema = Some(new_desc);
281 }
282
283 ops
284 });
285
286 let snapshot_mode = if import.with_snapshot || !subscribe_snapshot_optimization
287 {
288 SnapshotMode::Include
289 } else {
290 compute_state.metrics.inc_subscribe_snapshot_optimization();
291 SnapshotMode::Exclude
292 };
293 let suppress_early_progress_as_of = dataflow.as_of.clone();
294
295 let (mut ok_stream, err_stream, token) = persist_source::persist_source::<
298 DataflowErrorSer,
299 ConsolidatingColumnBuilder<Row, mz_repr::Timestamp, Diff>,
300 >(
301 inner,
302 *source_id,
303 Arc::clone(&compute_state.persist_clients),
304 &compute_state.txns_ctx,
305 import.desc.storage_metadata.clone(),
306 read_schema,
307 dataflow.as_of.clone(),
308 snapshot_mode,
309 until.clone(),
310 mfp.as_mut(),
311 compute_state.dataflow_max_inflight_bytes(),
312 start_signal.clone().into_send_future(),
313 ErrorHandler::Halt("compute_import"),
314 );
315
316 assert!(mfp.map(|x| x.is_identity()).unwrap_or(true));
319
320 if let Some(as_of) = suppress_early_progress_as_of {
324 ok_stream = suppress_early_progress(ok_stream, as_of);
325 }
326
327 if ENABLE_COMPUTE_LOGICAL_BACKPRESSURE.get(&compute_state.worker_config) {
328 let limit = COMPUTE_LOGICAL_BACKPRESSURE_MAX_RETAINED_CAPABILITIES
330 .get(&compute_state.worker_config);
331 let slack = COMPUTE_LOGICAL_BACKPRESSURE_INFLIGHT_SLACK
332 .get(&compute_state.worker_config)
333 .as_millis()
334 .try_into()
335 .expect("must fit");
336
337 let stream = ok_stream.limit_progress(
338 output_probe.clone(),
339 slack,
340 limit,
341 import.upper.clone(),
342 name.clone(),
343 );
344 ok_stream = stream;
345 }
346
347 let input_probe =
349 compute_state.input_probe_for(*source_id, dataflow.export_ids());
350 ok_stream = ok_stream.probe_with(&input_probe);
351
352 let (oks, errs) = (
353 ok_stream
354 .as_collection()
355 .leave_region(region)
356 .leave_region(scope),
357 err_stream
358 .as_collection()
359 .leave_region(region)
360 .leave_region(scope),
361 );
362
363 imported_sources.push((mz_expr::Id::Global(*source_id), (oks, errs)));
364
365 tokens.insert(*source_id, Rc::new(token));
367 });
368 }
369 });
370
371 if recursive {
374 scope.clone().iterative::<PointStamp<u64>, _, _>(|region| {
375 let mut context = Context::for_dataflow_in(
376 &dataflow,
377 region.clone(),
378 compute_state,
379 until,
380 dataflow_expiration,
381 );
382
383 for (id, (oks, errs)) in imported_sources.into_iter() {
384 let bundle = crate::render::CollectionBundle::from_edge(
385 oks.enter(region),
386 errs.enter(region),
387 );
388 context.insert_id(id, bundle);
390 }
391
392 for (idx_id, idx) in &dataflow.index_imports {
394 let input_probe = compute_state.input_probe_for(*idx_id, dataflow.export_ids());
395 let snapshot_mode = if idx.with_snapshot || !subscribe_snapshot_optimization {
396 SnapshotMode::Include
397 } else {
398 compute_state.metrics.inc_subscribe_snapshot_optimization();
399 SnapshotMode::Exclude
400 };
401 context.import_index(
402 scope,
403 compute_state,
404 &mut tokens,
405 input_probe,
406 *idx_id,
407 &idx.desc.as_lir(),
408 &idx.typ,
409 snapshot_mode,
410 start_signal.clone(),
411 );
412 }
413
414 for object in dataflow.objects_to_build {
416 let bundle = context.scope.clone().region_named(
417 &format!("BuildingObject({:?})", object.id),
418 |region| {
419 let depends = object.plan.depends();
420 let in_let = object.plan.is_recursive();
421 context
422 .enter_region(region, Some(&depends))
423 .render_recursive_plan(
424 object.id,
425 0,
426 object.plan,
427 BindingInfo::Body { in_let },
429 )
430 .leave_region(context.scope)
431 },
432 );
433 let global_id = object.id;
434
435 context.log_dataflow_global_id(
436 *bundle
437 .scope()
438 .addr()
439 .first()
440 .expect("Dataflow root id must exist"),
441 global_id,
442 );
443 context.insert_id(Id::Global(object.id), bundle);
444 }
445
446 for (idx_id, dependencies, idx) in indexes {
448 context.export_index_iterative(
449 scope,
450 compute_state,
451 &tokens,
452 dependencies,
453 idx_id,
454 &idx,
455 &output_probe,
456 );
457 }
458
459 for (sink_id, dependencies, sink) in sinks {
461 context.export_sink(
462 compute_state,
463 &tokens,
464 dependencies,
465 sink_id,
466 &sink,
467 start_signal.clone(),
468 &output_probe,
469 scope,
470 );
471 }
472 });
473 } else {
474 scope.clone().region_named(&build_name, |region| {
475 let mut context = Context::for_dataflow_in(
476 &dataflow,
477 region.clone(),
478 compute_state,
479 until,
480 dataflow_expiration,
481 );
482
483 for (id, (oks, errs)) in imported_sources.into_iter() {
484 let bundle = crate::render::CollectionBundle::from_edge(
485 oks.enter_region(region),
486 errs.enter_region(region),
487 );
488 context.insert_id(id, bundle);
490 }
491
492 for (idx_id, idx) in &dataflow.index_imports {
494 let input_probe = compute_state.input_probe_for(*idx_id, dataflow.export_ids());
495 let snapshot_mode = if idx.with_snapshot || !subscribe_snapshot_optimization {
496 SnapshotMode::Include
497 } else {
498 compute_state.metrics.inc_subscribe_snapshot_optimization();
499 SnapshotMode::Exclude
500 };
501 context.import_index(
502 scope,
503 compute_state,
504 &mut tokens,
505 input_probe,
506 *idx_id,
507 &idx.desc.as_lir(),
508 &idx.typ,
509 snapshot_mode,
510 start_signal.clone(),
511 );
512 }
513
514 for object in dataflow.objects_to_build {
516 let bundle = context.scope.clone().region_named(
517 &format!("BuildingObject({:?})", object.id),
518 |region| {
519 let depends = object.plan.depends();
520 context
521 .enter_region(region, Some(&depends))
522 .render_plan(object.id, object.plan)
523 .leave_region(context.scope)
524 },
525 );
526 let global_id = object.id;
527 context.log_dataflow_global_id(
528 *bundle
529 .scope()
530 .addr()
531 .first()
532 .expect("Dataflow root id must exist"),
533 global_id,
534 );
535 context.insert_id(Id::Global(object.id), bundle);
536 }
537
538 for (idx_id, dependencies, idx) in indexes {
540 context.export_index(
541 compute_state,
542 &tokens,
543 dependencies,
544 idx_id,
545 &idx,
546 &output_probe,
547 );
548 }
549
550 for (sink_id, dependencies, sink) in sinks {
552 context.export_sink(
553 compute_state,
554 &tokens,
555 dependencies,
556 sink_id,
557 &sink,
558 start_signal.clone(),
559 &output_probe,
560 scope,
561 );
562 }
563 });
564 }
565 });
566}
567
568impl<'g, T> Context<'g, T>
571where
572 T: Refines<mz_repr::Timestamp> + RenderTimestamp,
573{
574 fn import_filtered_index_collection<
578 'outer,
579 Tr: TraceReader<Time = mz_repr::Timestamp, Batch: Navigable> + Clone,
580 V: Data,
581 >(
582 &self,
583 arranged: Arranged<'outer, Tr>,
584 start_signal: StartSignal,
585 mut logic: impl FnMut(BatchKey<'_, Tr>, BatchVal<'_, Tr>) -> V + 'static,
586 ) -> VecCollection<'g, T, V, BatchDiff<Tr>>
587 where
588 mz_repr::Timestamp: TotalOrder,
591 BatchCursor<Tr>: Cursor<Time = mz_repr::Timestamp>,
592 {
593 let oks = arranged.stream.with_start_signal(start_signal).filter({
594 let as_of = self.as_of_frontier.clone();
595 move |b| !<Antichain<mz_repr::Timestamp> as PartialOrder>::less_equal(b.upper(), &as_of)
596 });
597 Arranged::<'outer, Tr>::flat_map_batches(oks, move |a, b| [logic(a, b)]).enter(self.scope)
598 }
599
600 fn import_filtered_index_edge<'outer, Tr>(
609 &self,
610 arranged: Arranged<'outer, Tr>,
611 start_signal: StartSignal,
612 mut logic: impl FnMut(BatchKey<'_, Tr>, BatchVal<'_, Tr>, &mut Row) + 'static,
613 ) -> ColCollection<'g, T>
614 where
615 Tr: TraceReader<Time = mz_repr::Timestamp, Batch: Navigable> + Clone,
616 mz_repr::Timestamp: TotalOrder,
617 BatchCursor<Tr>: Cursor<Time = mz_repr::Timestamp, Diff = Diff>,
618 {
619 let as_of = self.as_of_frontier.clone();
620 arranged
621 .stream
622 .with_start_signal(start_signal)
623 .unary::<ColumnBuilder<(Row, mz_repr::Timestamp, Diff)>, _, _, _>(
624 Pipeline,
625 "IndexToColumnar",
626 move |_cap, _info| {
627 let mut row_buf = Row::default();
628 move |input, output| {
629 input.for_each(|time, data| {
630 let mut session = output.session_with_builder(&time);
631 for batch in data.iter() {
632 if <Antichain<mz_repr::Timestamp> as PartialOrder>::less_equal(
633 batch.upper(),
634 &as_of,
635 ) {
636 continue;
637 }
638 let mut cursor = batch.cursor();
639 while let Some(key) = cursor.get_key(batch) {
640 while let Some(val) = cursor.get_val(batch) {
641 logic(key, val, &mut row_buf);
642 cursor.map_times(batch, |t, d| {
643 let t = <BatchCursor<Tr> as Cursor>::owned_time(t);
644 let d = <BatchCursor<Tr> as Cursor>::owned_diff(d);
645 session.give((&*row_buf, &t, &d));
646 });
647 cursor.step_val(batch);
648 }
649 cursor.step_key(batch);
650 }
651 }
652 });
653 }
654 },
655 )
656 .as_collection()
657 .enter(self.scope)
658 }
659
660 pub(crate) fn import_index<'outer>(
661 &mut self,
662 outer: Scope<'outer, mz_repr::Timestamp>,
663 compute_state: &mut ComputeState,
664 tokens: &mut BTreeMap<GlobalId, Rc<dyn std::any::Any>>,
665 input_probe: probe::Handle<mz_repr::Timestamp>,
666 idx_id: GlobalId,
667 idx: &IndexDesc<LirScalarExpr>,
668 typ: &ReprRelationType,
669 snapshot_mode: SnapshotMode,
670 start_signal: StartSignal,
671 ) {
672 if let Some(traces) = compute_state.traces.get_mut(&idx_id) {
673 assert!(
674 PartialOrder::less_equal(&traces.compaction_frontier(), &self.as_of_frontier),
675 "Index {idx_id} has been allowed to compact beyond the dataflow as_of"
676 );
677
678 let token = traces.to_drop().clone();
679
680 let (mut oks, ok_button) = traces.oks_mut().import_frontier_core(
681 outer,
682 &format!("Index({}, {:?})", idx.on_id, idx.key),
683 self.as_of_frontier.clone(),
684 self.until.clone(),
685 );
686
687 oks.stream = oks.stream.probe_with(&input_probe);
688
689 let (err_arranged, err_button) = traces.errs_mut().import_frontier_core(
690 outer,
691 &format!("ErrIndex({}, {:?})", idx.on_id, idx.key),
692 self.as_of_frontier.clone(),
693 self.until.clone(),
694 );
695
696 let bundle = match snapshot_mode {
697 SnapshotMode::Include => {
698 let ok_arranged = oks
699 .enter(self.scope)
700 .with_start_signal(start_signal.clone());
701 let err_arranged = err_arranged
702 .enter(self.scope)
703 .with_start_signal(start_signal);
704 CollectionBundle::from_expressions(
705 idx.key.clone(),
706 ArrangementFlavor::Trace(idx_id, ok_arranged, err_arranged),
707 )
708 }
709 SnapshotMode::Exclude => {
710 let oks = {
717 let mut datums = DatumVec::new();
718 let (permutation, _thinning) =
719 permutation_for_arrangement(&idx.key, typ.arity());
720 self.import_filtered_index_edge(
721 oks,
722 start_signal.clone(),
723 move |k: DatumSeq, v: DatumSeq, row: &mut Row| {
724 let temp_storage = RowArena::new();
725 let mut datums_borrow = datums.borrow();
726 k.extend_datums(&temp_storage, &mut datums_borrow, None);
727 v.extend_datums(&temp_storage, &mut datums_borrow, None);
728 row.packer()
729 .extend(permutation.iter().map(|i| datums_borrow[*i]));
730 },
731 )
732 };
733 let errs = self.import_filtered_index_collection(
734 err_arranged,
735 start_signal,
736 |e, _| e.clone(),
737 );
738 CollectionBundle::from_edge(oks, errs)
739 }
740 };
741 self.update_id(Id::Global(idx.on_id), bundle);
742 tokens.insert(
743 idx_id,
744 Rc::new((PressOnDrop(ok_button), PressOnDrop(err_button), token)),
745 );
746 } else {
747 panic!(
748 "import of index {} failed while building dataflow {}",
749 idx_id, self.dataflow_id
750 );
751 }
752 }
753}
754
755impl<'g> Context<'g, mz_repr::Timestamp> {
758 pub(crate) fn export_index(
759 &self,
760 compute_state: &mut ComputeState,
761 tokens: &BTreeMap<GlobalId, Rc<dyn std::any::Any>>,
762 dependency_ids: BTreeSet<GlobalId>,
763 idx_id: GlobalId,
764 idx: &IndexDesc<LirScalarExpr>,
765 output_probe: &MzProbeHandle<mz_repr::Timestamp>,
766 ) {
767 let mut needed_tokens = Vec::new();
769 for dep_id in dependency_ids {
770 if let Some(token) = tokens.get(&dep_id) {
771 needed_tokens.push(Rc::clone(token));
772 }
773 }
774 let bundle = self.lookup_id(Id::Global(idx_id)).unwrap_or_else(|| {
775 panic!(
776 "Arrangement alarmingly absent! id: {:?}",
777 Id::Global(idx_id)
778 )
779 });
780
781 let key = &idx.key;
782 match bundle.arrangement(key) {
783 Some(ArrangementFlavor::Local(mut oks, mut errs)) => {
784 if let Some(&expiration) = self.dataflow_expiration.as_option() {
798 oks.stream = oks.stream.expire_stream_at(
799 &format!("{}_export_index_oks", self.debug_name),
800 expiration,
801 );
802 errs.stream = errs.stream.expire_stream_at(
803 &format!("{}_export_index_errs", self.debug_name),
804 expiration,
805 );
806 }
807
808 oks.stream = oks.stream.probe_notify_with(vec![output_probe.clone()]);
809
810 if let Some(logger) = compute_state.compute_logger.clone() {
812 errs.stream = errs.stream.log_dataflow_errors(logger, idx_id);
813 }
814
815 compute_state.traces.set(
816 idx_id,
817 TraceBundle::new(oks.trace, errs.trace).with_drop(needed_tokens),
818 );
819 }
820 Some(ArrangementFlavor::Trace(gid, _, _)) => {
821 let trace = compute_state.traces.get(&gid).unwrap().clone();
824 compute_state.traces.set(idx_id, trace);
825 }
826 None => {
827 println!("collection available: {:?}", bundle.collection.is_none());
828 println!(
829 "keys available: {:?}",
830 bundle.arranged.keys().collect::<Vec<_>>()
831 );
832 panic!(
833 "Arrangement alarmingly absent! id: {:?}, keys: {:?}",
834 Id::Global(idx_id),
835 key
836 );
837 }
838 };
839 }
840}
841
842impl<'g, T> Context<'g, T>
845where
846 T: RenderTimestamp,
847{
848 pub(crate) fn export_index_iterative<'outer>(
849 &self,
850 outer: Scope<'outer, mz_repr::Timestamp>,
851 compute_state: &mut ComputeState,
852 tokens: &BTreeMap<GlobalId, Rc<dyn std::any::Any>>,
853 dependency_ids: BTreeSet<GlobalId>,
854 idx_id: GlobalId,
855 idx: &IndexDesc<LirScalarExpr>,
856 output_probe: &MzProbeHandle<mz_repr::Timestamp>,
857 ) {
858 let mut needed_tokens = Vec::new();
860 for dep_id in dependency_ids {
861 if let Some(token) = tokens.get(&dep_id) {
862 needed_tokens.push(Rc::clone(token));
863 }
864 }
865 let bundle = self.lookup_id(Id::Global(idx_id)).unwrap_or_else(|| {
866 panic!(
867 "Arrangement alarmingly absent! id: {:?}",
868 Id::Global(idx_id)
869 )
870 });
871
872 let key = &idx.key;
873 match bundle.arrangement(key) {
874 Some(ArrangementFlavor::Local(oks, errs)) => {
875 let mut oks = oks
879 .as_collection(|k, v| (k.to_row(), v.to_row()))
880 .leave(outer)
881 .mz_arrange::<
882 ColumnationChunker<_>,
883 RowRowBatcher<_, _>,
884 RowRowBuilder<_, _>,
885 _,
886 >(
887 "Arrange export iterative",
888 );
889
890 let mut errs = errs
891 .as_collection(|k, v| (k.clone(), v.clone()))
892 .leave(outer)
893 .mz_arrange::<ColumnationChunker<_>, ErrBatcher<_, _>, ErrBuilder<_, _>, _>(
894 "Arrange export iterative err",
895 );
896
897 if let Some(&expiration) = self.dataflow_expiration.as_option() {
900 oks.stream = oks.stream.expire_stream_at(
901 &format!("{}_export_index_iterative_oks", self.debug_name),
902 expiration,
903 );
904 errs.stream = errs.stream.expire_stream_at(
905 &format!("{}_export_index_iterative_err", self.debug_name),
906 expiration,
907 );
908 }
909
910 oks.stream = oks.stream.probe_notify_with(vec![output_probe.clone()]);
911
912 if let Some(logger) = compute_state.compute_logger.clone() {
914 errs.stream = errs.stream.log_dataflow_errors(logger, idx_id);
915 }
916
917 compute_state.traces.set(
918 idx_id,
919 TraceBundle::new(oks.trace, errs.trace).with_drop(needed_tokens),
920 );
921 }
922 Some(ArrangementFlavor::Trace(gid, _, _)) => {
923 let trace = compute_state.traces.get(&gid).unwrap().clone();
926 compute_state.traces.set(idx_id, trace);
927 }
928 None => {
929 println!("collection available: {:?}", bundle.collection.is_none());
930 println!(
931 "keys available: {:?}",
932 bundle.arranged.keys().collect::<Vec<_>>()
933 );
934 panic!(
935 "Arrangement alarmingly absent! id: {:?}, keys: {:?}",
936 Id::Global(idx_id),
937 key,
938 );
939 }
940 };
941 }
942}
943
944enum BindingInfo {
950 Body { in_let: bool },
951 Let { id: LocalId, last: bool },
952 LetRec { id: LocalId, last: bool },
953}
954
955impl<'scope> Context<'scope, Product<mz_repr::Timestamp, PointStamp<u64>>> {
956 fn render_recursive_plan(
969 &mut self,
970 object_id: GlobalId,
971 level: usize,
972 plan: RenderPlan,
973 binding: BindingInfo,
974 ) -> CollectionBundle<'scope, Product<mz_repr::Timestamp, PointStamp<u64>>> {
975 for BindStage { lets, recs } in plan.binds {
976 let mut let_iter = lets.into_iter().peekable();
978 while let Some(LetBind { id, value }) = let_iter.next() {
979 let bundle =
980 self.scope
981 .clone()
982 .region_named(&format!("Binding({:?})", id), |region| {
983 let depends = value.depends();
984 let last = let_iter.peek().is_none();
985 let binding = BindingInfo::Let { id, last };
986 self.enter_region(region, Some(&depends))
987 .render_letfree_plan(object_id, value, binding)
988 .leave_region(self.scope)
989 });
990 let bundle = self.distinct_binding_errs(bundle);
991 self.insert_id(Id::Local(id), bundle);
992 }
993
994 let rec_ids: Vec<_> = recs.iter().map(|r| r.id).collect();
995
996 let mut variable_read = BTreeSet::new();
1003 let mut read_so_far = BTreeSet::new();
1004 for rec in recs.iter() {
1005 read_so_far.extend(rec.value.depends());
1006 if read_so_far.contains(&Id::Local(rec.id)) {
1007 variable_read.insert(rec.id);
1008 }
1009 }
1010
1011 let mut variables = BTreeMap::new();
1015 for id in rec_ids.iter() {
1016 use differential_dataflow::dynamic::feedback_summary;
1017 let inner = feedback_summary::<u64>(level + 1, 1);
1018 let (oks_v, oks_collection) =
1019 Variable::new(self.scope, Product::new(Default::default(), inner.clone()));
1020 let (err_v, err_collection) =
1021 Variable::new(self.scope, Product::new(Default::default(), inner));
1022
1023 if variable_read.contains(id) {
1024 self.insert_id(
1025 Id::Local(*id),
1026 CollectionBundle::from_edge(oks_collection, err_collection),
1027 );
1028 }
1029 variables.insert(Id::Local(*id), (oks_v, err_v));
1030 }
1031 let mut bound_oks = BTreeMap::new();
1034 let mut rec_iter = recs.into_iter().peekable();
1035 while let Some(RecBind { id, value, limit }) = rec_iter.next() {
1036 let last = rec_iter.peek().is_none();
1037 let binding = BindingInfo::LetRec { id, last };
1038 let bundle = self.render_recursive_plan(object_id, level + 1, value, binding);
1039 let (oks, mut err) = bundle.collection.clone().unwrap();
1042 bound_oks.insert(id, oks.clone());
1043 let bundle = self.distinct_binding_errs(bundle);
1048 self.insert_id(Id::Local(id), bundle);
1049 let (oks_v, err_v) = variables.remove(&Id::Local(id)).unwrap();
1050
1051 let mut oks = columnar_consolidate(oks, "LetRecConsolidation");
1053
1054 if let Some(limit) = limit {
1055 let mut time = RecTimestamp::default();
1066 let (over_limit, in_limit) = oks
1067 .inner
1068 .partition_by::<ColumnBuilder<(Row, RecTimestamp, Diff)>, _>(
1069 "LetRecLimit",
1070 move |(_data, reference, _diff)| {
1071 time.copy_from(*reference);
1072 let iteration_index = time.inner.get(level).copied().unwrap_or(0);
1075 iteration_index + 1 >= limit.max_iters.into()
1077 },
1078 );
1079 oks = Collection::new(in_limit);
1080 if !limit.return_at_limit {
1081 let (_, over_limit) = flat_map_datums::<
1085 _,
1086 CapacityContainerBuilder<Vec<(Row, RecTimestamp, Diff)>>,
1087 _,
1088 >(
1089 Collection::new(over_limit),
1090 "LetRecLimitExceeded",
1091 0,
1092 move |_datums, time, diff, _ok_session, err_session| {
1093 err_session.give((
1094 DataflowErrorSer::from(EvalError::LetRecLimitExceeded(
1095 format!("{}", limit.max_iters.get()).into(),
1096 )),
1097 time,
1098 diff,
1099 ));
1100 1
1101 },
1102 );
1103 err = err.concat(over_limit.as_collection());
1104 }
1105 }
1106
1107 let err: KeyCollection<_, _, _> = err.into();
1113 let errs = err
1114 .mz_arrange::<
1115 ColumnationChunker<_>,
1116 ErrBatcher<_, _>,
1117 ErrBuilder<_, _>,
1118 ErrSpine<_, _>,
1119 >("Arrange recursive err")
1120 .mz_reduce_abelian::<_, ErrBuilder<_, _>, ErrSpine<_, _>, _>(
1121 "Distinct recursive err",
1122 move |_k, _s, t| t.push(((), Diff::ONE)),
1123 )
1124 .as_collection(|k, _| k.clone());
1125
1126 oks_v.set(oks);
1127 err_v.set(errs);
1128 }
1129 for id in rec_ids.into_iter() {
1131 let bundle = self.remove_id(Id::Local(id)).unwrap();
1132 let (_, err) = bundle.collection.unwrap();
1133 let oks = bound_oks
1134 .remove(&id)
1135 .expect("rec binding bound while rendering above");
1136 self.insert_id(
1137 Id::Local(id),
1138 CollectionBundle::from_edge(
1139 columnar_leave_dynamic(oks, level + 1),
1140 err.leave_dynamic(level + 1),
1141 ),
1142 );
1143 }
1144 }
1145
1146 self.render_letfree_plan(object_id, plan.body, binding)
1147 }
1148}
1149
1150impl<'scope, T: RenderTimestamp + MaybeBucketByTime> Context<'scope, T> {
1151 fn render_plan(
1162 &mut self,
1163 object_id: GlobalId,
1164 plan: RenderPlan,
1165 ) -> CollectionBundle<'scope, T> {
1166 let mut in_let = false;
1167 for BindStage { lets, recs } in plan.binds {
1168 assert!(recs.is_empty());
1169
1170 let mut let_iter = lets.into_iter().peekable();
1171 while let Some(LetBind { id, value }) = let_iter.next() {
1172 in_let = true;
1174 let bundle =
1175 self.scope
1176 .clone()
1177 .region_named(&format!("Binding({:?})", id), |region| {
1178 let depends = value.depends();
1179 let last = let_iter.peek().is_none();
1180 let binding = BindingInfo::Let { id, last };
1181 self.enter_region(region, Some(&depends))
1182 .render_letfree_plan(object_id, value, binding)
1183 .leave_region(self.scope)
1184 });
1185 let bundle = self.distinct_binding_errs(bundle);
1186 self.insert_id(Id::Local(id), bundle);
1187 }
1188 }
1189
1190 self.scope.clone().region_named("Main Body", |region| {
1191 let depends = plan.body.depends();
1192 self.enter_region(region, Some(&depends))
1193 .render_letfree_plan(object_id, plan.body, BindingInfo::Body { in_let })
1194 .leave_region(self.scope)
1195 })
1196 }
1197
1198 fn distinct_binding_errs(
1207 &self,
1208 bundle: CollectionBundle<'scope, T>,
1209 ) -> CollectionBundle<'scope, T> {
1210 if ENABLE_ERROR_DISTINCT.get(&self.config_set) {
1211 bundle.distinct_errs()
1212 } else {
1213 bundle
1214 }
1215 }
1216
1217 fn render_letfree_plan(
1219 &self,
1220 object_id: GlobalId,
1221 plan: LetFreePlan,
1222 binding: BindingInfo,
1223 ) -> CollectionBundle<'scope, T> {
1224 let (mut nodes, root_id, topological_order) = plan.destruct();
1225
1226 let mut collections = BTreeMap::new();
1228
1229 let should_compute_lir_metadata = self.compute_logger.is_some();
1235 let mut lir_mapping_metadata = if should_compute_lir_metadata {
1236 Some(Vec::with_capacity(nodes.len()))
1237 } else {
1238 None
1239 };
1240
1241 let mut topo_iter = topological_order.into_iter().peekable();
1242 while let Some(lir_id) = topo_iter.next() {
1243 let node = nodes.remove(&lir_id).unwrap();
1244
1245 let metadata = if should_compute_lir_metadata {
1249 let operator = node.expr.humanize(&DummyHumanizer);
1250
1251 let operator = if topo_iter.peek().is_none() {
1253 match &binding {
1254 BindingInfo::Body { in_let: true } => format!("Returning {operator}"),
1255 BindingInfo::Body { in_let: false } => operator,
1256 BindingInfo::Let { id, last: true } => {
1257 format!("With {id} = {operator}")
1258 }
1259 BindingInfo::Let { id, last: false } => {
1260 format!("{id} = {operator}")
1261 }
1262 BindingInfo::LetRec { id, last: true } => {
1263 format!("With Recursive {id} = {operator}")
1264 }
1265 BindingInfo::LetRec { id, last: false } => {
1266 format!("{id} = {operator}")
1267 }
1268 }
1269 } else {
1270 operator
1271 };
1272
1273 let operator_id_start = self.scope.worker().peek_identifier();
1279 Some((operator, operator_id_start))
1280 } else {
1281 None
1282 };
1283
1284 let mut bundle = self.render_plan_expr(node.expr, &collections);
1285
1286 if let Some((operator, operator_id_start)) = metadata {
1287 let operator_id_end = self.scope.worker().peek_identifier();
1288 let operator_span = (operator_id_start, operator_id_end);
1289
1290 if let Some(lir_mapping_metadata) = &mut lir_mapping_metadata {
1291 lir_mapping_metadata.push((
1292 lir_id,
1293 LirMetadata::new(operator, node.parent, node.nesting, operator_span),
1294 ))
1295 }
1296 }
1297
1298 self.log_operator_hydration(&mut bundle, lir_id);
1299
1300 collections.insert(lir_id, bundle);
1301 }
1302
1303 if let Some(lir_mapping_metadata) = lir_mapping_metadata {
1304 self.log_lir_mapping(object_id, lir_mapping_metadata);
1305 }
1306
1307 collections
1308 .remove(&root_id)
1309 .expect("LetFreePlan invariant (1)")
1310 }
1311
1312 fn render_plan_expr(
1319 &self,
1320 expr: render_plan::Expr,
1321 collections: &BTreeMap<LirId, CollectionBundle<'scope, T>>,
1322 ) -> CollectionBundle<'scope, T> {
1323 use render_plan::Expr::*;
1324
1325 let expect_input = |id| {
1326 collections
1327 .get(&id)
1328 .cloned()
1329 .unwrap_or_else(|| panic!("missing input collection: {id}"))
1330 };
1331
1332 match expr {
1333 Constant { rows } => {
1334 let (rows, errs) = match rows {
1336 Ok(rows) => (rows, Vec::new()),
1337 Err(e) => (Vec::new(), vec![e]),
1338 };
1339
1340 let as_of_frontier = self.as_of_frontier.clone();
1342 let until = self.until.clone();
1343 let ok_collection = rows
1347 .into_iter()
1348 .filter_map(move |(row, mut time, diff)| {
1349 time.advance_by(as_of_frontier.borrow());
1350 if !until.less_equal(&time) {
1351 Some((
1352 row.0,
1353 <T as Refines<mz_repr::Timestamp>>::to_inner(time),
1354 diff,
1355 ))
1356 } else {
1357 None
1358 }
1359 })
1360 .to_stream_with_builder::<_, ConsolidatingColumnBuilder<Row, T, Diff>>(
1361 self.scope,
1362 )
1363 .as_collection();
1364
1365 let mut error_time: mz_repr::Timestamp = Timestamp::minimum();
1366 error_time.advance_by(self.as_of_frontier.borrow());
1367 let err_collection = errs
1368 .into_iter()
1369 .map(move |e| {
1370 (
1371 DataflowErrorSer::from(e),
1372 <T as Refines<mz_repr::Timestamp>>::to_inner(error_time),
1373 Diff::ONE,
1374 )
1375 })
1376 .to_stream(self.scope)
1377 .as_collection();
1378
1379 CollectionBundle::from_edge(ok_collection, err_collection)
1380 }
1381 Get { id, keys, plan } => {
1382 let mut collection = self
1385 .lookup_id(id)
1386 .unwrap_or_else(|| panic!("Get({:?}) not found at render time", id));
1387 match plan {
1388 mz_compute_types::plan::GetPlan::PassArrangements => {
1389 assert!(
1391 keys.arranged
1392 .iter()
1393 .all(|(key, _, _)| collection.arranged.contains_key(key))
1394 );
1395 assert!(keys.raw <= collection.collection.is_some());
1396 collection.arranged.retain(|key, _value| {
1398 keys.arranged.iter().any(|(key2, _, _)| key2 == key)
1399 });
1400 collection
1401 }
1402 mz_compute_types::plan::GetPlan::Arrangement(key, row, mfp) => {
1403 let (oks, errs) = collection.as_collection_core(
1404 mfp,
1405 Some((key, row)),
1406 self.until.clone(),
1407 );
1408 CollectionBundle::from_edge(oks, errs)
1409 }
1410 mz_compute_types::plan::GetPlan::Collection(mfp) => {
1411 let (oks, errs) =
1412 collection.as_collection_core(mfp, None, self.until.clone());
1413 CollectionBundle::from_edge(oks, errs)
1414 }
1415 }
1416 }
1417 Mfp {
1418 input,
1419 mfp,
1420 input_key_val,
1421 } => {
1422 let input = expect_input(input);
1423 if mfp.is_identity() {
1425 input
1426 } else {
1427 let (oks, errs) =
1428 input.as_collection_core(mfp, input_key_val, self.until.clone());
1429 CollectionBundle::from_edge(oks, errs)
1430 }
1431 }
1432 FlatMap {
1433 input_key,
1434 input,
1435 exprs,
1436 func,
1437 mfp_after: mfp,
1438 } => {
1439 let input = expect_input(input);
1440 self.render_flat_map(input_key, input, exprs, func, mfp)
1441 }
1442 Join { inputs, plan } => {
1443 let inputs = inputs.into_iter().map(expect_input).collect();
1444 match plan {
1445 mz_compute_types::plan::join::JoinPlan::Linear(linear_plan) => {
1446 self.render_join(inputs, linear_plan)
1447 }
1448 mz_compute_types::plan::join::JoinPlan::Delta(delta_plan) => {
1449 self.render_delta_join(inputs, delta_plan)
1450 }
1451 }
1452 }
1453 Reduce {
1454 input_key,
1455 input,
1456 key_val_plan,
1457 plan,
1458 mfp_after,
1459 temporal_bucketing_strategy,
1460 } => {
1461 let input = expect_input(input);
1462 let mfp_option = (!mfp_after.is_identity()).then_some(mfp_after);
1463 self.render_reduce(
1464 input_key,
1465 input,
1466 key_val_plan,
1467 plan,
1468 mfp_option,
1469 temporal_bucketing_strategy,
1470 )
1471 }
1472 TopK {
1473 input,
1474 top_k_plan,
1475 temporal_bucketing_strategy,
1476 } => {
1477 let input = expect_input(input);
1478 self.render_topk(input, top_k_plan, temporal_bucketing_strategy)
1479 }
1480 Negate { input } => {
1481 let input = expect_input(input);
1482 let (oks, errs) = input
1483 .collection
1484 .clone()
1485 .expect("Negate input must be an unarranged collection");
1486 CollectionBundle::from_edge(columnar_negate(oks), errs)
1487 }
1488 Threshold {
1489 input,
1490 threshold_plan,
1491 } => {
1492 let input = expect_input(input);
1493 self.render_threshold(input, threshold_plan)
1494 }
1495 Union {
1496 inputs,
1497 consolidate_output,
1498 temporal_bucketing_strategies,
1499 } => {
1500 let mut oks = Vec::new();
1501 let mut errs = Vec::new();
1502 for (input, strategy) in inputs.into_iter().zip_eq(temporal_bucketing_strategies) {
1503 let (os, es) = expect_input(input)
1504 .collection
1505 .clone()
1506 .expect("Union input must be an unarranged collection");
1507 let os = if matches!(strategy, ArrangementStrategy::TemporalBucketing) {
1511 let summary: mz_repr::Timestamp = TEMPORAL_BUCKETING_SUMMARY
1512 .get(&self.config_set)
1513 .try_into()
1514 .expect("must fit");
1515 T::maybe_apply_temporal_bucketing(
1516 os.inner,
1517 self.as_of_frontier.clone(),
1518 summary,
1519 )
1520 } else {
1521 os
1522 };
1523 oks.push(os);
1524 errs.push(es);
1525 }
1526 let oks = concat_many(self.scope, oks);
1527 let oks = if consolidate_output {
1528 columnar_consolidate(oks, "UnionConsolidation")
1529 } else {
1530 oks
1531 };
1532 let errs = differential_dataflow::collection::concatenate(self.scope, errs);
1533 CollectionBundle::from_edge(oks, errs)
1534 }
1535 ArrangeBy {
1536 input_key,
1537 input,
1538 input_mfp,
1539 forms: keys,
1540 strategy,
1541 } => {
1542 let input = expect_input(input);
1543 input.ensure_collections(
1544 keys,
1545 input_key,
1546 input_mfp,
1547 self.as_of_frontier.clone(),
1548 self.until.clone(),
1549 &self.config_set,
1550 strategy,
1551 )
1552 }
1553 }
1554 }
1555
1556 fn log_dataflow_global_id(&self, dataflow_index: usize, global_id: GlobalId) {
1557 if let Some(logger) = &self.compute_logger {
1558 logger.log(&ComputeEvent::DataflowGlobal(DataflowGlobal {
1559 dataflow_index,
1560 global_id,
1561 }));
1562 }
1563 }
1564
1565 fn log_lir_mapping(&self, global_id: GlobalId, mapping: Vec<(LirId, LirMetadata)>) {
1566 if let Some(logger) = &self.compute_logger {
1567 logger.log(&ComputeEvent::LirMapping(LirMapping { global_id, mapping }));
1568 }
1569 }
1570
1571 fn log_operator_hydration(&self, bundle: &mut CollectionBundle<'scope, T>, lir_id: LirId) {
1572 match bundle.arranged.values_mut().next() {
1592 Some(arrangement) => {
1593 use ArrangementFlavor::*;
1594
1595 match arrangement {
1596 Local(a, _) => {
1597 a.stream = self.log_operator_hydration_inner(a.stream.clone(), lir_id);
1598 }
1599 Trace(_, a, _) => {
1600 a.stream = self.log_operator_hydration_inner(a.stream.clone(), lir_id);
1601 }
1602 }
1603 }
1604 None => {
1605 let (oks, _) = bundle
1606 .collection
1607 .as_mut()
1608 .expect("CollectionBundle invariant");
1609 let stream = self.log_operator_hydration_inner(oks.inner.clone(), lir_id);
1610 *oks = stream.as_collection();
1611 }
1612 }
1613 }
1614
1615 fn log_operator_hydration_inner<D>(
1616 &self,
1617 stream: Stream<'scope, T, D>,
1618 lir_id: LirId,
1619 ) -> Stream<'scope, T, D>
1620 where
1621 D: timely::Container + Clone + 'static,
1622 {
1623 let Some(logger) = self.compute_logger.clone() else {
1624 return stream.clone(); };
1626
1627 let export_ids = self.export_ids.clone();
1628
1629 let mut hydration_frontier = Antichain::new();
1637 for time in self.as_of_frontier.iter() {
1638 if let Some(time) = time.try_step_forward() {
1639 hydration_frontier.insert(Refines::to_inner(time));
1640 }
1641 }
1642
1643 let name = format!("LogOperatorHydration ({lir_id})");
1644 stream.unary_frontier(Pipeline, &name, |_cap, _info| {
1645 let mut hydrated = false;
1646
1647 for &export_id in &export_ids {
1648 logger.log(&ComputeEvent::OperatorHydration(OperatorHydration {
1649 export_id,
1650 lir_id,
1651 hydrated,
1652 }));
1653 }
1654
1655 move |(input, frontier), output| {
1656 input.for_each(|cap, data| {
1658 output.session(&cap).give_container(data);
1659 });
1660
1661 if hydrated {
1662 return;
1663 }
1664
1665 if PartialOrder::less_equal(&hydration_frontier.borrow(), &frontier.frontier()) {
1666 hydrated = true;
1667
1668 for &export_id in &export_ids {
1669 logger.log(&ComputeEvent::OperatorHydration(OperatorHydration {
1670 export_id,
1671 lir_id,
1672 hydrated,
1673 }));
1674 }
1675 }
1676 }
1677 })
1678 }
1679}
1680
1681#[allow(dead_code)] pub trait RenderTimestamp: MzTimestamp + Default + Refines<mz_repr::Timestamp> {
1684 fn system_time(&mut self) -> &mut mz_repr::Timestamp;
1689 fn system_delay(delay: mz_repr::Timestamp) -> <Self as Timestamp>::Summary;
1691 fn event_time(&self) -> mz_repr::Timestamp;
1693 fn event_time_mut(&mut self) -> &mut mz_repr::Timestamp;
1695 fn event_delay(delay: mz_repr::Timestamp) -> <Self as Timestamp>::Summary;
1697 fn step_back(&self) -> Self;
1700}
1701
1702pub trait MaybeBucketByTime: Timestamp + ColumnarData {
1709 fn maybe_apply_temporal_bucketing<'scope, D>(
1711 stream: Stream<'scope, Self, Column<(D, Self, Diff)>>,
1712 as_of: Antichain<mz_repr::Timestamp>,
1713 summary: mz_repr::Timestamp,
1714 ) -> Collection<'scope, Self, Column<(D, Self, Diff)>>
1715 where
1716 D: differential_dataflow::ExchangeData
1717 + crate::typedefs::MzData
1718 + differential_dataflow::Hashable
1719 + ColumnarData,
1720 for<'a> ::columnar::Ref<'a, D>: Copy + Ord + std::hash::Hash,
1721 for<'a> ::columnar::Ref<'a, Self>: Copy + Ord,
1722 for<'a> ::columnar::Ref<'a, Diff>: Ord,
1723 for<'a> <(D, Self, Diff) as ColumnarData>::Container:
1724 ColumnarPush<&'a (D, Self, Diff)> + ColumnarPush<::columnar::Ref<'a, (D, Self, Diff)>>;
1725
1726 fn maybe_apply_temporal_bucketing_vec<'scope, D>(
1732 stream: StreamVec<'scope, Self, (D, Self, Diff)>,
1733 as_of: Antichain<mz_repr::Timestamp>,
1734 summary: mz_repr::Timestamp,
1735 ) -> VecCollection<'scope, Self, D, Diff>
1736 where
1737 D: differential_dataflow::ExchangeData
1738 + crate::typedefs::MzData
1739 + differential_dataflow::Hashable
1740 + ColumnarData,
1741 for<'a> ::columnar::Ref<'a, D>: Copy + Ord + std::hash::Hash,
1742 for<'a> ::columnar::Ref<'a, Self>: Copy + Ord,
1743 for<'a> ::columnar::Ref<'a, Diff>: Ord,
1744 for<'a> <(D, Self, Diff) as ColumnarData>::Container:
1745 ColumnarPush<&'a (D, Self, Diff)> + ColumnarPush<::columnar::Ref<'a, (D, Self, Diff)>>;
1746}
1747
1748impl RenderTimestamp for mz_repr::Timestamp {
1749 fn system_time(&mut self) -> &mut mz_repr::Timestamp {
1750 self
1751 }
1752 fn system_delay(delay: mz_repr::Timestamp) -> <Self as Timestamp>::Summary {
1753 delay
1754 }
1755 fn event_time(&self) -> mz_repr::Timestamp {
1756 *self
1757 }
1758 fn event_time_mut(&mut self) -> &mut mz_repr::Timestamp {
1759 self
1760 }
1761 fn event_delay(delay: mz_repr::Timestamp) -> <Self as Timestamp>::Summary {
1762 delay
1763 }
1764 fn step_back(&self) -> Self {
1765 self.saturating_sub(1)
1766 }
1767}
1768
1769impl MaybeBucketByTime for mz_repr::Timestamp {
1770 fn maybe_apply_temporal_bucketing<'scope, D>(
1771 stream: Stream<'scope, Self, Column<(D, Self, Diff)>>,
1772 as_of: Antichain<mz_repr::Timestamp>,
1773 summary: mz_repr::Timestamp,
1774 ) -> Collection<'scope, Self, Column<(D, Self, Diff)>>
1775 where
1776 D: differential_dataflow::ExchangeData
1777 + crate::typedefs::MzData
1778 + differential_dataflow::Hashable
1779 + ColumnarData,
1780 for<'a> ::columnar::Ref<'a, D>: Copy + Ord + std::hash::Hash,
1781 for<'a> ::columnar::Ref<'a, Self>: Copy + Ord,
1782 for<'a> ::columnar::Ref<'a, Diff>: Ord,
1783 for<'a> <(D, Self, Diff) as ColumnarData>::Container:
1784 ColumnarPush<&'a (D, Self, Diff)> + ColumnarPush<::columnar::Ref<'a, (D, Self, Diff)>>,
1785 {
1786 stream.bucket(as_of, summary).as_collection()
1787 }
1788
1789 fn maybe_apply_temporal_bucketing_vec<'scope, D>(
1790 stream: StreamVec<'scope, Self, (D, Self, Diff)>,
1791 as_of: Antichain<mz_repr::Timestamp>,
1792 summary: mz_repr::Timestamp,
1793 ) -> VecCollection<'scope, Self, D, Diff>
1794 where
1795 D: differential_dataflow::ExchangeData
1796 + crate::typedefs::MzData
1797 + differential_dataflow::Hashable
1798 + ColumnarData,
1799 for<'a> ::columnar::Ref<'a, D>: Copy + Ord + std::hash::Hash,
1800 for<'a> ::columnar::Ref<'a, Self>: Copy + Ord,
1801 for<'a> ::columnar::Ref<'a, Diff>: Ord,
1802 for<'a> <(D, Self, Diff) as ColumnarData>::Container:
1803 ColumnarPush<&'a (D, Self, Diff)> + ColumnarPush<::columnar::Ref<'a, (D, Self, Diff)>>,
1804 {
1805 stream.bucket(as_of, summary).as_collection()
1806 }
1807}
1808
1809impl RenderTimestamp for Product<mz_repr::Timestamp, PointStamp<u64>> {
1810 fn system_time(&mut self) -> &mut mz_repr::Timestamp {
1811 &mut self.outer
1812 }
1813 fn system_delay(delay: mz_repr::Timestamp) -> <Self as Timestamp>::Summary {
1814 Product::new(delay, Default::default())
1815 }
1816 fn event_time(&self) -> mz_repr::Timestamp {
1817 self.outer
1818 }
1819 fn event_time_mut(&mut self) -> &mut mz_repr::Timestamp {
1820 &mut self.outer
1821 }
1822 fn event_delay(delay: mz_repr::Timestamp) -> <Self as Timestamp>::Summary {
1823 Product::new(delay, Default::default())
1824 }
1825 fn step_back(&self) -> Self {
1826 let inner = self.inner.clone();
1830 let mut vec = inner.into_inner();
1831 for item in vec.iter_mut() {
1832 *item = item.saturating_sub(1);
1833 }
1834 Product::new(self.outer.saturating_sub(1), PointStamp::new(vec))
1835 }
1836}
1837
1838impl MaybeBucketByTime for Product<mz_repr::Timestamp, PointStamp<u64>> {
1839 fn maybe_apply_temporal_bucketing<'scope, D>(
1840 stream: Stream<'scope, Self, Column<(D, Self, Diff)>>,
1841 _as_of: Antichain<mz_repr::Timestamp>,
1842 _summary: mz_repr::Timestamp,
1843 ) -> Collection<'scope, Self, Column<(D, Self, Diff)>>
1844 where
1845 D: differential_dataflow::ExchangeData
1846 + crate::typedefs::MzData
1847 + differential_dataflow::Hashable
1848 + ColumnarData,
1849 for<'a> ::columnar::Ref<'a, D>: Copy + Ord + std::hash::Hash,
1850 for<'a> ::columnar::Ref<'a, Self>: Copy + Ord,
1851 for<'a> ::columnar::Ref<'a, Diff>: Ord,
1852 for<'a> <(D, Self, Diff) as ColumnarData>::Container:
1853 ColumnarPush<&'a (D, Self, Diff)> + ColumnarPush<::columnar::Ref<'a, (D, Self, Diff)>>,
1854 {
1855 stream.as_collection()
1857 }
1858
1859 fn maybe_apply_temporal_bucketing_vec<'scope, D>(
1860 stream: StreamVec<'scope, Self, (D, Self, Diff)>,
1861 _as_of: Antichain<mz_repr::Timestamp>,
1862 _summary: mz_repr::Timestamp,
1863 ) -> VecCollection<'scope, Self, D, Diff>
1864 where
1865 D: differential_dataflow::ExchangeData
1866 + crate::typedefs::MzData
1867 + differential_dataflow::Hashable
1868 + ColumnarData,
1869 for<'a> ::columnar::Ref<'a, D>: Copy + Ord + std::hash::Hash,
1870 for<'a> ::columnar::Ref<'a, Self>: Copy + Ord,
1871 for<'a> ::columnar::Ref<'a, Diff>: Ord,
1872 for<'a> <(D, Self, Diff) as ColumnarData>::Container:
1873 ColumnarPush<&'a (D, Self, Diff)> + ColumnarPush<::columnar::Ref<'a, (D, Self, Diff)>>,
1874 {
1875 stream.as_collection()
1877 }
1878}
1879
1880#[derive(Clone)]
1890pub(crate) struct StartSignal {
1891 fut: futures::future::Shared<oneshot::Receiver<Infallible>>,
1896 token_ref: Weak<RefCell<Box<dyn Any>>>,
1898}
1899
1900impl StartSignal {
1901 pub fn new() -> (Self, Rc<dyn Any>) {
1904 let (tx, rx) = oneshot::channel::<Infallible>();
1905 let token: Rc<RefCell<Box<dyn Any>>> = Rc::new(RefCell::new(Box::new(tx)));
1906 let signal = Self {
1907 fut: rx.shared(),
1908 token_ref: Rc::downgrade(&token),
1909 };
1910 (signal, token)
1911 }
1912
1913 pub fn has_fired(&self) -> bool {
1914 self.token_ref.strong_count() == 0
1915 }
1916
1917 pub fn into_send_future(self) -> impl Future<Output = ()> + Send {
1922 use futures::FutureExt;
1923 self.fut.map(|_| ())
1924 }
1925
1926 pub fn drop_on_fire(&self, to_drop: Box<dyn Any>) {
1927 if let Some(token) = self.token_ref.upgrade() {
1928 let mut token = token.borrow_mut();
1929 let inner = std::mem::replace(&mut *token, Box::new(()));
1930 *token = Box::new((inner, to_drop));
1931 }
1932 }
1933}
1934
1935impl Future for StartSignal {
1936 type Output = ();
1937
1938 fn poll(mut self: Pin<&mut Self>, cx: &mut std::task::Context<'_>) -> Poll<Self::Output> {
1939 self.fut.poll_unpin(cx).map(|_| ())
1940 }
1941}
1942
1943pub(crate) trait WithStartSignal {
1945 fn with_start_signal(self, signal: StartSignal) -> Self;
1950}
1951
1952impl<'scope, Tr> WithStartSignal for Arranged<'scope, Tr>
1953where
1954 Tr: TraceReader<Time: RenderTimestamp> + Clone,
1955{
1956 fn with_start_signal(self, signal: StartSignal) -> Self {
1957 Arranged {
1958 stream: self.stream.with_start_signal(signal),
1959 trace: self.trace,
1960 }
1961 }
1962}
1963
1964impl<'scope, T: Timestamp, D> WithStartSignal for Stream<'scope, T, D>
1965where
1966 D: timely::Container + Clone + 'static,
1967{
1968 fn with_start_signal(self, signal: StartSignal) -> Self {
1969 let activations = self.scope().activations();
1970 self.unary(Pipeline, "StartSignal", |_cap, info| {
1971 let token = Box::new(ActivateOnDrop::new((), info.address, activations));
1972 signal.drop_on_fire(token);
1973
1974 let mut stash = Vec::new();
1975
1976 move |input, output| {
1977 if !signal.has_fired() {
1979 input.for_each(|cap, data| stash.push((cap, std::mem::take(data))));
1980 return;
1981 }
1982
1983 for (cap, mut data) in std::mem::take(&mut stash) {
1985 output.session(&cap).give_container(&mut data);
1986 }
1987
1988 input.for_each(|cap, data| {
1990 output.session(&cap).give_container(data);
1991 });
1992 }
1993 })
1994 }
1995}
1996
1997fn suppress_early_progress<'scope, T: Timestamp, D>(
2019 stream: Stream<'scope, T, D>,
2020 as_of: Antichain<T>,
2021) -> Stream<'scope, T, D>
2022where
2023 D: timely::Container + Clone,
2024{
2025 stream.unary_frontier(Pipeline, "SuppressEarlyProgress", |default_cap, _info| {
2026 let mut early_cap = Some(default_cap);
2027
2028 move |(input, frontier), output| {
2029 input.for_each_time(|data_cap, data| {
2030 if as_of.less_than(data_cap.time()) {
2031 let mut session = output.session(&data_cap);
2032 for data in data {
2033 session.give_container(data);
2034 }
2035 } else {
2036 let cap = early_cap.as_ref().expect("early_cap can't be dropped yet");
2037 let mut session = output.session(&cap);
2038 for data in data {
2039 session.give_container(data);
2040 }
2041 }
2042 });
2043
2044 if !PartialOrder::less_equal(&frontier.frontier(), &as_of.borrow()) {
2045 early_cap.take();
2046 }
2047 }
2048 })
2049}
2050
2051trait LimitProgress<T: Timestamp> {
2053 fn limit_progress(
2081 self,
2082 handle: MzProbeHandle<T>,
2083 slack_ms: u64,
2084 limit: Option<usize>,
2085 upper: Antichain<T>,
2086 name: String,
2087 ) -> Self;
2088}
2089
2090trait RecordTimes {
2092 fn for_each_time(&self, f: impl FnMut(mz_repr::Timestamp));
2094}
2095
2096impl<D, R> RecordTimes for Vec<(D, mz_repr::Timestamp, R)> {
2097 fn for_each_time(&self, mut f: impl FnMut(mz_repr::Timestamp)) {
2098 for (_, time, _) in self {
2099 f(*time);
2100 }
2101 }
2102}
2103
2104impl<D, R> RecordTimes for Column<(D, mz_repr::Timestamp, R)>
2105where
2106 D: ColumnarData,
2107 R: ColumnarData,
2108 (D, mz_repr::Timestamp, R): ColumnarData<
2109 Container = (
2110 D::Container,
2111 <mz_repr::Timestamp as ColumnarData>::Container,
2112 R::Container,
2113 ),
2114 >,
2115{
2116 fn for_each_time(&self, mut f: impl FnMut(mz_repr::Timestamp)) {
2117 for time in self.borrow().1.into_index_iter() {
2118 f(time);
2119 }
2120 }
2121}
2122
2123impl<'scope, C> LimitProgress<mz_repr::Timestamp> for Stream<'scope, mz_repr::Timestamp, C>
2126where
2127 C: timely::Container + Clone + RecordTimes,
2128{
2129 fn limit_progress(
2130 self,
2131 handle: MzProbeHandle<mz_repr::Timestamp>,
2132 slack_ms: u64,
2133 limit: Option<usize>,
2134 upper: Antichain<mz_repr::Timestamp>,
2135 name: String,
2136 ) -> Self {
2137 let scope = self.scope();
2138 let stream =
2139 self.unary_frontier(Pipeline, &format!("LimitProgress({name})"), |_cap, info| {
2140 let mut pending_times: BTreeSet<mz_repr::Timestamp> = BTreeSet::new();
2142 let mut retained_cap: Option<Capability<mz_repr::Timestamp>> = None;
2144
2145 let activator = scope.activator_for(info.address);
2146 handle.activate(activator.clone());
2147
2148 move |(input, frontier), output| {
2149 input.for_each(|cap, data| {
2150 data.for_each_time(|time| {
2151 let Some(time) = u64::from(time).checked_add(slack_ms) else {
2152 return;
2153 };
2154 let rounded_time = if slack_ms == 0 {
2158 time
2159 } else {
2160 (time / slack_ms).saturating_add(1).saturating_mul(slack_ms)
2161 };
2162 if !upper.less_than(&rounded_time.into()) {
2163 pending_times.insert(rounded_time.into());
2164 }
2165 });
2166 output.session(&cap).give_container(data);
2167 if retained_cap.as_ref().is_none_or(|c| {
2168 !c.time().less_than(cap.time()) && !upper.less_than(cap.time())
2169 }) {
2170 retained_cap = Some(cap.retain(0));
2171 }
2172 });
2173
2174 handle.with_frontier(|f| {
2175 while pending_times
2176 .first()
2177 .map_or(false, |retained_time| !f.less_than(&retained_time))
2178 {
2179 let _ = pending_times.pop_first();
2180 }
2181 });
2182
2183 while limit.map_or(false, |limit| pending_times.len() > limit) {
2184 let _ = pending_times.pop_first();
2185 }
2186
2187 match (retained_cap.as_mut(), pending_times.first()) {
2188 (Some(cap), Some(first)) => cap.downgrade(first),
2189 (_, None) => retained_cap = None,
2190 _ => {}
2191 }
2192
2193 if frontier.is_empty() {
2194 retained_cap = None;
2195 pending_times.clear();
2196 }
2197
2198 if !pending_times.is_empty() {
2199 tracing::debug!(
2200 name,
2201 info.global_id,
2202 pending_times = %PendingTimesDisplay(pending_times.iter().cloned()),
2203 frontier = ?frontier.frontier().get(0),
2204 probe = ?handle.with_frontier(|f| f.get(0).cloned()),
2205 ?upper,
2206 "pending times",
2207 );
2208 }
2209 }
2210 });
2211 stream
2212 }
2213}
2214
2215struct PendingTimesDisplay<T>(T);
2218
2219impl<T> std::fmt::Display for PendingTimesDisplay<T>
2220where
2221 T: IntoIterator<Item = mz_repr::Timestamp> + Clone,
2222{
2223 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
2224 let mut iter = self.0.clone().into_iter();
2225 write!(f, "[")?;
2226 if let Some(first) = iter.next() {
2227 write!(f, "{}", first)?;
2228 let mut last = u64::from(first);
2229 for time in iter {
2230 write!(f, ", +{}", u64::from(time) - last)?;
2231 last = u64::from(time);
2232 }
2233 }
2234 write!(f, "]")?;
2235 Ok(())
2236 }
2237}
2238
2239#[derive(Clone, Copy, Debug)]
2242struct Pairer {
2243 split_arity: usize,
2244}
2245
2246impl Pairer {
2247 fn new(split_arity: usize) -> Self {
2249 Self { split_arity }
2250 }
2251
2252 fn merge<'a, I1, I2>(&self, first: I1, second: I2) -> Row
2254 where
2255 I1: IntoIterator<Item = Datum<'a>>,
2256 I2: IntoIterator<Item = Datum<'a>>,
2257 {
2258 SharedRow::pack(first.into_iter().chain(second))
2259 }
2260
2261 fn split<'a>(&self, datum_iter: impl IntoIterator<Item = Datum<'a>>) -> (Row, Row) {
2263 let mut datum_iter = datum_iter.into_iter();
2264 let mut row_builder = SharedRow::get();
2265 let first = row_builder.pack_using(datum_iter.by_ref().take(self.split_arity));
2266 let second = row_builder.pack_using(datum_iter);
2267 (first, second)
2268 }
2269}