1use std::rc::Rc;
9use std::cell::RefCell;
10use std::collections::BinaryHeap;
11use std::cmp::Reverse;
12
13use crate::logging::TimelyLogger as Logger;
14use crate::logging::TimelySummaryLogger as SummaryLogger;
15
16use crate::scheduling::Schedule;
17use crate::scheduling::activate::Activations;
18
19use crate::progress::frontier::{MutableAntichain, MutableAntichainFilter};
20use crate::progress::{Timestamp, Operate, operate::SharedProgress};
21use crate::progress::{Location, Port, Source, Target};
22use crate::progress::operate::{FrontierInterest, Connectivity, PortConnectivity, PortConnectivityBuilder};
23use crate::progress::ChangeBatch;
24use crate::progress::broadcast::Progcaster;
25use crate::progress::reachability;
26use crate::progress::timestamp::Refines;
27
28use crate::worker::ProgressMode;
29
30pub struct SubgraphBuilder<TInner>
40where
41 TInner: Timestamp,
42{
43 pub name: String,
45
46 pub path: Rc<[usize]>,
48
49 index: usize,
51
52 identifier: usize,
54
55 children: Vec<(Box<dyn Operate<TInner>>, usize, usize)>,
57 child_count: usize,
58
59 edge_stash: Vec<(Source, Target)>,
60
61 input_messages: Vec<Rc<RefCell<ChangeBatch<TInner>>>>,
63
64 outputs: usize,
66
67}
68
69impl<TInner> SubgraphBuilder<TInner>
70where
71 TInner: Timestamp,
72{
73 pub fn new_input(&mut self, shared_counts: Rc<RefCell<ChangeBatch<TInner>>>) -> Target {
75 self.input_messages.push(shared_counts);
76 Target::new(self.index, self.input_messages.len() - 1)
77 }
78
79 pub fn new_output(&mut self) -> Source {
81 self.outputs += 1;
82 Source::new(self.index, self.outputs - 1)
83 }
84
85 pub fn connect(&mut self, source: Source, target: Target) {
90 self.edge_stash.push((source, target));
91 }
92
93 pub fn new_from(
96 path: Rc<[usize]>,
97 identifier: usize,
98 name: &str,
99 )
100 -> SubgraphBuilder<TInner>
101 {
102 let index = path[path.len() - 1];
103
104 SubgraphBuilder {
105 name: name.to_owned(),
106 path,
107 index,
108 identifier,
109 children: Vec::new(),
110 child_count: 1,
111 edge_stash: Vec::new(),
112 input_messages: Vec::new(),
113 outputs: 0,
114 }
115 }
116
117 pub fn allocate_child_id(&mut self) -> usize {
119 self.child_count += 1;
120 self.child_count - 1
121 }
122
123 pub fn add_child(&mut self, child: Box<dyn Operate<TInner>>, index: usize, identifier: usize) {
127 self.children.push((child, index, identifier));
128 }
129
130 pub fn build<TOuter: Timestamp>(mut self, worker: &crate::worker::Worker) -> Subgraph<TOuter, TInner> {
132 let inputs = self.input_messages.len();
138 let outputs = self.outputs;
139
140 let type_name = std::any::type_name::<TInner>();
141 let mut logging = worker.logging();
142 let mut summary_logging = worker.logger_for(&format!("timely/summary/{type_name}"));
143
144 self.children.sort_unstable_by_key(|&(_, index, _)| index);
146 let mut children: Vec<_> = [PerOperatorState::empty(outputs, inputs)]
147 .into_iter()
148 .chain(self.children.into_iter().map(|(operator, index, identifier)| {
149 let child = PerOperatorState::new(operator, index, identifier, logging.clone(), &mut summary_logging);
150 if let Some(l) = &mut logging {
151 let mut child_path = Vec::with_capacity(self.path.len() + 1);
152 child_path.extend_from_slice(&self.path[..]);
153 child_path.push(index);
154 l.log(crate::logging::OperatesEvent {
155 id: identifier,
156 addr: child_path,
157 name: child.name.to_owned(),
158 });
159 }
160 child
161 }))
162 .collect();
163 assert!(children.iter().enumerate().all(|(i,x)| i == x.index));
164
165 let mut builder = reachability::Builder::new();
166
167 let summary = (0..outputs).map(|_| PortConnectivity::default()).collect();
169 builder.add_node(0, outputs, inputs, summary);
170 for (index, child) in children.iter_mut().enumerate().skip(1) {
171 let summary = std::mem::take(&mut child.internal_summary);
172 builder.add_node(index, child.inputs, child.outputs, summary);
173 }
174
175 for (source, target) in self.edge_stash {
176 children[source.node].edges[source.port].push(target);
177 builder.add_edge(source, target);
178 }
179
180 let reachability_logging =
181 worker.logger_for(&format!("timely/reachability/{type_name}"))
182 .map(|logger| reachability::logging::TrackerLogger::new(self.identifier, logger));
183 let progress_logging = worker.logger_for(&format!("timely/progress/{type_name}"));
184 let (tracker, scope_summary) = builder.build(reachability_logging);
185
186 let progcaster = Progcaster::new(worker, Rc::clone(&self.path), self.identifier, logging, progress_logging);
187
188 let mut incomplete = vec![true; children.len()];
189 incomplete[0] = false;
190 let incomplete_count = incomplete.len() - 1;
191
192 let activations = worker.activations();
193
194 activations.borrow_mut().activate(&self.path[..]);
195
196 let max_interest = children.iter()
198 .flat_map(|c| c.notify.iter().copied())
199 .max()
200 .unwrap_or(FrontierInterest::Never);
201 let notify_me: Vec<FrontierInterest> = vec![max_interest; inputs];
202
203 Subgraph {
204 name: self.name,
205 path: self.path,
206 inputs,
207 outputs,
208 incomplete,
209 incomplete_count,
210 activations,
211 temp_active: BinaryHeap::new(),
212 maybe_shutdown: Vec::new(),
213 children,
214 input_messages: self.input_messages,
215 output_capabilities: vec![MutableAntichain::new(); self.outputs],
216
217 local_pointstamp: ChangeBatch::new(),
218 final_pointstamp: ChangeBatch::new(),
219 progcaster,
220 pointstamp_tracker: tracker,
221
222 shared_progress: Rc::new(RefCell::new(SharedProgress::new(inputs, outputs))),
223 scope_summary,
224
225 progress_mode: worker.config().progress_mode,
226 notify_me,
227 }
228 }
229}
230
231
232pub struct Subgraph<TOuter, TInner>
237where
238 TOuter: Timestamp,
239 TInner: Timestamp,
240{
241 name: String, pub path: Rc<[usize]>,
244 inputs: usize, outputs: usize, children: Vec<PerOperatorState<TInner>>,
249
250 incomplete: Vec<bool>, incomplete_count: usize, activations: Rc<RefCell<Activations>>,
255 temp_active: BinaryHeap<Reverse<usize>>,
256 maybe_shutdown: Vec<usize>,
257
258 input_messages: Vec<Rc<RefCell<ChangeBatch<TInner>>>>,
260
261 output_capabilities: Vec<MutableAntichain<TOuter>>,
263
264 local_pointstamp: ChangeBatch<(Location, TInner)>,
266 final_pointstamp: ChangeBatch<(Location, TInner)>,
267
268 pointstamp_tracker: reachability::Tracker<TInner>,
271
272 progcaster: Progcaster<TInner>,
274
275 shared_progress: Rc<RefCell<SharedProgress<TOuter>>>,
276 scope_summary: Connectivity<TInner::Summary>,
277
278 progress_mode: ProgressMode,
279
280 notify_me: Vec<FrontierInterest>,
281}
282
283impl<TOuter, TInner> Schedule for Subgraph<TOuter, TInner>
284where
285 TOuter: Timestamp,
286 TInner: Timestamp+Refines<TOuter>,
287{
288 fn name(&self) -> &str { &self.name }
289
290 fn path(&self) -> &[usize] { &self.path }
291
292 fn schedule(&mut self) -> bool {
293
294 self.accept_frontier(); self.harvest_inputs(); self.progcaster.recv(&mut self.final_pointstamp);
304
305 self.propagate_pointstamps();
307
308 { let temp_active = &mut self.temp_active;
310 self.activations
311 .borrow_mut()
312 .for_extensions(&self.path[..], |index| temp_active.push(Reverse(index)));
313 }
314
315 let mut previous = 0;
320 while let Some(Reverse(index)) = self.temp_active.pop() {
321 if index > previous {
323 self.activate_child(index);
325 previous = index;
326 }
327 }
328
329 {
332 let mut shared = self.shared_progress.borrow_mut();
333 for ((location, _time), diff) in self.local_pointstamp.iter() {
334 if let (0, Port::Target(port), true) = (location.node, location.port, *diff > 0) {
335 shared.pushed[port] = true;
336 }
337 }
338 }
339
340 self.send_progress();
342
343 if !self.final_pointstamp.is_empty() {
345 self.activations.borrow_mut().activate(&self.path[..]);
346 }
347
348 let incomplete = self.incomplete_count > 0;
350 let tracking = self.pointstamp_tracker.tracking_anything();
351
352 incomplete || tracking
353 }
354}
355
356
357impl<TOuter, TInner> Subgraph<TOuter, TInner>
358where
359 TOuter: Timestamp,
360 TInner: Timestamp+Refines<TOuter>,
361{
362 fn activate_child(&mut self, child_index: usize) -> bool {
366
367 let child = &mut self.children[child_index];
368
369 let incomplete = child.schedule();
370
371 if incomplete != self.incomplete[child_index] {
372 if incomplete { self.incomplete_count += 1; }
373 else { self.incomplete_count -= 1; }
374 self.incomplete[child_index] = incomplete;
375 }
376
377 if !incomplete {
378 let child_state = self.pointstamp_tracker.node_state(child_index);
380 let frontiers_empty = child_state.targets.iter().all(|x| x.implications.is_empty());
381 let no_capabilities = child_state.sources.iter().all(|x| x.pointstamps.is_empty());
382 if frontiers_empty && no_capabilities {
383 child.shut_down();
384 }
385 }
386 else {
387 #[cfg(debug_assertions)] {
389 child.validate_progress(self.pointstamp_tracker.node_state(child_index));
390 }
391 }
392
393 let outer_pushed = &mut self.shared_progress.borrow_mut().pushed[..];
395 if child.local {
396 child.extract_progress(&mut self.local_pointstamp, &mut self.temp_active, outer_pushed);
397 }
398 else {
399 child.extract_progress(&mut self.final_pointstamp, &mut self.temp_active, outer_pushed);
400 }
401
402 incomplete
403 }
404
405 fn accept_frontier(&mut self) {
407 for (port, changes) in self.shared_progress.borrow_mut().frontiers.iter_mut().enumerate() {
408 let source = Source::new(0, port);
409 for (time, value) in changes.drain() {
410 self.pointstamp_tracker.update_source(
411 source,
412 TInner::to_inner(time),
413 value
414 );
415 }
416 }
417 }
418
419 fn harvest_inputs(&mut self) {
426 for input in 0 .. self.inputs {
427 let source = Location::new_source(0, input);
428 let mut borrowed = self.input_messages[input].borrow_mut();
429 if borrowed.is_empty() { continue; }
430 for (time, delta) in borrowed.drain() {
431 for target in &self.children[0].edges[input] {
432 self.local_pointstamp.update((Location::from(*target), time.clone()), delta);
433 }
434 self.local_pointstamp.update((source, time), -delta);
435 }
436 for target in &self.children[0].edges[input] {
439 self.temp_active.push(Reverse(target.node));
440 }
441 }
442 }
443
444 fn propagate_pointstamps(&mut self) {
460
461 for ((location, timestamp), delta) in self.final_pointstamp.drain() {
463
464 if location.node == 0 {
466 match location.port {
467 Port::Source(scope_input) => {
470 self.shared_progress
471 .borrow_mut()
472 .consumeds[scope_input]
473 .update(timestamp.to_outer(), -delta);
474 },
475 Port::Target(scope_output) => {
479 self.shared_progress
480 .borrow_mut()
481 .produceds[scope_output]
482 .update(timestamp.to_outer(), delta);
483 },
484 }
485 }
486 else {
487 self.pointstamp_tracker.update(location, timestamp, delta);
488 }
489 }
490
491 self.pointstamp_tracker.propagate_all();
493
494 let (pushed, operators) = self.pointstamp_tracker.pushed();
496 for ((location, time), diff) in pushed.drain() {
497 self.maybe_shutdown.push(location.node);
498 if let crate::progress::Port::Target(port) = location.port {
500 let activate = match self.children[location.node].notify[port] {
502 FrontierInterest::Always => true,
503 FrontierInterest::IfCapability => { operators[location.node].cap_counts > 0 }
504 FrontierInterest::Never => false,
505 };
506 if activate { self.temp_active.push(Reverse(location.node)); }
507
508 self.children[location.node]
510 .shared_progress
511 .borrow_mut()
512 .frontiers[port]
513 .update(time, diff);
514 }
515 }
516
517 self.maybe_shutdown.sort_unstable();
519 self.maybe_shutdown.dedup();
520 for child_index in self.maybe_shutdown.drain(..) {
521 let child_state = self.pointstamp_tracker.node_state(child_index);
522 let frontiers_empty = child_state.targets.iter().all(|x| x.implications.is_empty());
523 let no_capabilities = child_state.cap_counts == 0;
524 if frontiers_empty && no_capabilities {
525 self.temp_active.push(Reverse(child_index));
526 }
527 }
528
529 for (output, internal) in self.shared_progress.borrow_mut().internals.iter_mut().enumerate() {
531 self.pointstamp_tracker
532 .pushed_output()[output]
533 .drain()
534 .map(|(time, diff)| (time.to_outer(), diff))
535 .filter_through(&mut self.output_capabilities[output])
536 .for_each(|(time, diff)| internal.update(time, diff));
537 }
538 }
539
540 fn send_progress(&mut self) {
545
546 let must_send = self.progress_mode == ProgressMode::Eager || {
549 let tracker = &mut self.pointstamp_tracker;
550 self.local_pointstamp
551 .iter()
552 .any(|((location, time), diff)|
553 location.node == 0 ||
555 *diff < 0 && tracker.is_global(*location, time)
557 )
558 };
559
560 if must_send {
561 self.progcaster.send(&mut self.local_pointstamp);
562 }
563 }
564}
565
566
567impl<TOuter, TInner> Operate<TOuter> for Subgraph<TOuter, TInner>
568where
569 TOuter: Timestamp,
570 TInner: Timestamp+Refines<TOuter>,
571{
572 fn local(&self) -> bool { false }
573 fn inputs(&self) -> usize { self.inputs }
574 fn outputs(&self) -> usize { self.outputs }
575
576 fn initialize(mut self: Box<Self>) -> (Connectivity<TOuter::Summary>, Rc<RefCell<SharedProgress<TOuter>>>, Box<dyn Schedule>) {
579
580 assert_eq!(self.children[0].outputs, self.inputs());
582 assert_eq!(self.children[0].inputs, self.outputs());
583
584 let mut internal_summary = vec![PortConnectivityBuilder::default(); self.inputs()];
588 for (input_idx, input) in std::mem::take(&mut self.scope_summary).into_iter().enumerate() {
589 for (output_idx, output) in input {
590 for outer in output.into_iter().map(TInner::summarize) {
591 internal_summary[input_idx].insert(output_idx, outer);
592 }
593 }
594 }
595 let internal_summary: Connectivity<_> = internal_summary.into_iter().map(|b| b.freeze()).collect();
596
597 debug_assert_eq!(
598 internal_summary.len(),
599 self.inputs(),
600 "the internal summary should have as many elements as there are inputs",
601 );
602 debug_assert!(
603 internal_summary.iter().all(|os| os.iter_ports().all(|(o,_)| o < self.outputs())),
604 "each element of the internal summary should only reference valid outputs",
605 );
606
607 for child in self.children.iter_mut() {
611 child.extract_progress(&mut self.final_pointstamp, &mut self.temp_active, &mut []);
612 }
613
614 self.propagate_pointstamps(); (internal_summary, Rc::clone(&self.shared_progress), self)
618 }
619
620 fn notify_me(&self) -> &[FrontierInterest] { &self.notify_me }
621}
622
623struct PerOperatorState<T: Timestamp> {
624
625 name: String, index: usize, id: usize, local: bool, notify: Vec<FrontierInterest>,
631 inputs: usize, outputs: usize, operator: Option<Box<dyn Schedule>>,
635
636 edges: Vec<Vec<Target>>, shared_progress: Rc<RefCell<SharedProgress<T>>>,
639
640 internal_summary: Connectivity<T::Summary>, logging: Option<Logger>,
643}
644
645impl<T: Timestamp> PerOperatorState<T> {
646
647 fn empty(inputs: usize, outputs: usize) -> PerOperatorState<T> {
648 PerOperatorState {
649 name: "External".to_owned(),
650 operator: None,
651 index: 0,
652 id: usize::MAX,
653 local: false,
654 notify: vec![FrontierInterest::IfCapability; inputs],
655 inputs,
656 outputs,
657
658 edges: vec![Vec::new(); outputs],
659
660 logging: None,
661
662 shared_progress: Rc::new(RefCell::new(SharedProgress::new(inputs,outputs))),
663 internal_summary: Vec::new(),
664 }
665 }
666
667 pub fn new(
668 scope: Box<dyn Operate<T>>,
669 index: usize,
670 identifier: usize,
671 logging: Option<Logger>,
672 summary_logging: &mut Option<SummaryLogger<T::Summary>>,
673 ) -> PerOperatorState<T>
674 {
675 let local = scope.local();
676 let inputs = scope.inputs();
677 let outputs = scope.outputs();
678 let notify = scope.notify_me().to_vec();
679
680 let (internal_summary, shared_progress, operator) = scope.initialize();
681
682 if let Some(l) = summary_logging {
683 l.log(crate::logging::OperatesSummaryEvent {
684 id: identifier,
685 summary: internal_summary.clone(),
686 })
687 }
688
689 assert_eq!(
690 internal_summary.len(),
691 inputs,
692 "operator summary has {} inputs when {} were expected",
693 internal_summary.len(),
694 inputs,
695 );
696 assert!(
697 internal_summary.iter().all(|os| os.iter_ports().all(|(o,_)| o < outputs)),
698 "operator summary references invalid output port",
699 );
700
701 PerOperatorState {
702 name: operator.name().to_owned(),
703 operator: Some(operator),
704 index,
705 id: identifier,
706 local,
707 notify,
708 inputs,
709 outputs,
710 edges: vec![vec![]; outputs],
711
712 logging,
713
714 shared_progress,
715 internal_summary,
716 }
717 }
718
719 pub fn schedule(&mut self) -> bool {
720
721 if let Some(ref mut operator) = self.operator {
722
723 if let Some(l) = self.logging.as_mut() {
725 let frontiers = &mut self.shared_progress.borrow_mut().frontiers[..];
729 if frontiers.iter_mut().any(|buffer| !buffer.is_empty()) {
730 l.log(crate::logging::PushProgressEvent { op_id: self.id })
731 }
732
733 l.log(crate::logging::ScheduleEvent::start(self.id));
734 }
735
736 let incomplete = {
737 let _current = crate::scheduling::current::enter(self.id);
738 operator.schedule()
739 };
740
741 if let Some(l) = self.logging.as_mut() {
743 l.log(crate::logging::ScheduleEvent::stop(self.id));
744 }
745
746 incomplete
747 }
748 else {
749
750 if self.shared_progress.borrow_mut().frontiers.iter_mut().any(|x| !x.is_empty()) {
752 println!("Operator prematurely shut down: {}", self.name);
753 println!(" {:?}", self.notify);
754 println!(" {:?}", self.shared_progress.borrow_mut().frontiers);
755 panic!();
756 }
757
758 false
760 }
761 }
762
763 fn shut_down(&mut self) {
764 if self.operator.is_some() {
765 if let Some(l) = self.logging.as_mut() {
766 l.log(crate::logging::ShutdownEvent{ id: self.id });
767 }
768 self.operator = None;
769 }
770 }
771
772 fn extract_progress(&self, pointstamps: &mut ChangeBatch<(Location, T)>, temp_active: &mut BinaryHeap<Reverse<usize>>, outer_pushed: &mut [bool]) {
778
779 let shared_progress = &mut *self.shared_progress.borrow_mut();
780
781 for (input, consumed) in shared_progress.consumeds.iter_mut().enumerate() {
783 let target = Location::new_target(self.index, input);
784 for (time, delta) in consumed.drain() {
785 pointstamps.update((target, time), -delta);
786 }
787 }
788 for (output, internal) in shared_progress.internals.iter_mut().enumerate() {
789 let source = Location::new_source(self.index, output);
790 for (time, delta) in internal.drain() {
791 pointstamps.update((source, time), delta);
792 }
793 }
794 for (output, produced) in shared_progress.produceds.iter_mut().enumerate() {
795 for (time, delta) in produced.drain() {
796 if let Some((last, rest)) = self.edges[output].split_last() {
797 for target in rest {
798 pointstamps.update((Location::from(*target), time.clone()), delta);
799 temp_active.push(Reverse(target.node));
800 }
801 pointstamps.update((Location::from(*last), time), delta);
802 temp_active.push(Reverse(last.node));
803 }
804 }
805 }
806 for (output, pushed) in shared_progress.pushed.iter_mut().enumerate() {
807 if std::mem::take(pushed) {
808 for target in self.edges[output].iter() {
809 if target.node == 0 { outer_pushed[target.port] = true; }
810 else { temp_active.push(Reverse(target.node)); }
811 }
812 }
813 }
814 }
815
816 #[allow(dead_code)]
821 fn validate_progress(&self, child_state: &reachability::PerOperator<T>) {
822
823 let shared_progress = &mut *self.shared_progress.borrow_mut();
824
825 for (output, internal) in shared_progress.internals.iter_mut().enumerate() {
827 for (time, diff) in internal.iter() {
828 if *diff > 0 {
829 let consumed = shared_progress.consumeds.iter_mut().any(|x| x.iter().any(|(t,d)| *d > 0 && t.less_equal(time)));
830 let internal = child_state.sources[output].implications.less_equal(time);
831 if !consumed && !internal {
832 println!("Increment at {:?}, not supported by\n\tconsumed: {:?}\n\tinternal: {:?}", time, shared_progress.consumeds, child_state.sources[output].implications);
833 panic!("Progress error; internal {:?}", self.name);
834 }
835 }
836 }
837 }
838 for (output, produced) in shared_progress.produceds.iter_mut().enumerate() {
839 for (time, diff) in produced.iter() {
840 if *diff > 0 {
841 let consumed = shared_progress.consumeds.iter_mut().any(|x| x.iter().any(|(t,d)| *d > 0 && t.less_equal(time)));
842 let internal = child_state.sources[output].implications.less_equal(time);
843 if !consumed && !internal {
844 println!("Increment at {:?}, not supported by\n\tconsumed: {:?}\n\tinternal: {:?}", time, shared_progress.consumeds, child_state.sources[output].implications);
845 panic!("Progress error; produced {:?}", self.name);
846 }
847 }
848 }
849 }
850 }
851}
852
853impl<T: Timestamp> Drop for PerOperatorState<T> {
855 fn drop(&mut self) {
856 self.shut_down();
857 }
858}