timely/dataflow/operators/core/
enterleave.rs1use std::marker::PhantomData;
23use std::rc::Rc;
24
25use crate::logging::{TimelyLogger, MessagesEvent};
26use crate::progress::Timestamp;
27use crate::progress::timestamp::Refines;
28use crate::progress::{Source, Target};
29use crate::{Accountable, Container};
30use crate::communication::Push;
31use crate::dataflow::channels::pushers::{Counter, Tee};
32use crate::dataflow::channels::Message;
33use crate::dataflow::{Stream, Scope};
34
35pub trait Enter<'outer, TOuter: Timestamp, TInner: Timestamp+Refines<TOuter>, C> {
37 fn enter<'inner>(self, inner: Scope<'inner, TInner>) -> Stream<'inner, TInner, C>;
54}
55
56impl<'outer, TOuter, TInner, C> Enter<'outer, TOuter, TInner, C> for Stream<'outer, TOuter, C>
57where
58 TOuter: Timestamp,
59 TInner: Timestamp + Refines<TOuter>,
60 C: Container,
61{
62 fn enter<'inner>(self, inner: Scope<'inner, TInner>) -> Stream<'inner, TInner, C> {
63
64 let inner_addr = inner.addr();
66 let outer_addr = self.scope().addr();
67 assert!(
68 inner_addr.len() == outer_addr.len() + 1
69 && inner_addr[..outer_addr.len()] == outer_addr[..],
70 "Enter::enter: `inner` is not a child of the stream's scope \
71 (inner addr: {:?}, outer addr: {:?})",
72 inner_addr,
73 outer_addr,
74 );
75
76 let (targets, registrar) = Tee::<TInner, C>::new();
77 let ingress = IngressNub {
78 targets: Counter::new(targets),
79 phantom: PhantomData,
80 activator: inner.activator_for(inner_addr),
81 active: false,
82 };
83 let produced = Rc::clone(ingress.targets.produced());
84 let input = inner.subgraph.borrow_mut().new_input(produced);
85 let channel_id = inner.worker().new_identifier();
86
87 if let Some(logger) = inner.worker().logging() {
88 let pusher = LogPusher::new(ingress, channel_id, inner.index(), logger);
89 self.connect_to(input, pusher, channel_id);
90 } else {
91 self.connect_to(input, ingress, channel_id);
92 }
93
94 Stream::new(Source::new(0, input.port), registrar, inner)
95 }
96}
97
98pub trait Leave<'inner, TInner: Timestamp, C> {
100 fn leave<'outer, TOuter: Timestamp>(self, outer: Scope<'outer, TOuter>) -> Stream<'outer, TOuter, C> where TInner: Refines<TOuter>;
119}
120
121impl<'inner, TInner, C> Leave<'inner, TInner, C> for Stream<'inner, TInner, C>
122where
123 TInner: Timestamp,
124 C: Container,
125{
126 fn leave<'outer, TOuter: Timestamp>(self, outer: Scope<'outer, TOuter>) -> Stream<'outer, TOuter, C> where TInner: Refines<TOuter> {
127
128 let scope = self.scope();
129
130 let inner_addr = scope.addr();
132 let outer_addr = outer.addr();
133 assert!(
134 inner_addr.len() == outer_addr.len() + 1
135 && inner_addr[..outer_addr.len()] == outer_addr[..],
136 "Leave::leave: `outer` is not the parent of the stream's scope \
137 (stream addr: {:?}, outer addr: {:?})",
138 inner_addr,
139 outer_addr,
140 );
141
142 let output = scope.subgraph.borrow_mut().new_output();
143 let target = Target::new(0, output.port);
144 let (targets, registrar) = Tee::<TOuter, C>::new();
145 let egress = EgressNub { targets, phantom: PhantomData };
146 let channel_id = scope.worker().new_identifier();
147
148 if let Some(logger) = scope.worker().logging() {
149 let pusher = LogPusher::new(egress, channel_id, scope.index(), logger);
150 self.connect_to(target, pusher, channel_id);
151 } else {
152 self.connect_to(target, egress, channel_id);
153 }
154
155 Stream::new(output, registrar, outer)
156 }
157}
158
159
160struct IngressNub<TOuter: Timestamp, TInner: Timestamp+Refines<TOuter>, TContainer: Container> {
161 targets: Counter<TInner, Tee<TInner, TContainer>>,
162 phantom: PhantomData<TOuter>,
163 activator: crate::scheduling::Activator,
164 active: bool,
165}
166
167impl<TOuter: Timestamp, TInner: Timestamp+Refines<TOuter>, TContainer: Container> Push<Message<TOuter, TContainer>> for IngressNub<TOuter, TInner, TContainer> {
168 fn push(&mut self, element: &mut Option<Message<TOuter, TContainer>>) {
169 if let Some(outer_message) = element {
170 let data = ::std::mem::take(&mut outer_message.data);
171 let stamp = outer_message.stamp.map_pointwise(|time| TInner::to_inner(time.clone()));
172 let mut inner_message = Some(Message::new(stamp, data));
173 self.targets.push(&mut inner_message);
174 if let Some(inner_message) = inner_message {
175 outer_message.data = inner_message.data;
176 }
177 self.active = true;
178 }
179 else {
180 if self.active {
181 self.activator.activate();
182 self.active = false;
183 }
184 self.targets.done();
185 }
186 }
187}
188
189
190struct EgressNub<TOuter: Timestamp, TInner: Timestamp+Refines<TOuter>, TContainer> {
191 targets: Tee<TOuter, TContainer>,
192 phantom: PhantomData<TInner>,
193}
194
195impl<TOuter, TInner, TContainer: Container> Push<Message<TInner, TContainer>> for EgressNub<TOuter, TInner, TContainer>
196where TOuter: Timestamp, TInner: Timestamp+Refines<TOuter>, {
197 fn push(&mut self, message: &mut Option<Message<TInner, TContainer>>) {
198 if let Some(inner_message) = message {
199 let data = ::std::mem::take(&mut inner_message.data);
200 let stamp = inner_message.stamp.map_pointwise(|time| time.clone().to_outer());
201 let mut outer_message = Some(Message::new(stamp, data));
202 self.targets.push(&mut outer_message);
203 if let Some(outer_message) = outer_message {
204 inner_message.data = outer_message.data;
205 }
206 }
207 else { self.targets.done(); }
208 }
209}
210
211struct LogPusher<P> {
218 pusher: P,
219 channel: usize,
220 counter: usize,
221 index: usize,
222 logger: TimelyLogger,
223}
224
225impl<P> LogPusher<P> {
226 fn new(pusher: P, channel: usize, index: usize, logger: TimelyLogger) -> Self {
227 Self {
228 pusher,
229 channel,
230 counter: 0,
231 index,
232 logger,
233 }
234 }
235}
236
237impl<T, C, P> Push<Message<T, C>> for LogPusher<P>
238where
239 C: Accountable,
240 P: Push<Message<T, C>>,
241{
242 fn push(&mut self, element: &mut Option<Message<T, C>>) {
243 if let Some(bundle) = element {
244 let send_event = MessagesEvent {
245 is_send: true,
246 channel: self.channel,
247 source: self.index,
248 target: self.index,
249 seq_no: self.counter,
250 record_count: bundle.data.record_count(),
251 };
252 let recv_event = MessagesEvent {
253 is_send: false,
254 ..send_event
255 };
256
257 self.logger.log(send_event);
258 self.logger.log(recv_event);
259 self.counter += 1;
260 }
261
262 self.pusher.push(element);
263 }
264}
265
266#[cfg(test)]
267mod test {
268 #[test]
272 fn test_nested() {
273
274 use crate::dataflow::{InputHandle, ProbeHandle};
275 use crate::dataflow::operators::{vec::Input, Inspect, Probe};
276
277 use crate::dataflow::operators::{Enter, Leave};
278
279 crate::execute(crate::Config::process(3), |worker| {
281
282 let index = worker.index();
283 let mut input = InputHandle::new();
284 let probe = ProbeHandle::new();
285
286 worker.dataflow(|scope| {
288 let data = scope.input_from(&mut input);
289
290 scope.region(|inner| {
291
292 let data = data.enter(inner);
293 inner.region(|inner2| data.enter(inner2).leave(inner)).leave(scope)
294 })
295 .inspect(move |x| println!("worker {}:\thello {}", index, x))
296 .probe_with(&probe);
297 });
298
299 input.advance_to(0);
301 for round in 0..10 {
302 if index == 0 {
303 input.send(round);
304 }
305 input.advance_to(round + 1);
306 while probe.less_than(input.time()) {
307 worker.step_or_park(None);
308 }
309 }
310 }).unwrap();
311 }
312
313}