Skip to main content

timely/dataflow/operators/generic/
handles.rs

1//! Handles to an operator's input and output streams.
2//!
3//! These handles are used by the generic operator interfaces to allow user closures to interact as
4//! the operator would with its input and output streams.
5
6use std::rc::Rc;
7use std::cell::{OnceCell, RefCell};
8use std::collections::VecDeque;
9
10use crate::progress::Timestamp;
11use crate::progress::ChangeBatch;
12use crate::progress::operate::PortConnectivity;
13use crate::dataflow::channels::pullers::Counter as PullCounter;
14use crate::dataflow::channels::Message;
15use crate::communication::Pull;
16use crate::{Container, ContainerBuilder, Accountable};
17use crate::container::{CapacityContainerBuilder, PushInto};
18
19use crate::dataflow::operators::InputCapability;
20use crate::dataflow::operators::capability::CapabilityTrait;
21
22/// Handle to an operator's input stream.
23pub struct InputHandleCore<T: Timestamp, C, P: Pull<Message<T, C>>> {
24    pull_counter: PullCounter<T, C, P>,
25    internal: Rc<RefCell<Vec<Rc<RefCell<ChangeBatch<T>>>>>>,
26    /// Timestamp summaries from this input to each output.
27    ///
28    /// Each timestamp received through this input may only produce output timestamps
29    /// greater or equal to the input timestamp subjected to at least one of these summaries.
30    summaries: Rc<OnceCell<PortConnectivity<T::Summary>>>,
31    /// Staged capabilities and containers.
32    staging: VecDeque<(InputCapability<T>, C)>,
33    staged: Vec<C>,
34}
35
36impl<T: Timestamp, C: Accountable, P: Pull<Message<T, C>>> InputHandleCore<T, C, P> {
37    /// Reads the next input buffer (at some timestamp `t`) and a corresponding capability for `t`.
38    /// The stamp of the input buffer can be retrieved by invoking `.stamp()` on the capability, and
39    /// for totally ordered timestamps its least time by `.least()`.
40    /// Returns `None` when there's no more data available.
41    #[inline]
42    fn next(&mut self) -> Option<(InputCapability<T>, &mut C)> {
43        let internal = &self.internal;
44        let summaries = &self.summaries;
45        self.pull_counter.next_guarded().map(|(guard, bundle)| {
46            (InputCapability::new(Rc::clone(internal), Rc::clone(summaries), guard), &mut bundle.data)
47        })
48    }
49    /// Iterates through pairs of capability and container.
50    ///
51    /// The `for_each_stamp` method is equivalent, but groups containers by stamp and is preferred,
52    /// in that it often leads to grouping work by stamp, including the creation of output sessions.
53    pub fn for_each<F>(&mut self, mut logic: F) where F: FnMut(InputCapability<T>, &mut C) {
54        while let Some((cap, data)) = self.next() { logic(cap, data); }
55    }
56    /// Iterates through distinct stamps, each with a capability and the containers received under it.
57    ///
58    /// Containers are grouped by the stamp of their message, the set of timestamps under which
59    /// it travels; the capability covers exactly that stamp.
60    pub fn for_each_stamp<F>(&mut self, mut logic: F) where F: FnMut(InputCapability<T>, std::slice::IterMut::<C>), C: Default {
61        while let Some((cap, data)) = self.next() {
62            let data = std::mem::take(data);
63            self.staging.push_back((cap, data));
64        }
65        self.staging.make_contiguous().sort_unstable_by(|x,y| x.0.stamp().cmp(y.0.stamp()));
66
67        while let Some((cap, data)) = self.staging.pop_front() {
68            self.staged.push(data);
69            let more = self.staging.iter().take_while(|(c,_)| c.stamp() == cap.stamp()).count();
70            self.staged.extend(self.staging.drain(..more).map(|(_,d)| d));
71            logic(cap, self.staged.iter_mut());
72            // Could return these back to the input ..
73            self.staged.clear();
74        }
75    }
76    /// Iterates through distinct stamps; renamed to [`for_each_stamp`](Self::for_each_stamp).
77    #[deprecated(note = "renamed to `for_each_stamp`: containers are grouped by stamp, not by a time")]
78    pub fn for_each_time<F>(&mut self, logic: F) where F: FnMut(InputCapability<T>, std::slice::IterMut::<C>), C: Default {
79        self.for_each_stamp(logic)
80    }
81}
82
83/// Constructs an input handle.
84/// Declared separately so that it can be kept private when `InputHandle` is re-exported.
85pub fn new_input_handle<T: Timestamp, C: Accountable, P: Pull<Message<T, C>>>(
86    pull_counter: PullCounter<T, C, P>,
87    internal: Rc<RefCell<Vec<Rc<RefCell<ChangeBatch<T>>>>>>,
88    summaries: Rc<OnceCell<PortConnectivity<T::Summary>>>,
89) -> InputHandleCore<T, C, P> {
90    InputHandleCore {
91        pull_counter,
92        internal,
93        summaries,
94        staging: Default::default(),
95        staged: Default::default(),
96    }
97}
98
99/// An owning pair of output pusher and container builder.
100pub struct OutputBuilder<T: Timestamp, CB: ContainerBuilder> {
101    output: crate::dataflow::channels::pushers::Output<T, CB::Container>,
102    builder: CB,
103}
104
105impl<T: Timestamp, CB: ContainerBuilder> OutputBuilder<T, CB> {
106    /// Constructs an output builder from an output and a default container builder.
107    pub fn from(output: crate::dataflow::channels::pushers::Output<T, CB::Container>) -> Self {
108        Self { output, builder: CB::default() }
109    }
110    /// An activated output buffer for building containers.
111    pub fn activate<'a>(&'a mut self) -> OutputBuilderSession<'a, T, CB> {
112        OutputBuilderSession {
113            session: self.output.activate(),
114            builder: &mut self.builder,
115        }
116    }
117}
118
119/// A wrapper around a live output session, with a container builder to buffer.
120pub struct OutputBuilderSession<'a, T: Timestamp, CB: ContainerBuilder> {
121    session: crate::dataflow::channels::pushers::OutputSession<'a, T, CB::Container>,
122    builder: &'a mut CB,
123}
124
125impl<'a, T: Timestamp, CB: ContainerBuilder> OutputBuilderSession<'a, T, CB> {
126    /// The index of the output port wrapped by this session.
127    #[inline]
128    pub fn output_index(&self) -> usize { self.session.output_index()}
129
130    /// A container-building session associated with a capability.
131    ///
132    /// This method is the prefered way of sending records that must be accumulated into a container,
133    /// as it avoid the recurring overhead of capability validation.
134    pub fn session_with_builder<'b, CT: CapabilityTrait<T>>(&'b mut self, capability: &'b CT) -> Session<'a, 'b, T, CB, CT> where 'a: 'b {
135        debug_assert!(self.session.valid(capability));
136        Session {
137            buffer: self,
138            capability,
139        }
140    }
141}
142
143impl<'a, T: Timestamp, C: Container> OutputBuilderSession<'a, T, CapacityContainerBuilder<C>> {
144    /// A container-building session associated with a capability.
145    ///
146    /// This method is the prefered way of sending records that must be accumulated into a container,
147    /// as it avoid the recurring overhead of capability validation.
148    pub fn session<'b, CT: CapabilityTrait<T>>(&'b mut self, capability: &'b CT) -> Session<'a, 'b, T, CapacityContainerBuilder<C>, CT> where 'a: 'b {
149        debug_assert!(self.session.valid(capability));
150        Session {
151            buffer: self,
152            capability,
153        }
154    }
155}
156
157/// An active output building session, which accepts items and builds containers.
158pub struct Session<'a: 'b, 'b, T: Timestamp, CB: ContainerBuilder, CT: CapabilityTrait<T>> {
159    buffer: &'b mut OutputBuilderSession<'a, T, CB>,
160    capability: &'b CT,
161}
162
163impl<'a: 'b, 'b, T: Timestamp, CB: ContainerBuilder, CT: CapabilityTrait<T>> Session<'a, 'b, T, CB, CT> {
164
165    /// Provides access to the underlying container builder.
166    pub fn builder(&mut self) -> &mut CB { &mut self.buffer.builder }
167
168    /// Provides one record at the time specified by the `Session`.
169    #[inline] pub fn give<D>(&mut self, data: D) where CB: PushInto<D> {
170        self.buffer.builder.push_into(data);
171        self.extract_and_send();
172    }
173    /// Provides an iterator of records at the time specified by the `Session`.
174    #[inline] pub fn give_iterator<I>(&mut self, iter: I) where I: Iterator, CB: PushInto<I::Item> {
175        for item in iter { self.buffer.builder.push_into(item); }
176        self.extract_and_send();
177    }
178    /// Provide a container at the time specified by the [Session].
179    #[inline] pub fn give_container(&mut self, container: &mut CB::Container) {
180        self.buffer.session.give(&self.capability, container);
181    }
182    /// Provide multiple containers at the time specifid by the [Session].
183    #[inline] pub fn give_containers<'c>(&mut self, containers: impl Iterator<Item = &'c mut CB::Container>) {
184        for container in containers { self.buffer.session.give(&self.capability, container); }
185    }
186
187    /// Extracts built containers and sends them.
188    pub fn extract_and_send(&mut self) {
189        while let Some(container) = self.buffer.builder.extract() {
190            self.buffer.session.give(&self.capability, container);
191        }
192    }
193    /// Finalizes containers and sends them.
194    pub fn flush(&mut self) {
195        while let Some(container) = self.buffer.builder.finish() {
196            self.buffer.session.give(&self.capability, container);
197        }
198    }
199}
200
201impl<'a: 'b, 'b, T: Timestamp, CB: ContainerBuilder, CT: CapabilityTrait<T>> Drop for Session<'a, 'b, T, CB, CT> {
202    fn drop(&mut self) { self.flush() }
203}