1use std::collections::BTreeMap;
11use std::rc::Rc;
12use std::sync::{Arc, Weak};
13
14use differential_dataflow::difference::Semigroup;
15use differential_dataflow::lattice::Lattice;
16use differential_dataflow::operators::arrange::arrangement::arrange_core;
17use differential_dataflow::operators::arrange::{Arranged, TraceAgent};
18use differential_dataflow::trace::implementations::BatchContainer;
19use differential_dataflow::trace::implementations::spine_fueled::Spine;
20use differential_dataflow::trace::{Batch, Batcher, Builder, Trace, TraceReader};
21use differential_dataflow::{Collection, Data, ExchangeData, Hashable, VecCollection};
22use mz_compute_types::dyncfgs::{ENABLE_COLUMN_PAGED_BATCHER, ENABLE_COLUMNAR_MERGE_BATCHER};
23use mz_dyncfg::ConfigSet;
24use mz_row_spine::ArcBatch;
25use mz_timely_util::containers::HeapSize;
26use timely::Container;
27use timely::container::{ContainerBuilder, PushInto};
28use timely::dataflow::Stream;
29use timely::dataflow::channels::pact::{Exchange, ParallelizationContract, Pipeline};
30use timely::dataflow::operators::Operator;
31use timely::progress::Timestamp;
32
33use crate::logging::compute::{
34 ArrangementHeapAllocations, ArrangementHeapCapacity, ArrangementHeapSize,
35 ArrangementHeapSizeOperator, ComputeEvent, ComputeEventBuilder,
36};
37use crate::typedefs::{
38 KeyAgent, KeyValAgent, MzArrangeData, MzData, MzTimestamp, RowAgent, RowRowAgent, RowValAgent,
39};
40
41pub enum ArrangementBatcher {
48 Columnation,
51 Columnar,
54 ColumnarPaged,
57}
58
59impl ArrangementBatcher {
60 pub fn from_config(config: &ConfigSet) -> Self {
68 if ENABLE_COLUMN_PAGED_BATCHER.get(config) {
69 Self::ColumnarPaged
70 } else if ENABLE_COLUMNAR_MERGE_BATCHER.get(config) {
71 Self::Columnar
72 } else {
73 Self::Columnation
74 }
75 }
76}
77
78pub trait MzArrange<'scope>: MzArrangeCore<'scope> {
80 fn mz_arrange<Chu, Ba, Bu, Tr>(self, name: &str) -> Arranged<'scope, TraceAgent<Tr>>
86 where
87 Ba: Batcher<Time = Self::Timestamp> + 'static,
88 Chu: ContainerBuilder<Container = Ba::Output>
89 + for<'a> PushInto<&'a mut Self::Input>
90 + 'static,
91 Bu: Builder<Time = Self::Timestamp, Input = Ba::Output, Output = Tr::Batch>,
92 Tr: Trace + TraceReader<Time = Self::Timestamp> + 'static,
93 Tr::Batch: Batch,
94 Arranged<'scope, TraceAgent<Tr>>: ArrangementSize;
95}
96
97pub trait MzArrangeCore<'scope> {
99 type Timestamp: Timestamp + Lattice;
101 type Input: Container + Clone + 'static;
103
104 fn mz_arrange_core<P, Chu, Ba, Bu, Tr>(
111 self,
112 pact: P,
113 name: &str,
114 ) -> Arranged<'scope, TraceAgent<Tr>>
115 where
116 P: ParallelizationContract<Self::Timestamp, Self::Input>,
117 Ba: Batcher<Time = Self::Timestamp> + 'static,
118 Chu: ContainerBuilder<Container = Ba::Output>
119 + for<'a> PushInto<&'a mut Self::Input>
120 + 'static,
121 Bu: Builder<Time = Self::Timestamp, Input = Ba::Output, Output = Tr::Batch>,
122 Tr: Trace + TraceReader<Time = Self::Timestamp> + 'static,
123 Tr::Batch: Batch,
124 Arranged<'scope, TraceAgent<Tr>>: ArrangementSize;
125}
126
127impl<'scope, T, C> MzArrangeCore<'scope> for Stream<'scope, T, C>
128where
129 T: Timestamp + Lattice,
130 C: Container + Clone + 'static,
131{
132 type Timestamp = T;
133 type Input = C;
134
135 fn mz_arrange_core<P, Chu, Ba, Bu, Tr>(
136 self,
137 pact: P,
138 name: &str,
139 ) -> Arranged<'scope, TraceAgent<Tr>>
140 where
141 P: ParallelizationContract<T, Self::Input>,
142 Ba: Batcher<Time = T> + 'static,
143 Chu: ContainerBuilder<Container = Ba::Output>
144 + for<'a> PushInto<&'a mut Self::Input>
145 + 'static,
146 Bu: Builder<Time = T, Input = Ba::Output, Output = Tr::Batch>,
147 Tr: Trace + TraceReader<Time = T> + 'static,
148 Tr::Batch: Batch,
149 Arranged<'scope, TraceAgent<Tr>>: ArrangementSize,
150 {
151 #[allow(clippy::disallowed_methods)]
153 arrange_core::<_, _, Chu, Ba, Bu, _>(self, pact, name).log_arrangement_size()
154 }
155}
156
157impl<'scope, T, K, V, R> MzArrange<'scope> for VecCollection<'scope, T, (K, V), R>
158where
159 T: Timestamp + Lattice,
160 K: ExchangeData + Hashable,
161 V: ExchangeData,
162 R: ExchangeData,
163{
164 fn mz_arrange<Chu, Ba, Bu, Tr>(self, name: &str) -> Arranged<'scope, TraceAgent<Tr>>
165 where
166 Ba: Batcher<Time = T> + 'static,
167 Chu: ContainerBuilder<Container = Ba::Output>
168 + for<'a> PushInto<&'a mut Self::Input>
169 + 'static,
170 Bu: Builder<Time = T, Input = Ba::Output, Output = Tr::Batch>,
171 Tr: Trace + TraceReader<Time = T> + 'static,
172 Tr::Batch: Batch,
173 Arranged<'scope, TraceAgent<Tr>>: ArrangementSize,
174 {
175 let exchange = Exchange::new(move |update: &((K, V), T, R)| (update.0).0.hashed().into());
176 self.mz_arrange_core::<_, Chu, Ba, Bu, _>(exchange, name)
177 }
178}
179
180impl<'scope, T, C> MzArrangeCore<'scope> for Collection<'scope, T, C>
181where
182 T: Timestamp + Lattice,
183 C: Container + Clone + 'static,
184{
185 type Timestamp = T;
186 type Input = C;
187
188 fn mz_arrange_core<P, Chu, Ba, Bu, Tr>(
189 self,
190 pact: P,
191 name: &str,
192 ) -> Arranged<'scope, TraceAgent<Tr>>
193 where
194 P: ParallelizationContract<T, Self::Input>,
195 Ba: Batcher<Time = T> + 'static,
196 Chu: ContainerBuilder<Container = Ba::Output>
197 + for<'a> PushInto<&'a mut Self::Input>
198 + 'static,
199 Bu: Builder<Time = T, Input = Ba::Output, Output = Tr::Batch>,
200 Tr: Trace + TraceReader<Time = T> + 'static,
201 Tr::Batch: Batch,
202 Arranged<'scope, TraceAgent<Tr>>: ArrangementSize,
203 {
204 self.inner.mz_arrange_core::<_, Chu, Ba, Bu, _>(pact, name)
205 }
206}
207
208pub struct KeyCollection<'scope, T: Timestamp, K: 'static, R: 'static = usize>(
212 VecCollection<'scope, T, K, R>,
213);
214
215impl<'scope, T: Timestamp, K, R: Semigroup> From<VecCollection<'scope, T, K, R>>
216 for KeyCollection<'scope, T, K, R>
217{
218 fn from(value: VecCollection<'scope, T, K, R>) -> Self {
219 KeyCollection(value)
220 }
221}
222
223impl<'scope, T, K, R> MzArrange<'scope> for KeyCollection<'scope, T, K, R>
224where
225 T: Timestamp + Lattice,
226 K: ExchangeData + Hashable,
227 R: ExchangeData,
228{
229 fn mz_arrange<Chu, Ba, Bu, Tr>(self, name: &str) -> Arranged<'scope, TraceAgent<Tr>>
230 where
231 Ba: Batcher<Time = T> + 'static,
232 Chu: ContainerBuilder<Container = Ba::Output>
233 + for<'a> PushInto<&'a mut Self::Input>
234 + 'static,
235 Bu: Builder<Time = T, Input = Ba::Output, Output = Tr::Batch>,
236 Tr: Trace + TraceReader<Time = T> + 'static,
237 Tr::Batch: Batch,
238 Arranged<'scope, TraceAgent<Tr>>: ArrangementSize,
239 {
240 self.0.map(|d| (d, ())).mz_arrange::<Chu, Ba, Bu, _>(name)
241 }
242}
243
244impl<'scope, T, K, R> MzArrangeCore<'scope> for KeyCollection<'scope, T, K, R>
245where
246 T: Timestamp + Lattice,
247 K: Clone + 'static,
248 R: Clone + 'static,
249{
250 type Timestamp = T;
251 type Input = Vec<((K, ()), T, R)>;
252
253 fn mz_arrange_core<P, Chu, Ba, Bu, Tr>(
254 self,
255 pact: P,
256 name: &str,
257 ) -> Arranged<'scope, TraceAgent<Tr>>
258 where
259 P: ParallelizationContract<T, Self::Input>,
260 Ba: Batcher<Time = T> + 'static,
261 Chu: ContainerBuilder<Container = Ba::Output>
262 + for<'a> PushInto<&'a mut Self::Input>
263 + 'static,
264 Bu: Builder<Time = T, Input = Ba::Output, Output = Tr::Batch>,
265 Tr: Trace + TraceReader<Time = T> + 'static,
266 Tr::Batch: Batch,
267 Arranged<'scope, TraceAgent<Tr>>: ArrangementSize,
268 {
269 self.0
270 .map(|d| (d, ()))
271 .mz_arrange_core::<_, Chu, Ba, Bu, _>(pact, name)
272 }
273}
274
275pub trait ArrangementSize {
277 fn log_arrangement_size(self) -> Self;
279}
280
281fn log_arrangement_size_inner<'scope, B, L>(
291 arranged: Arranged<'scope, TraceAgent<Spine<ArcBatch<B>>>>,
292 mut logic: L,
293) -> Arranged<'scope, TraceAgent<Spine<ArcBatch<B>>>>
294where
295 B: Batch + 'static,
296 L: FnMut(&B) -> (usize, usize, usize) + 'static,
297{
298 let scope = arranged.stream.scope();
299 let Some(logger) = scope
300 .worker()
301 .logger_for::<ComputeEventBuilder>("materialize/compute")
302 else {
303 return arranged;
304 };
305 let operator_id = arranged.trace.operator().global_id;
306 let trace = Rc::downgrade(&arranged.trace.trace_box_unstable());
307
308 let (mut old_size, mut old_capacity, mut old_allocations) = (0isize, 0isize, 0isize);
309
310 let stream = arranged
311 .stream
312 .unary(Pipeline, "ArrangementSize", |_cap, info| {
313 let address = info.address;
314 logger.log(&ComputeEvent::ArrangementHeapSizeOperator(
315 ArrangementHeapSizeOperator {
316 operator_id,
317 address: address.to_vec(),
318 },
319 ));
320
321 let mut batches: BTreeMap<*const B, (Weak<B>, (usize, usize, usize))> = BTreeMap::new();
327
328 move |input, output| {
329 input.for_each(|time, data| {
330 for batch in data.iter() {
331 batches
332 .entry(Arc::as_ptr(&batch.0))
333 .or_insert_with(|| (Arc::downgrade(&batch.0), logic(&batch.0)));
334 }
335 output.session(&time).give_container(data);
336 });
337 let Some(trace) = trace.upgrade() else {
338 batches.clear();
345 return;
346 };
347
348 trace.borrow().trace().map_batches(|batch| {
349 batches
350 .entry(Arc::as_ptr(&batch.0))
351 .or_insert_with(|| (Arc::downgrade(&batch.0), logic(&batch.0)));
352 });
353
354 let (mut size, mut capacity, mut allocations) = (0, 0, 0);
355 batches.retain(|_, (weak, cached)| {
356 if weak.strong_count() > 0 {
357 let (sz, c, a) = *cached;
358 (size += sz, capacity += c, allocations += a);
359 true
360 } else {
361 false
362 }
363 });
364
365 let size = size.try_into().expect("must fit");
366 if size != old_size {
367 logger.log(&ComputeEvent::ArrangementHeapSize(ArrangementHeapSize {
368 operator_id,
369 delta_size: size - old_size,
370 }));
371 }
372
373 let capacity = capacity.try_into().expect("must fit");
374 if capacity != old_capacity {
375 logger.log(&ComputeEvent::ArrangementHeapCapacity(
376 ArrangementHeapCapacity {
377 operator_id,
378 delta_capacity: capacity - old_capacity,
379 },
380 ));
381 }
382
383 let allocations = allocations.try_into().expect("must fit");
384 if allocations != old_allocations {
385 logger.log(&ComputeEvent::ArrangementHeapAllocations(
386 ArrangementHeapAllocations {
387 operator_id,
388 delta_allocations: allocations - old_allocations,
389 },
390 ));
391 }
392
393 old_size = size;
394 old_capacity = capacity;
395 old_allocations = allocations;
396 }
397 });
398 Arranged {
399 trace: arranged.trace,
400 stream,
401 }
402}
403
404impl<'scope, T, K, V, R> ArrangementSize for Arranged<'scope, KeyValAgent<K, V, T, R>>
405where
406 T: MzTimestamp,
407 K: Data + MzData,
408 V: Data + MzData,
409 R: Semigroup + Ord + MzData + 'static,
410{
411 fn log_arrangement_size(self) -> Self {
412 log_arrangement_size_inner(self, |batch| {
413 let (mut size, mut capacity, mut allocations) = (0, 0, 0);
414 let mut callback = |siz, cap| {
415 size += siz;
416 capacity += cap;
417 allocations += usize::from(cap > 0);
418 };
419 batch.storage.keys.heap_size(&mut callback);
420 batch.storage.vals.offs.heap_size(&mut callback);
421 batch.storage.vals.vals.heap_size(&mut callback);
422 batch.storage.upds.offs.heap_size(&mut callback);
423 batch.storage.upds.times.heap_size(&mut callback);
424 batch.storage.upds.diffs.heap_size(&mut callback);
425 (size, capacity, allocations)
426 })
427 }
428}
429
430impl<'scope, T, K, R> ArrangementSize for Arranged<'scope, KeyAgent<K, T, R>>
431where
432 T: MzTimestamp,
433 K: Data + MzArrangeData,
434 R: Semigroup + Ord + MzData + 'static,
435{
436 fn log_arrangement_size(self) -> Self {
437 log_arrangement_size_inner(self, |batch| {
438 let (mut size, mut capacity, mut allocations) = (0, 0, 0);
439 let mut callback = |siz, cap| {
440 size += siz;
441 capacity += cap;
442 allocations += usize::from(cap > 0);
443 };
444 batch.storage.keys.heap_size(&mut callback);
445 batch.storage.upds.offs.heap_size(&mut callback);
446 batch.storage.upds.times.heap_size(&mut callback);
447 batch.storage.upds.diffs.heap_size(&mut callback);
448 (size, capacity, allocations)
449 })
450 }
451}
452
453impl<'scope, T, V, R> ArrangementSize for Arranged<'scope, RowValAgent<V, T, R>>
454where
455 T: MzTimestamp,
456 V: Data + MzArrangeData,
457 R: Semigroup + Ord + MzArrangeData + 'static,
458{
459 fn log_arrangement_size(self) -> Self {
460 log_arrangement_size_inner(self, |batch| {
461 let (mut size, mut capacity, mut allocations) = (0, 0, 0);
462 let mut callback = |siz, cap| {
463 size += siz;
464 capacity += cap;
465 allocations += usize::from(cap > 0);
466 };
467 batch.storage.keys.heap_size(&mut callback);
468 batch.storage.vals.offs.heap_size(&mut callback);
469 batch.storage.vals.vals.heap_size(&mut callback);
470 batch.storage.upds.offs.heap_size(&mut callback);
471 batch.storage.upds.times.heap_size(&mut callback);
472 batch.storage.upds.diffs.heap_size(&mut callback);
473 (size, capacity, allocations)
474 })
475 }
476}
477
478impl<'scope, T, R> ArrangementSize for Arranged<'scope, RowRowAgent<T, R>>
479where
480 T: MzTimestamp,
481 R: Semigroup + Ord + MzArrangeData + 'static,
482{
483 fn log_arrangement_size(self) -> Self {
484 log_arrangement_size_inner(self, |batch| {
485 let (mut size, mut capacity, mut allocations) = (0, 0, 0);
486 let mut callback = |siz, cap| {
487 size += siz;
488 capacity += cap;
489 allocations += usize::from(cap > 0);
490 };
491 batch.storage.keys.heap_size(&mut callback);
492 batch.storage.vals.offs.heap_size(&mut callback);
493 batch.storage.vals.vals.heap_size(&mut callback);
494 batch.storage.upds.offs.heap_size(&mut callback);
495 batch.storage.upds.times.heap_size(&mut callback);
496 batch.storage.upds.diffs.heap_size(&mut callback);
497 (size, capacity, allocations)
498 })
499 }
500}
501
502impl<'scope, T, DC> ArrangementSize for Arranged<'scope, RowAgent<T, DC::Owned, DC>>
503where
504 T: MzTimestamp,
505 DC: BatchContainer<Owned: Semigroup + 'static> + HeapSize,
506{
507 fn log_arrangement_size(self) -> Self {
508 log_arrangement_size_inner(self, |batch| {
509 let (mut size, mut capacity, mut allocations) = (0, 0, 0);
510 let mut callback = |siz, cap| {
511 size += siz;
512 capacity += cap;
513 allocations += usize::from(cap > 0);
514 };
515 batch.storage.keys.heap_size(&mut callback);
516 batch.storage.upds.offs.heap_size(&mut callback);
517 batch.storage.upds.times.heap_size(&mut callback);
518 batch.storage.upds.diffs.heap_size(&mut callback);
519 (size, capacity, allocations)
520 })
521 }
522}