1use std::collections::BTreeMap;
14use std::rc::Rc;
15
16use differential_dataflow::consolidation::ConsolidatingContainerBuilder;
17use differential_dataflow::operators::arrange::Arranged;
18use differential_dataflow::trace::cursor::{BatchCursor, BatchKey, BatchVal};
19use differential_dataflow::trace::implementations::BatchContainer;
20use differential_dataflow::trace::{Cursor, Navigable, TraceReader};
21use differential_dataflow::{AsCollection, Data, VecCollection};
22use mz_compute_types::dataflows::DataflowDescription;
23use mz_compute_types::dyncfgs::{
24 ENABLE_COLUMN_PAGED_BATCHER, ENABLE_COMPUTE_RENDER_FUELED_AS_SPECIFIC_COLLECTION,
25 ENABLE_COMPUTE_TEMPORAL_BUCKETING, TEMPORAL_BUCKETING_SUMMARY,
26};
27use mz_compute_types::plan::scalar::{LirScalarExpr, mfp_mir_to_lir_plan, mfp_plan_lir_to_mir};
28use mz_compute_types::plan::{ArrangementStrategy, AvailableCollections};
29use mz_dyncfg::ConfigSet;
30use mz_expr::{Eval, Id, MfpPlan};
31use mz_ore::soft_assert_or_log;
32use mz_repr::fixed_length::ExtendDatums;
33use mz_repr::{DatumVec, DatumVecBorrow, Diff, GlobalId, Row, RowArena, SharedRow};
34use mz_storage_types::controller::CollectionMetadata;
35use mz_timely_util::columnar::batcher;
36use mz_timely_util::columnar::builder::ColumnBuilder;
37use mz_timely_util::columnar::{Col2ValBatcher, Col2ValPagedBatcher, columnar_exchange};
38use mz_timely_util::columnation::ColumnationChunker;
39use timely::ContainerBuilder;
40use timely::container::{CapacityContainerBuilder, PushInto};
41use timely::dataflow::channels::pact::{ExchangeCore, Pipeline};
42use timely::dataflow::operators::Capability;
43use timely::dataflow::operators::generic::builder_rc::OperatorBuilder;
44use timely::dataflow::operators::generic::{OutputBuilder, OutputBuilderSession};
45use timely::dataflow::{Scope, Stream};
46use timely::progress::operate::FrontierInterest;
47use timely::progress::{Antichain, Timestamp};
48
49use crate::compute_state::ComputeState;
50use crate::extensions::arrange::{KeyCollection, MzArrange, MzArrangeCore};
51use crate::render::columnar::CollectionEdge;
52use crate::render::errors::{DataflowErrorSer, ErrorLogger};
53use crate::render::{LinearJoinSpec, MaybeBucketByTime, RenderTimestamp};
54use crate::typedefs::{
55 ErrAgent, ErrBatcher, ErrBuilder, ErrEnter, ErrSpine, RowRowAgent, RowRowEnter, RowRowSpine,
56};
57use mz_row_spine::{DatumSeq, RowRowBuilder, RowRowColPagedBuilder};
58
59pub struct Context<'scope, T: RenderTimestamp> {
67 pub(crate) scope: Scope<'scope, T>,
71 pub debug_name: String,
73 pub dataflow_id: usize,
75 pub export_ids: Vec<GlobalId>,
77 pub as_of_frontier: Antichain<mz_repr::Timestamp>,
82 pub until: Antichain<mz_repr::Timestamp>,
85 pub bindings: BTreeMap<Id, CollectionBundle<'scope, T>>,
87 pub(super) compute_logger: Option<crate::logging::compute::Logger>,
89 pub(super) linear_join_spec: LinearJoinSpec,
91 pub dataflow_expiration: Antichain<mz_repr::Timestamp>,
94 pub config_set: Rc<ConfigSet>,
96}
97
98impl<'scope, T: RenderTimestamp> Context<'scope, T> {
99 pub fn for_dataflow_in<Plan>(
101 dataflow: &DataflowDescription<Plan, CollectionMetadata>,
102 scope: Scope<'scope, T>,
103 compute_state: &ComputeState,
104 until: Antichain<mz_repr::Timestamp>,
105 dataflow_expiration: Antichain<mz_repr::Timestamp>,
106 ) -> Self {
107 use mz_ore::collections::CollectionExt as IteratorExt;
108 let dataflow_id = *scope.addr().into_first();
109 let as_of_frontier = dataflow
110 .as_of
111 .clone()
112 .unwrap_or_else(|| Antichain::from_elem(Timestamp::minimum()));
113
114 let export_ids = dataflow.export_ids().collect();
115
116 let compute_logger = if dataflow.is_transient() {
120 None
121 } else {
122 compute_state.compute_logger.clone()
123 };
124
125 Self {
126 scope,
127 debug_name: dataflow.debug_name.clone(),
128 dataflow_id,
129 export_ids,
130 as_of_frontier,
131 until,
132 bindings: BTreeMap::new(),
133 compute_logger,
134 linear_join_spec: compute_state.linear_join_spec,
135 dataflow_expiration,
136 config_set: Rc::clone(&compute_state.worker_config),
137 }
138 }
139}
140
141impl<'scope, T: RenderTimestamp> Context<'scope, T> {
142 pub fn insert_id(
147 &mut self,
148 id: Id,
149 collection: CollectionBundle<'scope, T>,
150 ) -> Option<CollectionBundle<'scope, T>> {
151 self.bindings.insert(id, collection)
152 }
153 pub fn remove_id(&mut self, id: Id) -> Option<CollectionBundle<'scope, T>> {
157 self.bindings.remove(&id)
158 }
159 pub fn update_id(&mut self, id: Id, collection: CollectionBundle<'scope, T>) {
161 if !self.bindings.contains_key(&id) {
162 self.bindings.insert(id, collection);
163 } else {
164 let binding = self
165 .bindings
166 .get_mut(&id)
167 .expect("Binding verified to exist");
168 if collection.collection.is_some() {
169 binding.collection = collection.collection;
170 }
171 for (key, flavor) in collection.arranged.into_iter() {
172 binding.arranged.insert(key, flavor);
173 }
174 }
175 }
176 pub fn lookup_id(&self, id: Id) -> Option<CollectionBundle<'scope, T>> {
178 self.bindings.get(&id).cloned()
179 }
180
181 pub(super) fn error_logger(&self) -> ErrorLogger {
182 ErrorLogger::new(self.debug_name.clone())
183 }
184}
185
186impl<'scope, T: RenderTimestamp> Context<'scope, T> {
187 pub fn enter_region<'a>(
189 &self,
190 region: Scope<'a, T>,
191 bindings: Option<&std::collections::BTreeSet<Id>>,
192 ) -> Context<'a, T> {
193 let bindings = self
194 .bindings
195 .iter()
196 .filter(|(key, _)| bindings.as_ref().map(|b| b.contains(key)).unwrap_or(true))
197 .map(|(key, bundle)| (*key, bundle.enter_region(region)))
198 .collect();
199
200 Context {
201 scope: region,
202 debug_name: self.debug_name.clone(),
203 dataflow_id: self.dataflow_id.clone(),
204 export_ids: self.export_ids.clone(),
205 as_of_frontier: self.as_of_frontier.clone(),
206 until: self.until.clone(),
207 compute_logger: self.compute_logger.clone(),
208 linear_join_spec: self.linear_join_spec.clone(),
209 bindings,
210 dataflow_expiration: self.dataflow_expiration.clone(),
211 config_set: Rc::clone(&self.config_set),
212 }
213 }
214}
215
216#[derive(Clone)]
218pub enum ArrangementFlavor<'scope, T: RenderTimestamp> {
219 Local(
221 Arranged<'scope, RowRowAgent<T, Diff>>,
222 Arranged<'scope, ErrAgent<T, Diff>>,
223 ),
224 Trace(
229 GlobalId,
230 Arranged<'scope, RowRowEnter<mz_repr::Timestamp, Diff, T>>,
231 Arranged<'scope, ErrEnter<mz_repr::Timestamp, T>>,
232 ),
233}
234
235impl<'scope, T: RenderTimestamp> ArrangementFlavor<'scope, T> {
236 #[deprecated(note = "Use `flat_map` instead.")]
244 pub fn as_collection(
245 &self,
246 ) -> (
247 VecCollection<'scope, T, Row, Diff>,
248 VecCollection<'scope, T, DataflowErrorSer, Diff>,
249 ) {
250 let mut datums = DatumVec::new();
251 let logic = move |k: DatumSeq, v: DatumSeq| {
252 let temp_storage = RowArena::new();
253 let mut datums_borrow = datums.borrow();
254 k.extend_datums(&temp_storage, &mut datums_borrow, None);
255 v.extend_datums(&temp_storage, &mut datums_borrow, None);
256 SharedRow::pack(&**datums_borrow)
257 };
258 match &self {
259 ArrangementFlavor::Local(oks, errs) => (
260 oks.clone().as_collection(logic),
261 errs.clone().as_collection(|k, &()| k.clone()),
262 ),
263 ArrangementFlavor::Trace(_, oks, errs) => (
264 oks.clone().as_collection(logic),
265 errs.clone().as_collection(|k, &()| k.clone()),
266 ),
267 }
268 }
269
270 pub fn flat_map<D, DCB, L>(
303 &self,
304 key: Option<&Row>,
305 max_demand: usize,
306 logic: L,
307 ) -> (
308 Stream<'scope, T, DCB::Container>,
309 VecCollection<'scope, T, DataflowErrorSer, Diff>,
310 )
311 where
312 D: Data,
313 DCB: ContainerBuilder + PushInto<(D, T, Diff)>,
314 L: for<'a, 'b> FnMut(
315 &'a mut DatumVecBorrow<'b>,
316 T,
317 Diff,
318 &mut Session<T, DCB>,
319 &mut Session<T, ECB<T>>,
320 ) -> usize
321 + 'static,
322 {
323 match &self {
326 ArrangementFlavor::Local(oks, errs) => {
327 let (oks, mfp_errs) = CollectionBundle::<T>::flat_map_core_fallible::<_, _, DCB, _>(
328 oks.clone(),
329 key,
330 max_demand,
331 logic,
332 REFUEL,
333 );
334 let errs = errs.clone().as_collection(|k, &()| k.clone());
335 let errs = errs.concat(mfp_errs.as_collection());
336 (oks, errs)
337 }
338 ArrangementFlavor::Trace(_, oks, errs) => {
339 let (oks, mfp_errs) = CollectionBundle::<T>::flat_map_core_fallible::<_, _, DCB, _>(
340 oks.clone(),
341 key,
342 max_demand,
343 logic,
344 REFUEL,
345 );
346 let errs = errs.clone().as_collection(|k, &()| k.clone());
347 let errs = errs.concat(mfp_errs.as_collection());
348 (oks, errs)
349 }
350 }
351 }
352
353 pub fn flat_map_ok<D, DCB, L>(
358 &self,
359 key: Option<&Row>,
360 max_demand: usize,
361 logic: L,
362 ) -> (
363 Stream<'scope, T, DCB::Container>,
364 VecCollection<'scope, T, DataflowErrorSer, Diff>,
365 )
366 where
367 D: Data,
368 DCB: ContainerBuilder + PushInto<(D, T, Diff)>,
369 L: for<'a, 'b> FnMut(&'a mut DatumVecBorrow<'b>, T, Diff, &mut Session<T, DCB>) -> usize
370 + 'static,
371 {
372 match &self {
373 ArrangementFlavor::Local(oks, errs) => {
374 let oks = CollectionBundle::<T>::flat_map_core_ok::<_, _, DCB, _>(
375 oks.clone(),
376 key,
377 max_demand,
378 logic,
379 REFUEL,
380 );
381 let errs = errs.clone().as_collection(|k, &()| k.clone());
382 (oks, errs)
383 }
384 ArrangementFlavor::Trace(_, oks, errs) => {
385 let oks = CollectionBundle::<T>::flat_map_core_ok::<_, _, DCB, _>(
386 oks.clone(),
387 key,
388 max_demand,
389 logic,
390 REFUEL,
391 );
392 let errs = errs.clone().as_collection(|k, &()| k.clone());
393 (oks, errs)
394 }
395 }
396 }
397}
398impl<'scope, T: RenderTimestamp> ArrangementFlavor<'scope, T> {
399 pub fn scope(&self) -> Scope<'scope, T> {
401 match self {
402 ArrangementFlavor::Local(oks, _errs) => oks.stream.scope(),
403 ArrangementFlavor::Trace(_gid, oks, _errs) => oks.stream.scope(),
404 }
405 }
406
407 pub fn enter_region<'a>(&self, region: Scope<'a, T>) -> ArrangementFlavor<'a, T> {
409 match self {
410 ArrangementFlavor::Local(oks, errs) => ArrangementFlavor::Local(
411 oks.clone().enter_region(region),
412 errs.clone().enter_region(region),
413 ),
414 ArrangementFlavor::Trace(gid, oks, errs) => ArrangementFlavor::Trace(
415 *gid,
416 oks.clone().enter_region(region),
417 errs.clone().enter_region(region),
418 ),
419 }
420 }
421}
422impl<'scope, T: RenderTimestamp> ArrangementFlavor<'scope, T> {
423 pub fn leave_region<'outer>(&self, outer: Scope<'outer, T>) -> ArrangementFlavor<'outer, T> {
425 match self {
426 ArrangementFlavor::Local(oks, errs) => ArrangementFlavor::Local(
427 oks.clone().leave_region(outer),
428 errs.clone().leave_region(outer),
429 ),
430 ArrangementFlavor::Trace(gid, oks, errs) => ArrangementFlavor::Trace(
431 *gid,
432 oks.clone().leave_region(outer),
433 errs.clone().leave_region(outer),
434 ),
435 }
436 }
437}
438
439#[derive(Clone)]
444pub struct CollectionBundle<'scope, T: RenderTimestamp> {
445 pub collection: Option<(
446 CollectionEdge<'scope, T>,
447 VecCollection<'scope, T, DataflowErrorSer, Diff>,
448 )>,
449 pub arranged: BTreeMap<Vec<LirScalarExpr>, ArrangementFlavor<'scope, T>>,
450}
451
452impl<'scope, T: RenderTimestamp> CollectionBundle<'scope, T> {
453 pub fn from_collections(
455 oks: VecCollection<'scope, T, Row, Diff>,
456 errs: VecCollection<'scope, T, DataflowErrorSer, Diff>,
457 ) -> Self {
458 Self::from_edge(CollectionEdge::Vec(oks), errs)
459 }
460
461 pub fn from_edge(
463 oks: CollectionEdge<'scope, T>,
464 errs: VecCollection<'scope, T, DataflowErrorSer, Diff>,
465 ) -> Self {
466 Self {
467 collection: Some((oks, errs)),
468 arranged: BTreeMap::default(),
469 }
470 }
471
472 pub fn from_expressions(
474 exprs: Vec<LirScalarExpr>,
475 arrangements: ArrangementFlavor<'scope, T>,
476 ) -> Self {
477 let mut arranged = BTreeMap::new();
478 arranged.insert(exprs, arrangements);
479 Self {
480 collection: None,
481 arranged,
482 }
483 }
484
485 pub fn from_columns<I: IntoIterator<Item = usize>>(
487 columns: I,
488 arrangements: ArrangementFlavor<'scope, T>,
489 ) -> Self {
490 let mut keys = Vec::new();
491 for column in columns {
492 keys.push(LirScalarExpr::column(column));
493 }
494 Self::from_expressions(keys, arrangements)
495 }
496
497 pub fn scope(&self) -> Scope<'scope, T> {
499 if let Some((oks, _errs)) = &self.collection {
500 oks.scope()
501 } else {
502 self.arranged
503 .values()
504 .next()
505 .expect("Must contain a valid collection")
506 .scope()
507 }
508 }
509
510 pub fn enter_region<'inner>(&self, region: Scope<'inner, T>) -> CollectionBundle<'inner, T> {
512 CollectionBundle {
513 collection: self.collection.as_ref().map(|(oks, errs)| {
514 (
515 oks.clone().enter_region(region),
516 errs.clone().enter_region(region),
517 )
518 }),
519 arranged: self
520 .arranged
521 .iter()
522 .map(|(key, bundle)| (key.clone(), bundle.enter_region(region)))
523 .collect(),
524 }
525 }
526}
527
528impl<'scope, T: RenderTimestamp> CollectionBundle<'scope, T> {
529 pub fn leave_region<'outer>(&self, outer: Scope<'outer, T>) -> CollectionBundle<'outer, T> {
531 CollectionBundle {
532 collection: self.collection.as_ref().map(|(oks, errs)| {
533 (
534 oks.clone().leave_region(outer),
535 errs.clone().leave_region(outer),
536 )
537 }),
538 arranged: self
539 .arranged
540 .iter()
541 .map(|(key, bundle)| (key.clone(), bundle.leave_region(outer)))
542 .collect(),
543 }
544 }
545}
546
547impl<'scope, T: RenderTimestamp> CollectionBundle<'scope, T> {
548 pub fn as_specific_collection(
561 &self,
562 key: Option<&[LirScalarExpr]>,
563 config_set: &ConfigSet,
564 ) -> (
565 VecCollection<'scope, T, Row, Diff>,
566 VecCollection<'scope, T, DataflowErrorSer, Diff>,
567 ) {
568 match key {
574 None => {
575 let (oks, errs) = self
576 .collection
577 .clone()
578 .expect("The unarranged collection doesn't exist.");
579 (oks.into_vec(), errs)
580 }
581 Some(key) => {
582 let arranged = self.arranged.get(key).unwrap_or_else(|| {
583 panic!("The collection arranged by {:?} doesn't exist.", key)
584 });
585 if ENABLE_COMPUTE_RENDER_FUELED_AS_SPECIFIC_COLLECTION.get(config_set) {
586 let (ok, err) = arranged
590 .flat_map_ok::<_, CapacityContainerBuilder<Vec<(Row, T, Diff)>>, _>(
591 None,
592 usize::MAX,
593 |borrow, t, r, ok_session| {
594 ok_session.give((SharedRow::pack(borrow.iter()), t, r));
595 1
596 },
597 );
598 (ok.as_collection(), err)
599 } else {
600 #[allow(deprecated)]
601 arranged.as_collection()
602 }
603 }
604 }
605 }
606
607 pub fn flat_map<D, DCB, L>(
623 &self,
624 key_val: Option<(Vec<LirScalarExpr>, Option<Row>)>,
625 max_demand: usize,
626 logic: L,
627 ) -> (
628 Stream<'scope, T, DCB::Container>,
629 VecCollection<'scope, T, DataflowErrorSer, Diff>,
630 )
631 where
632 D: Data,
633 DCB: ContainerBuilder + PushInto<(D, T, Diff)>,
634 L: for<'a> FnMut(
635 &'a mut DatumVecBorrow<'_>,
636 T,
637 Diff,
638 &mut Session<T, DCB>,
639 &mut Session<T, ECB<T>>,
640 ) -> usize
641 + 'static,
642 {
643 if let Some((key, val)) = key_val {
647 self.arrangement(&key)
648 .expect("Should have ensured during planning that this arrangement exists.")
649 .flat_map::<_, DCB, _>(val.as_ref(), max_demand, logic)
650 } else {
651 let (oks, errs) = self
652 .collection
653 .clone()
654 .expect("Invariant violated: CollectionBundle contains no collection.");
655 let (ok_stream, err_stream) = oks.flat_map_datums::<DCB, _>(max_demand, logic);
656 let errs = errs.concat(err_stream.as_collection());
657 (ok_stream, errs)
658 }
659 }
660
661 fn flat_map_core_fallible<Tr, D, DCB, L>(
672 trace: Arranged<'scope, Tr>,
673 key: Option<&<<BatchCursor<Tr> as Cursor>::KeyContainer as BatchContainer>::Owned>,
674 max_demand: usize,
675 mut logic: L,
676 refuel: usize,
677 ) -> (
678 Stream<'scope, T, DCB::Container>,
679 Stream<'scope, T, Vec<(DataflowErrorSer, T, Diff)>>,
680 )
681 where
682 Tr: TraceReader<Batch: Navigable, Time = T> + Clone + 'static,
683 for<'a> BatchCursor<Tr>:
684 Cursor<Key<'a>: ExtendDatums, Val<'a>: ExtendDatums, Time = T, Diff = mz_repr::Diff>,
685 <<BatchCursor<Tr> as Cursor>::KeyContainer as BatchContainer>::Owned: PartialEq,
686 D: Data,
687 DCB: ContainerBuilder + PushInto<(D, T, Diff)>,
688 L: for<'a, 'b> FnMut(
692 &'a mut DatumVecBorrow<'b>,
693 T,
694 mz_repr::Diff,
695 &mut Session<T, DCB>,
696 &mut Session<T, ECB<T>>,
697 ) -> usize
698 + 'static,
699 {
700 let scope = trace.stream.scope();
701
702 let mut key_con = <BatchCursor<Tr> as Cursor>::KeyContainer::with_capacity(1);
703 if let Some(key) = &key {
704 key_con.push_own(key);
705 }
706 let mode = if key.is_some() { "index" } else { "scan" };
707 let name = format!("ArrangementFlatMap({})", mode);
708
709 let mut builder = OperatorBuilder::new(name, scope.clone());
710 let (ok_output, ok_stream) = builder.new_output();
711 let mut ok_output = OutputBuilder::<_, DCB>::from(ok_output);
712 let (err_output, err_stream) = builder.new_output();
713 let mut err_output = OutputBuilder::<_, ECB<T>>::from(err_output);
714 let mut input = builder.new_input(trace.stream.clone(), Pipeline);
715 let operator_info = builder.operator_info();
716
717 builder.build(move |_capabilities| {
718 let activator = scope.activator_for(operator_info.address);
720 let mut todo = std::collections::VecDeque::new();
722 move |_frontiers| {
723 let key = key_con.get(0);
724 let mut ok_output = ok_output.activate();
725 let mut err_output = err_output.activate();
726
727 input.for_each(|time, data| {
729 let ok_cap = time.retain(0);
732 let err_cap = time.retain(1);
733 for batch in data.iter() {
734 todo.push_back(PendingWork::new(
735 ok_cap.clone(),
736 err_cap.clone(),
737 batch.cursor(),
738 batch.clone(),
739 ));
740 }
741 });
742
743 let mut temp_storage = RowArena::new();
748 let mut datums = DatumVec::new();
749 let mut decode_logic =
750 |k: BatchKey<'_, Tr>,
751 v: BatchVal<'_, Tr>,
752 t: T,
753 d: mz_repr::Diff,
754 ok_session: &mut Session<T, DCB>,
755 err_session: &mut Session<T, ECB<T>>| {
756 temp_storage.clear();
757 let mut datums_borrow = datums.borrow();
758 k.extend_datums(&temp_storage, &mut datums_borrow, Some(max_demand));
759 let remaining = max_demand.saturating_sub(datums_borrow.len());
760 v.extend_datums(&temp_storage, &mut datums_borrow, Some(remaining));
761 logic(&mut datums_borrow, t, d, ok_session, err_session)
762 };
763
764 let mut fuel = refuel;
766 while !todo.is_empty() && fuel > 0 {
767 todo.front_mut().unwrap().do_work(
768 key.as_ref(),
769 &mut decode_logic,
770 &mut fuel,
771 &mut ok_output,
772 &mut err_output,
773 );
774 if fuel > 0 {
775 todo.pop_front();
776 }
777 }
778 if !todo.is_empty() {
780 activator.activate();
781 }
782 }
783 });
784
785 (ok_stream, err_stream)
786 }
787
788 fn flat_map_core_ok<Tr, D, DCB, L>(
794 trace: Arranged<'scope, Tr>,
795 key: Option<&<<BatchCursor<Tr> as Cursor>::KeyContainer as BatchContainer>::Owned>,
796 max_demand: usize,
797 mut logic: L,
798 refuel: usize,
799 ) -> Stream<'scope, T, DCB::Container>
800 where
801 Tr: TraceReader<Batch: Navigable, Time = T> + Clone + 'static,
802 for<'a> BatchCursor<Tr>:
803 Cursor<Key<'a>: ExtendDatums, Val<'a>: ExtendDatums, Time = T, Diff = mz_repr::Diff>,
804 <<BatchCursor<Tr> as Cursor>::KeyContainer as BatchContainer>::Owned: PartialEq,
805 D: Data,
806 DCB: ContainerBuilder + PushInto<(D, T, Diff)>,
807 L: for<'a, 'b> FnMut(
810 &'a mut DatumVecBorrow<'b>,
811 T,
812 mz_repr::Diff,
813 &mut Session<T, DCB>,
814 ) -> usize
815 + 'static,
816 {
817 let scope = trace.stream.scope();
818
819 let mut key_con = <BatchCursor<Tr> as Cursor>::KeyContainer::with_capacity(1);
820 if let Some(key) = &key {
821 key_con.push_own(key);
822 }
823 let mode = if key.is_some() { "index" } else { "scan" };
824 let name = format!("ArrangementFlatMapOk({})", mode);
825
826 let mut builder = OperatorBuilder::new(name, scope.clone());
827 let (ok_output, ok_stream) = builder.new_output();
828 let mut ok_output = OutputBuilder::<_, DCB>::from(ok_output);
829 let mut input = builder.new_input(trace.stream.clone(), Pipeline);
830 let operator_info = builder.operator_info();
831
832 builder.build(move |_capabilities| {
833 let activator = scope.activator_for(operator_info.address);
834 let mut todo = std::collections::VecDeque::new();
835 move |_frontiers| {
836 let key = key_con.get(0);
837 let mut ok_output = ok_output.activate();
838
839 input.for_each(|time, data| {
840 let cap = time.retain(0);
841 for batch in data.iter() {
842 todo.push_back(PendingWorkOk::new(
843 cap.clone(),
844 batch.cursor(),
845 batch.clone(),
846 ));
847 }
848 });
849
850 let mut temp_storage = RowArena::new();
852 let mut datums = DatumVec::new();
853 let mut decode_logic =
854 |k: BatchKey<'_, Tr>,
855 v: BatchVal<'_, Tr>,
856 t: T,
857 d: mz_repr::Diff,
858 ok_session: &mut Session<T, DCB>| {
859 temp_storage.clear();
860 let mut datums_borrow = datums.borrow();
861 k.extend_datums(&temp_storage, &mut datums_borrow, Some(max_demand));
862 let remaining = max_demand.saturating_sub(datums_borrow.len());
863 v.extend_datums(&temp_storage, &mut datums_borrow, Some(remaining));
864 logic(&mut datums_borrow, t, d, ok_session)
865 };
866
867 let mut fuel = refuel;
868 while !todo.is_empty() && fuel > 0 {
869 todo.front_mut().unwrap().do_work(
870 key.as_ref(),
871 &mut decode_logic,
872 &mut fuel,
873 &mut ok_output,
874 );
875 if fuel > 0 {
876 todo.pop_front();
877 }
878 }
879 if !todo.is_empty() {
880 activator.activate();
881 }
882 }
883 });
884
885 ok_stream
886 }
887
888 pub fn arrangement(&self, key: &[LirScalarExpr]) -> Option<ArrangementFlavor<'scope, T>> {
893 self.arranged.get(key).map(|x| x.clone())
894 }
895}
896
897impl<'scope, T: RenderTimestamp> CollectionBundle<'scope, T> {
898 pub fn as_collection_core(
907 &self,
908 mfp_plan: MfpPlan<LirScalarExpr>,
909 key_val: Option<(Vec<LirScalarExpr>, Option<Row>)>,
910 until: Antichain<mz_repr::Timestamp>,
911 config_set: &ConfigSet,
912 ) -> (
913 VecCollection<'scope, T, mz_repr::Row, Diff>,
914 VecCollection<'scope, T, DataflowErrorSer, Diff>,
915 ) {
916 let has_key_val = if let Some((_key, Some(_val))) = &key_val {
922 true
923 } else {
924 false
925 };
926
927 if mfp_plan.is_identity() && !has_key_val {
928 let key = key_val.map(|(k, _v)| k);
929 return self.as_specific_collection(key.as_deref(), config_set);
930 }
931
932 let (mfp_plan, max_demand) = {
937 let mut mir_mfp = mfp_plan_lir_to_mir(mfp_plan).into_map_filter_project();
938 let max_demand = mir_mfp.demand().last().map(|x| *x + 1).unwrap_or(0);
939 mir_mfp.permute_fn(|c| c, max_demand);
940 mir_mfp.optimize();
941 let plan = mfp_mir_to_lir_plan(mir_mfp);
942 (plan, max_demand)
943 };
944
945 let mut datum_vec = DatumVec::new();
946 let until = std::rc::Rc::new(until);
948
949 let (stream, errors) = self
950 .flat_map::<_, ConsolidatingContainerBuilder<Vec<(Row, T, Diff)>>, _>(
951 key_val,
952 max_demand,
953 move |row_datums, time, diff, ok_session, err_session| {
954 let mut row_builder = SharedRow::get();
955 let until = std::rc::Rc::clone(&until);
956 let temp_storage = RowArena::new();
957 let row_iter = row_datums.iter();
958 let mut datums_local = datum_vec.borrow();
959 datums_local.extend(row_iter);
960 let event_time = time.event_time();
961 let mut work: usize = 0;
962 for result in mfp_plan.evaluate(
963 &mut datums_local,
964 &temp_storage,
965 event_time,
966 diff.clone(),
967 move |time| !until.less_equal(time),
968 &mut row_builder,
969 ) {
970 work += 1;
971 match result {
972 Ok((row, event_time, diff)) => {
973 let mut time: T = time.clone();
975 *time.event_time_mut() = event_time;
976 ok_session.give((row, time, diff));
977 }
978 Err((e, event_time, diff)) => {
979 let mut time: T = time.clone();
981 *time.event_time_mut() = event_time;
982 err_session.give((e, time, diff));
983 }
984 }
985 }
986 work
987 },
988 );
989
990 (stream.as_collection(), errors)
991 }
992 pub fn ensure_collections(
993 mut self,
994 collections: AvailableCollections,
995 input_key: Option<Vec<LirScalarExpr>>,
996 input_mfp: MfpPlan<LirScalarExpr>,
997 as_of: Antichain<mz_repr::Timestamp>,
998 until: Antichain<mz_repr::Timestamp>,
999 config_set: &ConfigSet,
1000 strategy: ArrangementStrategy,
1001 ) -> Self
1002 where
1003 T: MaybeBucketByTime,
1004 {
1005 if collections == Default::default() {
1006 return self;
1007 }
1008 for (key, _, _) in collections.arranged.iter() {
1017 soft_assert_or_log!(
1018 !self.arranged.contains_key(key),
1019 "LIR ArrangeBy tried to create an existing arrangement"
1020 );
1021 }
1022
1023 let mut bucketed = false;
1026
1027 let will_create_arrangement = collections
1031 .arranged
1032 .iter()
1033 .any(|(key, _, _)| !self.arranged.contains_key(key));
1034
1035 let form_raw_collection = collections.raw || will_create_arrangement;
1037 if form_raw_collection && self.collection.is_none() {
1038 let (oks, errs) =
1039 self.as_collection_core(input_mfp, input_key.map(|k| (k, None)), until, config_set);
1040 let effective_strategy = if will_create_arrangement {
1044 strategy
1045 } else {
1046 ArrangementStrategy::Direct
1047 };
1048 let oks = if matches!(effective_strategy, ArrangementStrategy::TemporalBucketing)
1049 && ENABLE_COMPUTE_TEMPORAL_BUCKETING.get(config_set)
1050 {
1051 let summary: mz_repr::Timestamp = TEMPORAL_BUCKETING_SUMMARY
1052 .get(config_set)
1053 .try_into()
1054 .expect("must fit");
1055 bucketed = true;
1056 T::maybe_apply_temporal_bucketing(oks.inner, as_of.clone(), summary)
1057 } else {
1058 oks
1059 };
1060 self.collection = Some((CollectionEdge::Vec(oks), errs));
1061 }
1062 for (key, _, thinning) in collections.arranged {
1063 if !self.arranged.contains_key(&key) {
1064 let name = format!("ArrangeBy[{:?}]", key);
1066
1067 let (oks, errs) = self
1068 .collection
1069 .take()
1070 .expect("Collection constructed above");
1071 let oks = oks.into_vec();
1072 let effective_strategy = if bucketed {
1077 ArrangementStrategy::Direct
1078 } else {
1079 strategy
1080 };
1081 let oks = if matches!(effective_strategy, ArrangementStrategy::TemporalBucketing)
1082 && ENABLE_COMPUTE_TEMPORAL_BUCKETING.get(config_set)
1083 {
1084 let summary: mz_repr::Timestamp = TEMPORAL_BUCKETING_SUMMARY
1085 .get(config_set)
1086 .try_into()
1087 .expect("must fit");
1088 bucketed = true;
1089 T::maybe_apply_temporal_bucketing(oks.inner, as_of.clone(), summary)
1090 } else {
1091 oks
1092 };
1093 let use_paged_path = ENABLE_COLUMN_PAGED_BATCHER.get(config_set);
1094 let (oks, errs_keyed, passthrough) = Self::arrange_collection(
1095 &name,
1096 oks,
1097 key.clone(),
1098 thinning.clone(),
1099 use_paged_path,
1100 );
1101 let errs_concat: KeyCollection<_, _, _> = errs.clone().concat(errs_keyed).into();
1102 self.collection = Some((CollectionEdge::Vec(passthrough), errs));
1103 let errs =
1104 errs_concat.mz_arrange::<
1105 ColumnationChunker<_>,
1106 ErrBatcher<_, _>,
1107 ErrBuilder<_, _>,
1108 ErrSpine<_, _>,
1109 >(
1110 &format!("{}-errors", name),
1111 );
1112 self.arranged
1113 .insert(key, ArrangementFlavor::Local(oks, errs));
1114 }
1115 }
1116 self
1117 }
1118
1119 fn arrange_collection(
1130 name: &String,
1131 oks: VecCollection<'scope, T, Row, Diff>,
1132 key: Vec<LirScalarExpr>,
1133 thinning: Vec<usize>,
1134 use_paged_path: bool,
1135 ) -> (
1136 Arranged<'scope, RowRowAgent<T, Diff>>,
1137 VecCollection<'scope, T, DataflowErrorSer, Diff>,
1138 VecCollection<'scope, T, Row, Diff>,
1139 ) {
1140 let mut builder = OperatorBuilder::new("FormArrangementKey".to_string(), oks.inner.scope());
1145 let (ok_output, ok_stream) = builder.new_output();
1146 let mut ok_output =
1147 OutputBuilder::<_, ColumnBuilder<((Row, Row), T, Diff)>>::from(ok_output);
1148 let (err_output, err_stream) = builder.new_output();
1149 let mut err_output = OutputBuilder::from(err_output);
1150 let (passthrough_output, passthrough_stream) = builder.new_output();
1151 let mut passthrough_output = OutputBuilder::from(passthrough_output);
1152 let mut input = builder.new_input(oks.inner, Pipeline);
1153 builder.set_notify_for(0, FrontierInterest::Never);
1154 builder.build(move |_capabilities| {
1155 let mut key_buf = Row::default();
1156 let mut val_buf = Row::default();
1157 let mut datums = DatumVec::new();
1158 move |_frontiers| {
1159 let mut temp_storage = RowArena::new();
1162 let mut ok_output = ok_output.activate();
1163 let mut err_output = err_output.activate();
1164 let mut passthrough_output = passthrough_output.activate();
1165 input.for_each(|time, data| {
1166 let mut ok_session = ok_output.session_with_builder(&time);
1167 let mut err_session = err_output.session(&time);
1168 for (row, time, diff) in data.iter() {
1169 temp_storage.clear();
1170 let datums = datums.borrow_with(row);
1171 let key_iter = key.iter().map(|k| k.eval(&datums, &temp_storage));
1172 match key_buf.packer().try_extend(key_iter) {
1173 Ok(()) => {
1174 let val_datum_iter = thinning.iter().map(|c| datums[*c]);
1175 val_buf.packer().extend(val_datum_iter);
1176 ok_session.give(((&*key_buf, &*val_buf), time, diff));
1177 }
1178 Err(e) => {
1179 err_session.give((e.into(), time.clone(), *diff));
1180 }
1181 }
1182 }
1183 passthrough_output.session(&time).give_container(data);
1184 });
1185 }
1186 });
1187
1188 let exchange =
1189 ExchangeCore::<ColumnBuilder<_>, _>::new_core(columnar_exchange::<Row, Row, T, Diff>);
1190 let oks = if use_paged_path {
1191 ok_stream.mz_arrange_core::<
1192 _,
1193 batcher::ColumnChunker<_>,
1194 Col2ValPagedBatcher<_, _, _, _>,
1195 RowRowColPagedBuilder<_, _>,
1196 RowRowSpine<_, _>,
1197 >(exchange, name)
1198 } else {
1199 ok_stream.mz_arrange_core::<
1200 _,
1201 batcher::Chunker<_>,
1202 Col2ValBatcher<_, _, _, _>,
1203 RowRowBuilder<_, _>,
1204 RowRowSpine<_, _>,
1205 >(exchange, name)
1206 };
1207 (
1208 oks,
1209 err_stream.as_collection(),
1210 passthrough_stream.as_collection(),
1211 )
1212 }
1213}
1214
1215pub(crate) type Session<'a, 'b, T, CB> =
1219 timely::dataflow::operators::generic::Session<'a, 'b, T, CB, Capability<T>>;
1220
1221pub(crate) type ECB<T> = ConsolidatingContainerBuilder<Vec<(DataflowErrorSer, T, Diff)>>;
1226
1227const REFUEL: usize = 1_000_000;
1231
1232struct PendingWork<C>
1233where
1234 C: Cursor,
1235{
1236 ok_capability: Capability<C::Time>,
1238 err_capability: Capability<C::Time>,
1240 cursor: C,
1241 batch: C::Storage,
1242}
1243
1244impl<C> PendingWork<C>
1245where
1246 C: Cursor<KeyContainer: BatchContainer<Owned: PartialEq + Sized>>,
1247{
1248 fn new(
1251 ok_capability: Capability<C::Time>,
1252 err_capability: Capability<C::Time>,
1253 cursor: C,
1254 batch: C::Storage,
1255 ) -> Self {
1256 Self {
1257 ok_capability,
1258 err_capability,
1259 cursor,
1260 batch,
1261 }
1262 }
1263 fn do_work<D, DCB, L>(
1266 &mut self,
1267 key: Option<&C::Key<'_>>,
1268 logic: &mut L,
1269 fuel: &mut usize,
1270 ok_output: &mut OutputBuilderSession<'_, C::Time, DCB>,
1271 err_output: &mut OutputBuilderSession<'_, C::Time, ECB<C::Time>>,
1272 ) where
1273 D: Data,
1274 DCB: ContainerBuilder + PushInto<(D, C::Time, C::Diff)>,
1275 L: FnMut(
1276 C::Key<'_>,
1277 C::Val<'_>,
1278 C::Time,
1279 C::Diff,
1280 &mut Session<C::Time, DCB>,
1281 &mut Session<C::Time, ECB<C::Time>>,
1282 ) -> usize,
1283 {
1284 let mut ok_session = ok_output.session_with_builder(&self.ok_capability);
1285 let mut err_session = err_output.session_with_builder(&self.err_capability);
1286 walk_cursor(&mut self.cursor, &self.batch, key, fuel, |k, v, t, d| {
1287 logic(k, v, t, d, &mut ok_session, &mut err_session)
1288 });
1289 }
1290}
1291
1292struct PendingWorkOk<C>
1295where
1296 C: Cursor,
1297{
1298 capability: Capability<C::Time>,
1299 cursor: C,
1300 batch: C::Storage,
1301}
1302
1303impl<C> PendingWorkOk<C>
1304where
1305 C: Cursor<KeyContainer: BatchContainer<Owned: PartialEq + Sized>>,
1306{
1307 fn new(capability: Capability<C::Time>, cursor: C, batch: C::Storage) -> Self {
1308 Self {
1309 capability,
1310 cursor,
1311 batch,
1312 }
1313 }
1314
1315 fn do_work<D, DCB, L>(
1318 &mut self,
1319 key: Option<&C::Key<'_>>,
1320 logic: &mut L,
1321 fuel: &mut usize,
1322 ok_output: &mut OutputBuilderSession<'_, C::Time, DCB>,
1323 ) where
1324 D: Data,
1325 DCB: ContainerBuilder + PushInto<(D, C::Time, C::Diff)>,
1326 L: FnMut(C::Key<'_>, C::Val<'_>, C::Time, C::Diff, &mut Session<C::Time, DCB>) -> usize,
1327 {
1328 let mut ok_session = ok_output.session_with_builder(&self.capability);
1329 walk_cursor(&mut self.cursor, &self.batch, key, fuel, |k, v, t, d| {
1330 logic(k, v, t, d, &mut ok_session)
1331 });
1332 }
1333}
1334
1335fn walk_cursor<C, F>(
1345 cursor: &mut C,
1346 batch: &C::Storage,
1347 key: Option<&C::Key<'_>>,
1348 fuel: &mut usize,
1349 mut emit: F,
1350) where
1351 C: Cursor<KeyContainer: BatchContainer<Owned: PartialEq + Sized>>,
1352 F: FnMut(C::Key<'_>, C::Val<'_>, C::Time, C::Diff) -> usize,
1353{
1354 use differential_dataflow::consolidation::consolidate;
1355
1356 let mut work: usize = 0;
1357 let mut buffer = Vec::new();
1358 if let Some(key) = key {
1359 let key = C::KeyContainer::reborrow(*key);
1360 if cursor.get_key(batch).map(|k| k == key) != Some(true) {
1361 cursor.seek_key(batch, key);
1362 }
1363 if cursor.get_key(batch).map(|k| k == key) == Some(true) {
1364 let key = cursor.key(batch);
1365 while let Some(val) = cursor.get_val(batch) {
1366 cursor.map_times(batch, |time, diff| {
1367 buffer.push((C::owned_time(time), C::owned_diff(diff)));
1368 });
1369 consolidate(&mut buffer);
1370 for (time, diff) in buffer.drain(..) {
1371 work += emit(key, val, time, diff);
1372 }
1373 cursor.step_val(batch);
1374 if work >= *fuel {
1375 *fuel = 0;
1376 return;
1377 }
1378 }
1379 }
1380 } else {
1381 while let Some(key) = cursor.get_key(batch) {
1382 while let Some(val) = cursor.get_val(batch) {
1383 cursor.map_times(batch, |time, diff| {
1384 buffer.push((C::owned_time(time), C::owned_diff(diff)));
1385 });
1386 consolidate(&mut buffer);
1387 for (time, diff) in buffer.drain(..) {
1388 work += emit(key, val, time, diff);
1389 }
1390 cursor.step_val(batch);
1391 if work >= *fuel {
1392 *fuel = 0;
1393 return;
1394 }
1395 }
1396 cursor.step_key(batch);
1397 }
1398 }
1399 *fuel -= work;
1400}