1pub mod compute;
13mod differential;
14pub(super) mod initialize;
15mod prometheus;
16mod reachability;
17mod resource_usage;
18mod timely;
19
20use std::any::Any;
21use std::collections::BTreeMap;
22use std::marker::PhantomData;
23use std::rc::Rc;
24use std::time::{Duration, Instant};
25
26use ::prometheus::IntCounter;
27use ::timely::container::{CapacityContainerBuilder, PushInto};
28use ::timely::dataflow::Stream;
29use ::timely::dataflow::channels::pact::Pipeline;
30use ::timely::dataflow::operators::capture::{Event, EventLink, EventPusher};
31use ::timely::dataflow::operators::generic::Session;
32use ::timely::dataflow::operators::{Capability, CapabilityTrait, InputCapability, Operator};
33use ::timely::progress::Stamp;
34use ::timely::progress::Timestamp as TimelyTimestamp;
35use ::timely::scheduling::Activator;
36use ::timely::{Container, ContainerBuilder};
37use differential_dataflow::trace::Batcher;
38use mz_compute_client::logging::{ComputeLog, DifferentialLog, LogVariant, TimelyLog};
39use mz_expr::{MirScalarExpr, permutation_for_arrangement};
40use mz_repr::{Datum, Diff, Row, RowPacker, RowRef, Timestamp};
41use mz_timely_util::activator::RcActivator;
42use mz_timely_util::columnar::builder::ColumnBuilder;
43use mz_timely_util::operator::{BatcherNew, consolidate_pact};
44
45use crate::logging::compute::Logger as ComputeLogger;
46use crate::typedefs::RowRowAgent;
47
48pub use crate::logging::initialize::initialize;
49
50pub(super) type Update<D> = (D, Timestamp, Diff);
52pub(super) type OutputSession<'a, 'b, CB> =
55 Session<'a, 'b, Timestamp, CB, InputCapability<Timestamp>>;
56pub(super) type OutputSessionVec<'a, 'b, D> =
58 OutputSession<'a, 'b, CapacityContainerBuilder<Vec<D>>>;
59pub(super) type OutputSessionColumnar<'a, 'b, D> = OutputSession<'a, 'b, ColumnBuilder<D>>;
61
62struct BatchLogger<C, P>
64where
65 P: EventPusher<Timestamp, C>,
66{
67 time_ms: Timestamp,
69 event_pusher: P,
71 interval_ms: u128,
75 records_total: IntCounter,
77 _marker: PhantomData<C>,
78}
79
80impl<C, P> BatchLogger<C, P>
81where
82 P: EventPusher<Timestamp, C>,
83{
84 fn new(event_pusher: P, interval_ms: u128, records_total: IntCounter) -> Self {
86 BatchLogger {
87 time_ms: Timestamp::minimum(),
88 event_pusher,
89 interval_ms,
90 records_total,
91 _marker: PhantomData,
92 }
93 }
94}
95
96impl<C, P> BatchLogger<C, P>
97where
98 P: EventPusher<Timestamp, C>,
99 C: Container,
100{
101 fn publish_batch(&mut self, data: C) {
103 let records = u64::try_from(data.record_count()).expect("record count is non-negative");
104 self.records_total.inc_by(records);
105 self.event_pusher
107 .push(Event::Messages(Stamp::from_elem(self.time_ms), data));
108 }
109
110 fn report_progress(&mut self, time: Duration) -> bool {
114 let time_ms = ((time.as_millis() / self.interval_ms) + 1) * self.interval_ms;
115 let new_time_ms: Timestamp = time_ms.try_into().expect("must fit");
116 if self.time_ms < new_time_ms {
117 self.event_pusher
118 .push(Event::Progress(vec![(new_time_ms, 1), (self.time_ms, -1)]));
119 self.time_ms = new_time_ms;
120 true
121 } else {
122 false
123 }
124 }
125}
126
127impl<C, P> Drop for BatchLogger<C, P>
128where
129 P: EventPusher<Timestamp, C>,
130{
131 fn drop(&mut self) {
132 self.event_pusher
133 .push(Event::Progress(vec![(self.time_ms, -1)]));
134 }
135}
136
137#[derive(Clone)]
147struct EventQueue<C, const N: usize = 1> {
148 links: [Rc<EventLink<Timestamp, C>>; N],
149 activator: RcActivator,
150}
151
152impl<C, const N: usize> EventQueue<C, N> {
153 fn new(name: &str) -> Self {
154 let activator_name = format!("{name}_activator");
155 let activate_after = 128;
156 Self {
157 links: [(); N].map(|_| Rc::new(EventLink::new())),
158 activator: RcActivator::new(activator_name, activate_after),
159 }
160 }
161}
162
163#[derive(Default)]
165struct SharedLoggingState {
166 arrangement_size_activators: BTreeMap<usize, Activator>,
168 compute_logger: Option<ComputeLogger>,
170}
171
172pub(crate) struct PermutedRowPacker {
174 key: Vec<usize>,
175 value: Vec<usize>,
176 key_row: Row,
177 value_row: Row,
178}
179
180impl PermutedRowPacker {
181 pub(crate) fn new<V: Into<LogVariant>>(variant: V) -> Self {
183 let variant = variant.into();
184 let key = variant.index_by();
185 let (_, value) = permutation_for_arrangement(
186 &key.iter()
187 .cloned()
188 .map(MirScalarExpr::column)
189 .collect::<Vec<_>>(),
190 variant.desc().arity(),
191 );
192 Self {
193 key,
194 value,
195 key_row: Row::default(),
196 value_row: Row::default(),
197 }
198 }
199
200 pub(crate) fn pack_slice(&mut self, datums: &[Datum]) -> (&RowRef, &RowRef) {
202 self.pack_by_index(|packer, index| packer.push(datums[index]))
203 }
204
205 pub(crate) fn pack_by_index<F: Fn(&mut RowPacker, usize)>(
207 &mut self,
208 logic: F,
209 ) -> (&RowRef, &RowRef) {
210 let mut packer = self.key_row.packer();
211 for index in &self.key {
212 logic(&mut packer, *index);
213 }
214
215 let mut packer = self.value_row.packer();
216 for index in &self.value {
217 logic(&mut packer, *index);
218 }
219
220 (&self.key_row, &self.value_row)
221 }
222}
223
224pub(super) fn downgrade_to_interval_boundary(
236 cap: &mut Capability<Timestamp>,
237 activator: &Activator,
238 now: Instant,
239 start_offset: Duration,
240 interval_ms: u128,
241) -> Timestamp {
242 let elapsed = now.elapsed().as_millis();
243 let time_ms: u128 = ((elapsed + start_offset.as_millis()) / interval_ms + 1) * interval_ms;
244 let ts: Timestamp = time_ms.try_into().expect("must fit");
245 cap.downgrade(&ts);
246
247 let next_boundary_ms = time_ms - start_offset.as_millis();
248 let next_activation =
249 now + Duration::from_millis(next_boundary_ms.try_into().expect("must fit"));
250 activator.activate_after(next_activation.saturating_duration_since(Instant::now()));
251
252 ts
253}
254
255pub(super) fn emit_snapshot_diff<K, V, CB, P, F>(
265 session: &mut Session<'_, '_, Timestamp, CB, P>,
266 packer: &mut PermutedRowPacker,
267 prev: &BTreeMap<K, V>,
268 current: &BTreeMap<K, V>,
269 ts: Timestamp,
270 pack: F,
271) where
272 K: Ord,
273 V: PartialEq,
274 CB: ContainerBuilder + for<'a> PushInto<((&'a RowRef, &'a RowRef), Timestamp, Diff)>,
275 P: CapabilityTrait<Timestamp>,
276 F: for<'a> Fn(&'a mut PermutedRowPacker, &K, &V) -> (&'a RowRef, &'a RowRef),
277{
278 for (key, value) in prev {
279 if current.get(key) != Some(value) {
280 let row = pack(packer, key, value);
281 session.give((row, ts, Diff::MINUS_ONE));
282 }
283 }
284 for (key, value) in current {
285 if prev.get(key) != Some(value) {
286 let row = pack(packer, key, value);
287 session.give((row, ts, Diff::ONE));
288 }
289 }
290}
291
292struct LogCollection {
294 trace: RowRowAgent<Timestamp, Diff>,
296 token: Rc<dyn Any>,
298}
299
300pub(super) fn consolidate_and_pack<'scope, B, CB, L, F, C, Ch>(
307 input: Stream<'scope, Timestamp, C>,
308 log: L,
309 mut logic: F,
310) -> Stream<'scope, Timestamp, CB::Container>
311where
312 B: Batcher<C, Time = Timestamp, Output = Vec<Ch>> + BatcherNew + 'static,
313 C: Container + Clone + 'static,
314 Ch: Clone + 'static,
315 CB: ContainerBuilder,
316 L: Into<LogVariant>,
317 F: FnMut(Ch, &mut PermutedRowPacker, &mut OutputSession<CB>) + 'static,
318{
319 let log = log.into();
320 let c_name = &format!("Consolidate {log:?}");
322 let u_name = &format!("ToRow {log:?}");
323 let mut packer = PermutedRowPacker::new(log);
324 let consolidated = consolidate_pact::<B, _, _>(input, Pipeline, c_name, B::new_batcher);
325 consolidated.unary::<CB, _, _, _>(Pipeline, u_name, |_, _| {
326 move |input, output| {
327 input.for_each_stamp(|time, data| {
328 let mut session = output.session_with_builder(&time);
329 for item in data.flatten().flat_map(|data| data.drain(..)) {
330 logic(item, &mut packer, &mut session);
331 }
332 });
333 }
334 })
335}