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 ::timely::container::{CapacityContainerBuilder, PushInto};
27use ::timely::dataflow::Stream;
28use ::timely::dataflow::channels::pact::Pipeline;
29use ::timely::dataflow::operators::capture::{Event, EventLink, EventPusher};
30use ::timely::dataflow::operators::generic::Session;
31use ::timely::dataflow::operators::{Capability, CapabilityTrait, InputCapability, Operator};
32use ::timely::progress::Timestamp as TimelyTimestamp;
33use ::timely::scheduling::Activator;
34use ::timely::{Container, ContainerBuilder};
35use differential_dataflow::trace::Batcher;
36use mz_compute_client::logging::{ComputeLog, DifferentialLog, LogVariant, TimelyLog};
37use mz_expr::{MirScalarExpr, permutation_for_arrangement};
38use mz_repr::{Datum, Diff, Row, RowPacker, RowRef, Timestamp};
39use mz_timely_util::activator::RcActivator;
40use mz_timely_util::columnar::builder::ColumnBuilder;
41use mz_timely_util::operator::consolidate_pact;
42
43use crate::logging::compute::Logger as ComputeLogger;
44use crate::typedefs::RowRowAgent;
45
46pub use crate::logging::initialize::initialize;
47
48pub(super) type Update<D> = (D, Timestamp, Diff);
50pub(super) type OutputSession<'a, 'b, CB> =
53 Session<'a, 'b, Timestamp, CB, InputCapability<Timestamp>>;
54pub(super) type OutputSessionVec<'a, 'b, D> =
56 OutputSession<'a, 'b, CapacityContainerBuilder<Vec<D>>>;
57pub(super) type OutputSessionColumnar<'a, 'b, D> = OutputSession<'a, 'b, ColumnBuilder<D>>;
59
60struct BatchLogger<C, P>
62where
63 P: EventPusher<Timestamp, C>,
64{
65 time_ms: Timestamp,
67 event_pusher: P,
69 interval_ms: u128,
73 _marker: PhantomData<C>,
74}
75
76impl<C, P> BatchLogger<C, P>
77where
78 P: EventPusher<Timestamp, C>,
79{
80 fn new(event_pusher: P, interval_ms: u128) -> Self {
82 BatchLogger {
83 time_ms: Timestamp::minimum(),
84 event_pusher,
85 interval_ms,
86 _marker: PhantomData,
87 }
88 }
89}
90
91impl<C, P> BatchLogger<C, P>
92where
93 P: EventPusher<Timestamp, C>,
94 C: Container,
95{
96 fn publish_batch(&mut self, data: C) {
98 self.event_pusher.push(Event::Messages(self.time_ms, data));
99 }
100
101 fn report_progress(&mut self, time: Duration) -> bool {
105 let time_ms = ((time.as_millis() / self.interval_ms) + 1) * self.interval_ms;
106 let new_time_ms: Timestamp = time_ms.try_into().expect("must fit");
107 if self.time_ms < new_time_ms {
108 self.event_pusher
109 .push(Event::Progress(vec![(new_time_ms, 1), (self.time_ms, -1)]));
110 self.time_ms = new_time_ms;
111 true
112 } else {
113 false
114 }
115 }
116}
117
118impl<C, P> Drop for BatchLogger<C, P>
119where
120 P: EventPusher<Timestamp, C>,
121{
122 fn drop(&mut self) {
123 self.event_pusher
124 .push(Event::Progress(vec![(self.time_ms, -1)]));
125 }
126}
127
128#[derive(Clone)]
138struct EventQueue<C, const N: usize = 1> {
139 links: [Rc<EventLink<Timestamp, C>>; N],
140 activator: RcActivator,
141}
142
143impl<C, const N: usize> EventQueue<C, N> {
144 fn new(name: &str) -> Self {
145 let activator_name = format!("{name}_activator");
146 let activate_after = 128;
147 Self {
148 links: [(); N].map(|_| Rc::new(EventLink::new())),
149 activator: RcActivator::new(activator_name, activate_after),
150 }
151 }
152}
153
154#[derive(Default)]
156struct SharedLoggingState {
157 arrangement_size_activators: BTreeMap<usize, Activator>,
159 compute_logger: Option<ComputeLogger>,
161}
162
163pub(crate) struct PermutedRowPacker {
165 key: Vec<usize>,
166 value: Vec<usize>,
167 key_row: Row,
168 value_row: Row,
169}
170
171impl PermutedRowPacker {
172 pub(crate) fn new<V: Into<LogVariant>>(variant: V) -> Self {
174 let variant = variant.into();
175 let key = variant.index_by();
176 let (_, value) = permutation_for_arrangement(
177 &key.iter()
178 .cloned()
179 .map(MirScalarExpr::column)
180 .collect::<Vec<_>>(),
181 variant.desc().arity(),
182 );
183 Self {
184 key,
185 value,
186 key_row: Row::default(),
187 value_row: Row::default(),
188 }
189 }
190
191 pub(crate) fn pack_slice(&mut self, datums: &[Datum]) -> (&RowRef, &RowRef) {
193 self.pack_by_index(|packer, index| packer.push(datums[index]))
194 }
195
196 pub(crate) fn pack_by_index<F: Fn(&mut RowPacker, usize)>(
198 &mut self,
199 logic: F,
200 ) -> (&RowRef, &RowRef) {
201 let mut packer = self.key_row.packer();
202 for index in &self.key {
203 logic(&mut packer, *index);
204 }
205
206 let mut packer = self.value_row.packer();
207 for index in &self.value {
208 logic(&mut packer, *index);
209 }
210
211 (&self.key_row, &self.value_row)
212 }
213}
214
215pub(super) fn downgrade_to_interval_boundary(
227 cap: &mut Capability<Timestamp>,
228 activator: &Activator,
229 now: Instant,
230 start_offset: Duration,
231 interval_ms: u128,
232) -> Timestamp {
233 let elapsed = now.elapsed().as_millis();
234 let time_ms: u128 = ((elapsed + start_offset.as_millis()) / interval_ms + 1) * interval_ms;
235 let ts: Timestamp = time_ms.try_into().expect("must fit");
236 cap.downgrade(&ts);
237
238 let next_boundary_ms = time_ms - start_offset.as_millis();
239 let next_activation =
240 now + Duration::from_millis(next_boundary_ms.try_into().expect("must fit"));
241 activator.activate_after(next_activation.saturating_duration_since(Instant::now()));
242
243 ts
244}
245
246pub(super) fn emit_snapshot_diff<K, V, CB, P, F>(
256 session: &mut Session<'_, '_, Timestamp, CB, P>,
257 packer: &mut PermutedRowPacker,
258 prev: &BTreeMap<K, V>,
259 current: &BTreeMap<K, V>,
260 ts: Timestamp,
261 pack: F,
262) where
263 K: Ord,
264 V: PartialEq,
265 CB: ContainerBuilder + for<'a> PushInto<((&'a RowRef, &'a RowRef), Timestamp, Diff)>,
266 P: CapabilityTrait<Timestamp>,
267 F: for<'a> Fn(&'a mut PermutedRowPacker, &K, &V) -> (&'a RowRef, &'a RowRef),
268{
269 for (key, value) in prev {
270 if current.get(key) != Some(value) {
271 let row = pack(packer, key, value);
272 session.give((row, ts, Diff::MINUS_ONE));
273 }
274 }
275 for (key, value) in current {
276 if prev.get(key) != Some(value) {
277 let row = pack(packer, key, value);
278 session.give((row, ts, Diff::ONE));
279 }
280 }
281}
282
283struct LogCollection {
285 trace: RowRowAgent<Timestamp, Diff>,
287 token: Rc<dyn Any>,
289}
290
291pub(super) fn consolidate_and_pack<'scope, Chu, B, CB, L, F, C>(
298 input: Stream<'scope, Timestamp, C>,
299 log: L,
300 mut logic: F,
301) -> Stream<'scope, Timestamp, CB::Container>
302where
303 B: Batcher<Time = Timestamp> + 'static,
304 Chu: ContainerBuilder<Container = B::Output> + for<'a> PushInto<&'a mut C> + 'static,
305 C: Container + Clone + 'static,
306 B::Output: Clone,
307 CB: ContainerBuilder,
308 L: Into<LogVariant>,
309 F: FnMut(B::Output, &mut PermutedRowPacker, &mut OutputSession<CB>) + 'static,
310{
311 let log = log.into();
312 let c_name = &format!("Consolidate {log:?}");
314 let u_name = &format!("ToRow {log:?}");
315 let mut packer = PermutedRowPacker::new(log);
316 let consolidated = consolidate_pact::<Chu, B, _, _>(input, Pipeline, c_name);
317 consolidated.unary::<CB, _, _, _>(Pipeline, u_name, |_, _| {
318 move |input, output| {
319 input.for_each_time(|time, data| {
320 let mut session = output.session_with_builder(&time);
321 for item in data.flatten().flat_map(|data| data.drain(..)) {
322 logic(item, &mut packer, &mut session);
323 }
324 });
325 }
326 })
327}