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