1use std::cell::{Cell, RefCell};
19use std::collections::VecDeque;
20use std::future::Future;
21use std::pin::Pin;
22use std::rc::Rc;
23use std::sync::Arc;
24use std::sync::atomic::{AtomicBool, Ordering};
25use std::task::{Context, Poll, Waker, ready};
26
27use futures_util::Stream;
28use futures_util::task::ArcWake;
29use timely::communication::{Pull, Push};
30use timely::container::{CapacityContainerBuilder, PushInto};
31use timely::dataflow::channels::Message;
32use timely::dataflow::channels::pact::ParallelizationContract;
33use timely::dataflow::channels::pushers::Output;
34use timely::dataflow::operators::generic::builder_rc::OperatorBuilder as OperatorBuilderRc;
35use timely::dataflow::operators::generic::{InputHandleCore, OperatorInfo};
36use timely::dataflow::operators::{Capability, CapabilitySet, CapabilityTrait, InputCapability};
37use timely::dataflow::{Scope, Stream as TimelyStream, StreamVec};
38use timely::order::TotalOrder;
39use timely::progress::{Antichain, Stamp, Timestamp};
40use timely::scheduling::{Activator, SyncActivator};
41use timely::{Bincode, Container, ContainerBuilder, PartialOrder};
42
43use crate::containers::stack::FueledBuilder;
44
45pub struct OperatorBuilder<'scope, T: Timestamp> {
47 builder: OperatorBuilderRc<'scope, T>,
48 activator: Activator,
50 operator_waker: Arc<TimelyWaker>,
52 input_frontiers: Vec<Antichain<T>>,
54 input_queues: Vec<Box<dyn InputQueue<T>>>,
56 output_flushes: Vec<Box<dyn FnMut()>>,
59 shutdown_handle: ButtonHandle,
61 shutdown_button: Button,
63}
64
65trait InputQueue<T: Timestamp> {
68 fn accept_input(&mut self);
70
71 fn drain_input(&mut self);
73
74 fn notify_progress(&mut self, upper: Antichain<T>);
76}
77
78impl<T, D, C, P> InputQueue<T> for InputHandleQueue<T, D, C, P>
79where
80 T: Timestamp,
81 D: Container,
82 C: InputConnection<T> + 'static,
83 P: Pull<Message<T, D>> + 'static,
84{
85 fn accept_input(&mut self) {
86 let mut queue = self.queue.borrow_mut();
87 let mut new_data = false;
88 self.handle.for_each(|cap, data| {
89 new_data = true;
90 let cap = self.connection.accept(cap);
91 queue.push_back(Event::Data(cap, std::mem::take(data)));
92 });
93 if new_data {
94 if let Some(waker) = self.waker.take() {
95 waker.wake();
96 }
97 }
98 }
99
100 fn drain_input(&mut self) {
101 self.queue.borrow_mut().clear();
102 self.handle.for_each(|_, _| {});
103 }
104
105 fn notify_progress(&mut self, upper: Antichain<T>) {
106 let mut queue = self.queue.borrow_mut();
107 match queue.back_mut() {
111 Some(&mut Event::Progress(ref mut prev_upper)) => *prev_upper = upper,
112 _ => queue.push_back(Event::Progress(upper)),
113 }
114 if let Some(waker) = self.waker.take() {
115 waker.wake();
116 }
117 }
118}
119
120struct InputHandleQueue<
121 T: Timestamp,
122 D: Container,
123 C: InputConnection<T>,
124 P: Pull<Message<T, D>> + 'static,
125> {
126 queue: Rc<RefCell<VecDeque<Event<T, C::Capability, D>>>>,
127 waker: Rc<Cell<Option<Waker>>>,
128 connection: C,
129 handle: InputHandleCore<T, D, P>,
130}
131
132struct TimelyWaker {
134 activator: SyncActivator,
135 active: AtomicBool,
136 task_ready: AtomicBool,
137}
138
139impl ArcWake for TimelyWaker {
140 fn wake_by_ref(arc_self: &Arc<Self>) {
141 arc_self.task_ready.store(true, Ordering::SeqCst);
142 if !arc_self.active.load(Ordering::SeqCst) {
144 let _ = arc_self.activator.activate();
149 }
150 }
151}
152
153pub struct AsyncInputHandle<T: Timestamp, D: Container, C: InputConnection<T>> {
155 queue: Rc<RefCell<VecDeque<Event<T, C::Capability, D>>>>,
156 waker: Rc<Cell<Option<Waker>>>,
157 done: bool,
159}
160
161impl<T: Timestamp, D: Container, C: InputConnection<T>> AsyncInputHandle<T, D, C> {
162 pub fn next_sync(&mut self) -> Option<Event<T, C::Capability, D>> {
163 let mut queue = self.queue.borrow_mut();
164 match queue.pop_front()? {
165 Event::Data(cap, data) => Some(Event::Data(cap, data)),
166 Event::Progress(frontier) => {
167 self.done = frontier.is_empty();
168 Some(Event::Progress(frontier))
169 }
170 }
171 }
172
173 pub async fn ready(&self) {
176 std::future::poll_fn(|cx| self.poll_ready(cx)).await
177 }
178
179 fn poll_ready(&self, cx: &Context<'_>) -> Poll<()> {
180 if self.queue.borrow().is_empty() {
181 self.waker.set(Some(cx.waker().clone()));
182 Poll::Pending
183 } else {
184 Poll::Ready(())
185 }
186 }
187}
188
189impl<T: Timestamp, D: Container, C: InputConnection<T>> Stream for AsyncInputHandle<T, D, C> {
190 type Item = Event<T, C::Capability, D>;
191
192 fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
193 if self.done {
194 return Poll::Ready(None);
195 }
196 ready!(self.poll_ready(cx));
197 Poll::Ready(self.next_sync())
198 }
199
200 fn size_hint(&self) -> (usize, Option<usize>) {
201 (self.queue.borrow().len(), None)
202 }
203}
204
205#[derive(Debug)]
207pub enum Event<T: Timestamp, C, D> {
208 Data(C, D),
210 Progress(Antichain<T>),
212}
213
214struct AsyncOutputHandleInner<T: Timestamp, CB: ContainerBuilder> {
216 output: Output<T, CB::Container>,
218 capability: Option<CapabilitySet<T>>,
220 builder: CB,
222}
223
224impl<T: Timestamp, CB: ContainerBuilder> AsyncOutputHandleInner<T, CB> {
225 fn flush(&mut self) {
227 while let Some(container) = self.builder.finish() {
228 self.output
229 .give(self.capability.as_ref().expect("must exist"), container);
230 }
231 }
232
233 fn cease(&mut self) {
235 self.flush();
236 let _ = self.output.activate();
237 self.capability = None;
238 }
239
240 fn give<D, C>(&mut self, cap: &C, data: D)
243 where
244 CB: PushInto<D>,
245 C: ShipUnder<T>,
246 {
247 if let Some(capability) = &self.capability
248 && !cap.same_times(capability)
249 {
250 self.flush();
251 self.capability = None;
252 }
253 if self.capability.is_none() {
254 self.capability = Some(cap.to_set());
255 }
256
257 self.builder.push_into(data);
258 while let Some(container) = self.builder.extract() {
259 self.output
260 .give(self.capability.as_ref().expect("must exist"), container);
261 }
262 }
263}
264
265pub struct AsyncOutputHandle<T: Timestamp, CB: ContainerBuilder> {
266 inner: Rc<RefCell<AsyncOutputHandleInner<T, CB>>>,
267 index: usize,
268}
269
270impl<T, C> AsyncOutputHandle<T, CapacityContainerBuilder<C>>
271where
272 T: Timestamp,
273 C: Container + Clone + 'static,
274{
275 #[inline]
276 pub fn give_container<Cap: ShipUnder<T>>(&self, cap: &Cap, container: &mut C) {
277 let mut inner = self.inner.borrow_mut();
278 inner.flush();
279 inner.output.give(cap, container);
280 }
281}
282
283impl<T, CB> AsyncOutputHandle<T, CB>
284where
285 T: Timestamp,
286 CB: ContainerBuilder,
287{
288 fn new(output: Output<T, CB::Container>, index: usize) -> Self {
289 let inner = AsyncOutputHandleInner {
290 output,
291 capability: None,
292 builder: CB::default(),
293 };
294 Self {
295 inner: Rc::new(RefCell::new(inner)),
296 index,
297 }
298 }
299
300 fn cease(&self) {
301 self.inner.borrow_mut().cease();
302 }
303}
304
305impl<T, CB> AsyncOutputHandle<T, CB>
306where
307 T: Timestamp,
308 CB: ContainerBuilder,
309{
310 pub fn give<D, Cap: ShipUnder<T>>(&self, cap: &Cap, data: D)
311 where
312 CB: PushInto<D>,
313 {
314 self.inner.borrow_mut().give(cap, data);
315 }
316}
317
318pub const MAX_OUTSTANDING_BYTES: usize = 128 * 1024 * 1024;
321
322impl<T, D> AsyncOutputHandle<T, FueledBuilder<CapacityContainerBuilder<Vec<D>>>>
323where
324 D: Clone + 'static,
325 T: Timestamp,
326{
327 pub async fn give_fueled<D2, Cap: ShipUnder<T>>(&self, cap: &Cap, data: D2, size_bytes: usize)
332 where
333 FueledBuilder<CapacityContainerBuilder<Vec<D>>>: PushInto<D2>,
334 {
335 let should_yield = {
336 let mut handle = self.inner.borrow_mut();
337 handle.give(cap, data);
338 let bytes = &handle.builder.bytes;
339 bytes.set(bytes.get() + size_bytes);
340 let should_yield = bytes.get() > MAX_OUTSTANDING_BYTES;
341 if should_yield {
342 bytes.set(0);
343 }
344 should_yield
345 };
346 if should_yield {
347 tokio::task::yield_now().await;
348 }
349 }
350}
351
352impl<T: Timestamp, CB: ContainerBuilder> Clone for AsyncOutputHandle<T, CB> {
353 fn clone(&self) -> Self {
354 Self {
355 inner: Rc::clone(&self.inner),
356 index: self.index,
357 }
358 }
359}
360
361pub trait InputConnection<T: Timestamp> {
370 type Capability;
372
373 fn describe(&self, outputs: usize) -> Vec<Antichain<T::Summary>>;
375
376 fn accept(&self, input_cap: InputCapability<T>) -> Self::Capability;
378}
379
380pub struct Disconnected;
382
383impl<T: Timestamp> InputConnection<T> for Disconnected {
384 type Capability = Stamp<T>;
385
386 fn describe(&self, outputs: usize) -> Vec<Antichain<T::Summary>> {
387 vec![Antichain::new(); outputs]
388 }
389
390 fn accept(&self, input_cap: InputCapability<T>) -> Self::Capability {
391 input_cap.stamp().clone()
392 }
393}
394
395pub struct ConnectedToOne(usize);
397
398impl<T: Timestamp> InputConnection<T> for ConnectedToOne {
399 type Capability = CapabilitySet<T>;
400
401 fn describe(&self, outputs: usize) -> Vec<Antichain<T::Summary>> {
402 let mut summary = vec![Antichain::new(); outputs];
403 summary[self.0] = Antichain::from_elem(T::Summary::default());
404 summary
405 }
406
407 fn accept(&self, input_cap: InputCapability<T>) -> Self::Capability {
408 input_cap.retain_stamp(self.0)
409 }
410}
411
412pub struct ConnectedToMany<const N: usize>([usize; N]);
414
415impl<const N: usize, T: Timestamp> InputConnection<T> for ConnectedToMany<N> {
416 type Capability = [CapabilitySet<T>; N];
417
418 fn describe(&self, outputs: usize) -> Vec<Antichain<T::Summary>> {
419 let mut summary = vec![Antichain::new(); outputs];
420 for output in self.0 {
421 summary[output] = Antichain::from_elem(T::Summary::default());
422 }
423 summary
424 }
425
426 fn accept(&self, input_cap: InputCapability<T>) -> Self::Capability {
427 self.0.map(|output| input_cap.retain_stamp(output))
428 }
429}
430
431pub fn sole_capability<T: Timestamp + TotalOrder>(
437 capabilities: &CapabilitySet<T>,
438) -> &Capability<T> {
439 match &capabilities[..] {
440 [capability] => capability,
441 [] => panic!("message stamped with no capabilities"),
442 _ => unreachable!("a capability set over a total order holds at most one capability"),
443 }
444}
445
446pub trait ShipUnder<T: Timestamp>: CapabilityTrait<T> {
451 fn to_set(&self) -> CapabilitySet<T>;
453
454 fn same_times(&self, set: &CapabilitySet<T>) -> bool;
458}
459
460impl<T: Timestamp> ShipUnder<T> for Capability<T> {
461 fn to_set(&self) -> CapabilitySet<T> {
462 std::iter::once(self.clone()).collect()
463 }
464
465 fn same_times(&self, set: &CapabilitySet<T>) -> bool {
466 matches!(&set[..], [only] if only.time() == self.time())
467 }
468}
469
470impl<T: Timestamp> ShipUnder<T> for CapabilitySet<T> {
471 fn to_set(&self) -> CapabilitySet<T> {
472 self.clone()
473 }
474
475 fn same_times(&self, set: &CapabilitySet<T>) -> bool {
476 self.len() == set.len()
478 && self
479 .iter()
480 .all(|cap| set.iter().any(|other| other.time() == cap.time()))
481 }
482}
483
484pub trait OutputIndex {
488 fn index(&self) -> usize;
490}
491
492impl<T: Timestamp, CB: ContainerBuilder> OutputIndex for AsyncOutputHandle<T, CB> {
493 fn index(&self) -> usize {
494 self.index
495 }
496}
497
498impl<'scope, T: Timestamp> OperatorBuilder<'scope, T> {
499 pub fn new(name: String, scope: Scope<'scope, T>) -> Self {
501 let builder = OperatorBuilderRc::new(name, scope);
502 let info = builder.operator_info();
503 let activator = scope.activator_for(Rc::clone(&info.address));
504 let sync_activator = scope.worker().sync_activator_for(info.address.to_vec());
505 let operator_waker = TimelyWaker {
506 activator: sync_activator,
507 active: AtomicBool::new(false),
508 task_ready: AtomicBool::new(true),
509 };
510 let (shutdown_handle, shutdown_button) = button(scope, info.address);
511
512 OperatorBuilder {
513 builder,
514 activator,
515 operator_waker: Arc::new(operator_waker),
516 input_frontiers: Default::default(),
517 input_queues: Default::default(),
518 output_flushes: Default::default(),
519 shutdown_handle,
520 shutdown_button,
521 }
522 }
523
524 pub fn new_input_for<D, P>(
526 &mut self,
527 stream: TimelyStream<'scope, T, D>,
528 pact: P,
529 output: &dyn OutputIndex,
530 ) -> AsyncInputHandle<T, D, ConnectedToOne>
531 where
532 D: Container + Clone + 'static,
533 P: ParallelizationContract<T, D>,
534 {
535 let index = output.index();
536 assert!(index < self.builder.shape().outputs());
537 self.new_input_connection(stream, pact, ConnectedToOne(index))
538 }
539
540 pub fn new_input_for_many<const N: usize, D, P>(
542 &mut self,
543 stream: TimelyStream<'scope, T, D>,
544 pact: P,
545 outputs: [&dyn OutputIndex; N],
546 ) -> AsyncInputHandle<T, D, ConnectedToMany<N>>
547 where
548 D: Container + Clone + 'static,
549 P: ParallelizationContract<T, D>,
550 {
551 let indices = outputs.map(|output| output.index());
552 for index in indices {
553 assert!(index < self.builder.shape().outputs());
554 }
555 self.new_input_connection(stream, pact, ConnectedToMany(indices))
556 }
557
558 pub fn new_disconnected_input<D, P>(
560 &mut self,
561 stream: TimelyStream<'scope, T, D>,
562 pact: P,
563 ) -> AsyncInputHandle<T, D, Disconnected>
564 where
565 D: Container + Clone + 'static,
566 P: ParallelizationContract<T, D>,
567 {
568 self.new_input_connection(stream, pact, Disconnected)
569 }
570
571 pub fn new_input_connection<D, P, C>(
573 &mut self,
574 stream: TimelyStream<'scope, T, D>,
575 pact: P,
576 connection: C,
577 ) -> AsyncInputHandle<T, D, C>
578 where
579 D: Container + Clone + 'static,
580 P: ParallelizationContract<T, D>,
581 C: InputConnection<T> + 'static,
582 {
583 self.input_frontiers
584 .push(Antichain::from_elem(T::minimum()));
585
586 let outputs = self.builder.shape().outputs();
587 let handle = self.builder.new_input_connection(
588 stream,
589 pact,
590 connection.describe(outputs).into_iter().enumerate(),
591 );
592
593 let waker = Default::default();
594 let queue = Default::default();
595 let input_queue = InputHandleQueue {
596 queue: Rc::clone(&queue),
597 waker: Rc::clone(&waker),
598 connection,
599 handle,
600 };
601 self.input_queues.push(Box::new(input_queue));
602
603 AsyncInputHandle {
604 queue,
605 waker,
606 done: false,
607 }
608 }
609
610 pub fn new_output<CB: ContainerBuilder>(
612 &mut self,
613 ) -> (
614 AsyncOutputHandle<T, CB>,
615 TimelyStream<'scope, T, CB::Container>,
616 ) {
617 let index = self.builder.shape().outputs();
618
619 let (output, stream) = self.builder.new_output_connection([]);
620
621 let handle = AsyncOutputHandle::new(output, index);
622
623 let flush_handle = handle.clone();
624 self.output_flushes
625 .push(Box::new(move || flush_handle.cease()));
626
627 (handle, stream)
628 }
629
630 pub fn build<B, L>(self, constructor: B) -> Button
635 where
636 B: FnOnce(Vec<Capability<T>>) -> L,
637 L: Future + 'static,
638 {
639 let operator_waker = self.operator_waker;
640 let mut input_frontiers = self.input_frontiers;
641 let mut input_queues = self.input_queues;
642 let mut output_flushes = self.output_flushes;
643 let mut shutdown_handle = self.shutdown_handle;
644 self.builder.build_reschedule(move |caps| {
645 let mut logic_fut = Some(Box::pin(constructor(caps)));
646 move |new_frontiers| {
647 operator_waker.active.store(true, Ordering::SeqCst);
648 for (i, queue) in input_queues.iter_mut().enumerate() {
649 let cur = &mut input_frontiers[i];
651 let new = new_frontiers[i].frontier();
652 if PartialOrder::less_than(&cur.borrow(), &new) {
653 queue.notify_progress(new.to_owned());
654 *cur = new.to_owned();
655 }
656 queue.accept_input();
659 }
660 operator_waker.active.store(false, Ordering::SeqCst);
661
662 if shutdown_handle.local_pressed() {
666 if shutdown_handle.all_pressed() {
669 logic_fut = None;
670 for queue in input_queues.iter_mut() {
671 queue.drain_input();
672 }
673 false
674 } else {
675 true
676 }
677 } else {
678 if let Some(fut) = logic_fut.as_mut() {
680 if operator_waker.task_ready.load(Ordering::SeqCst) {
681 let waker = futures_util::task::waker_ref(&operator_waker);
682 let mut cx = Context::from_waker(&waker);
683 operator_waker.task_ready.store(false, Ordering::SeqCst);
684 if Pin::new(fut).poll(&mut cx).is_ready() {
685 logic_fut = None;
687 }
688 for flush in output_flushes.iter_mut() {
690 (flush)();
691 }
692 }
693 }
694
695 if logic_fut.is_some() {
697 true
698 } else {
699 for queue in input_queues.iter_mut() {
701 queue.drain_input();
702 }
703 false
704 }
705 }
706 }
707 });
708
709 self.shutdown_button
710 }
711
712 pub fn build_fallible<E: 'static, F>(
749 mut self,
750 constructor: F,
751 ) -> (Button, StreamVec<'scope, T, Rc<E>>)
752 where
753 F: for<'a> FnOnce(
754 &'a mut [CapabilitySet<T>],
755 ) -> Pin<Box<dyn Future<Output = Result<(), E>> + 'a>>
756 + 'static,
757 {
758 let (error_output, error_stream) = self.new_output::<CapacityContainerBuilder<_>>();
760 let button = self.build(|mut caps| async move {
761 let error_cap = caps.pop().unwrap();
762 let mut caps = caps
763 .into_iter()
764 .map(CapabilitySet::from_elem)
765 .collect::<Vec<_>>();
766 if let Err(err) = constructor(&mut *caps).await {
767 error_output.give(&error_cap, Rc::new(err));
768 drop(error_cap);
769 std::future::pending().await
772 }
773 });
774 (button, error_stream)
775 }
776
777 pub fn operator_info(&self) -> OperatorInfo {
779 self.builder.operator_info()
780 }
781
782 pub fn activator(&self) -> &Activator {
784 &self.activator
785 }
786}
787
788pub fn button<'scope, T: Timestamp>(
790 scope: Scope<'scope, T>,
791 addr: Rc<[usize]>,
792) -> (ButtonHandle, Button) {
793 let index = scope.worker().new_identifier();
794 let (pushers, puller) = scope.worker().allocate(index, addr);
795
796 let local_pressed = Rc::new(Cell::new(false));
797
798 let handle = ButtonHandle {
799 buttons_remaining: scope.peers(),
800 local_pressed: Rc::clone(&local_pressed),
801 puller,
802 };
803
804 let token = Button {
805 pushers,
806 local_pressed,
807 };
808
809 (handle, token)
810}
811
812pub struct ButtonHandle {
814 buttons_remaining: usize,
816 local_pressed: Rc<Cell<bool>>,
818 puller: Box<dyn Pull<Bincode<bool>>>,
819}
820
821impl ButtonHandle {
822 pub fn local_pressed(&self) -> bool {
824 self.local_pressed.get()
825 }
826
827 pub fn all_pressed(&mut self) -> bool {
829 while self.puller.recv().is_some() {
830 self.buttons_remaining -= 1;
831 }
832 self.buttons_remaining == 0
833 }
834}
835
836pub struct Button {
837 pushers: Vec<Box<dyn Push<Bincode<bool>>>>,
838 local_pressed: Rc<Cell<bool>>,
839}
840
841impl Button {
842 pub fn press(&mut self) {
844 for mut pusher in self.pushers.drain(..) {
845 pusher.send(Bincode::from(true));
846 pusher.done();
847 }
848 self.local_pressed.set(true);
849 }
850
851 pub fn press_on_drop(self) -> PressOnDropButton {
854 PressOnDropButton(self)
855 }
856}
857
858pub struct PressOnDropButton(Button);
859
860impl Drop for PressOnDropButton {
861 fn drop(&mut self) {
862 self.0.press();
863 }
864}
865
866#[cfg(test)]
867mod test {
868 use futures_util::StreamExt;
869 use timely::WorkerConfig;
870 use timely::dataflow::channels::pact::Pipeline;
871 use timely::dataflow::operators::Capture;
872 use timely::dataflow::operators::capture::Extract;
873 use timely::dataflow::operators::vec::ToStream;
874
875 use super::*;
876
877 #[mz_ore::test]
878 fn async_operator() {
879 let capture = timely::example(|scope| {
880 let input = (0..10).to_stream(scope);
881
882 let mut op = OperatorBuilder::new("async_passthru".to_string(), input.scope());
883 let (output, output_stream) = op.new_output::<CapacityContainerBuilder<_>>();
884 let mut input_handle = op.new_input_for(input, Pipeline, &output);
885
886 op.build(move |_capabilities| async move {
887 tokio::task::yield_now().await;
888 while let Some(event) = input_handle.next().await {
889 match event {
890 Event::Data(cap, data) => {
891 for item in data.iter().copied() {
892 tokio::task::yield_now().await;
893 output.give(&cap, item);
894 }
895 }
896 Event::Progress(_frontier) => {}
897 }
898 }
899 });
900
901 output_stream.capture()
902 });
903 let extracted = capture.extract();
904
905 assert_eq!(extracted, vec![(0, vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9])]);
906 }
907
908 #[mz_ore::test]
909 fn gh_18837() {
910 let (builders, other) = timely::CommunicationConfig::Process(2).try_build().unwrap();
911 timely::execute::execute_from(builders, other, WorkerConfig::default(), |worker| {
912 let index = worker.index();
913 let tokens = worker.dataflow::<u64, _, _>(move |scope| {
914 let mut producer = OperatorBuilder::new("producer".to_string(), scope.clone());
915 let (_output, output_stream) =
916 producer.new_output::<CapacityContainerBuilder<Vec<usize>>>();
917 let producer_button = producer.build(move |mut capabilities| async move {
918 let mut cap = capabilities.pop().unwrap();
919 if index != 0 {
920 return;
921 }
922 cap.downgrade(&1);
924 std::future::pending().await
925 });
926
927 let mut consumer = OperatorBuilder::new("consumer".to_string(), scope.clone());
928 let mut input_handle = consumer.new_disconnected_input(output_stream, Pipeline);
929 let consumer_button = consumer.build(move |_| async move {
930 while let Some(event) = input_handle.next().await {
931 if let Event::Progress(frontier) = event {
932 assert!(frontier.less_equal(&1));
934 }
935 }
936 });
937
938 (
939 producer_button.press_on_drop(),
940 consumer_button.press_on_drop(),
941 )
942 });
943
944 for _ in 0..100 {
946 worker.step();
947 }
948 if index == 0 {
950 drop(tokens)
951 }
952 for _ in 0..100 {
954 worker.step();
955 }
956 })
957 .expect("timely panicked");
958 }
959}