1use differential_dataflow::operators::arrange::Arranged;
15use differential_dataflow::trace::Cursor;
16use differential_dataflow::trace::cursor::BatchCursor;
17use mz_compute_types::plan::scalar::LirScalarExpr;
18use mz_compute_types::plan::threshold::{BasicThresholdPlan, ThresholdPlan};
19use mz_repr::{Diff, Row, Timestamp};
20use mz_row_spine::{DatumSeq, RowRowBuilder};
21use mz_timely_util::columnation::ColumnationChunker;
22
23use crate::extensions::arrange::{KeyCollection, MzArrange};
24use crate::extensions::reduce::MzReduce;
25use crate::render::RenderTimestamp;
26use crate::render::context::{ArrangementFlavor, CollectionBundle, Context};
27use crate::typedefs::{ErrBatcher, ErrBuilder, RowRowAgent, RowRowEnter, RowRowSpine};
28
29fn threshold_local<'scope, T: RenderTimestamp>(
35 arrangement: Arranged<'scope, RowRowAgent<T, Diff>>,
36 name: &str,
37) -> Arranged<'scope, RowRowAgent<T, Diff>> {
38 arrangement.mz_reduce_abelian::<_, RowRowBuilder<_, _>, RowRowSpine<_, _>, _>(
39 name,
40 move |_key, s, t| {
41 for (record, count) in s.iter() {
42 if count.is_positive() {
43 t.push((
44 <BatchCursor<RowRowSpine<T, Diff>> as Cursor>::owned_val(*record),
45 *count,
46 ));
47 }
48 }
49 },
50 )
51}
52
53fn threshold_trace<'scope, T: RenderTimestamp>(
55 arrangement: Arranged<'scope, RowRowEnter<Timestamp, Diff, T>>,
56 name: &str,
57) -> Arranged<'scope, RowRowAgent<T, Diff>> {
58 let logic = move |_key: DatumSeq<'_>, s: &[(DatumSeq<'_>, Diff)], t: &mut Vec<(Row, Diff)>| {
59 for (record, count) in s.iter() {
60 if count.is_positive() {
61 t.push((
62 <BatchCursor<RowRowSpine<T, Diff>> as Cursor>::owned_val(*record),
63 *count,
64 ));
65 }
66 }
67 };
68 arrangement.mz_reduce_abelian::<_, RowRowBuilder<T, Diff>, RowRowSpine<T, Diff>, _>(name, logic)
69}
70
71pub fn build_threshold_basic<'scope, T: RenderTimestamp>(
76 input: CollectionBundle<'scope, T>,
77 key: Vec<LirScalarExpr>,
78) -> CollectionBundle<'scope, T> {
79 let arrangement = input
80 .arrangement(&key)
81 .expect("Arrangement ensured to exist");
82 match arrangement {
83 ArrangementFlavor::Local(oks, errs) => {
84 let oks = threshold_local(oks, "Threshold local");
85 CollectionBundle::from_expressions(key, ArrangementFlavor::Local(oks, errs))
86 }
87 ArrangementFlavor::Trace(_, oks, errs) => {
88 let oks = threshold_trace(oks, "Threshold trace");
89 let errs: KeyCollection<_, _, _> = errs.as_collection(|k, _| k.clone()).into();
90 let errs = errs
91 .mz_arrange::<ColumnationChunker<_>, ErrBatcher<_, _>, ErrBuilder<_, _>, _>(
92 "Arrange threshold basic err",
93 );
94 CollectionBundle::from_expressions(key, ArrangementFlavor::Local(oks, errs))
95 }
96 }
97}
98
99impl<'scope, T: RenderTimestamp> Context<'scope, T> {
100 pub(crate) fn render_threshold(
101 &self,
102 input: CollectionBundle<'scope, T>,
103 threshold_plan: ThresholdPlan,
104 ) -> CollectionBundle<'scope, T> {
105 match threshold_plan {
106 ThresholdPlan::Basic(BasicThresholdPlan {
107 ensure_arrangement: (key, _, _),
108 }) => {
109 build_threshold_basic(input, key)
113 }
114 }
115 }
116}