1use std::cell::RefCell;
4use std::cmp::Ordering;
5use std::collections::VecDeque;
6use std::rc::Rc;
7
8use timely::ContainerBuilder;
9use timely::dataflow::Stream;
10use timely::progress::Timestamp;
11
12use super::history::load_current;
13use crate::lattice::Lattice;
14use crate::operators::arrange::Arranged;
15use crate::operators::history::ValueHistory;
16use crate::operators::join::{Fresh, JoinTactic, join_with_tactic};
17use crate::trace::{BatchCursor, BatchDiff, BatchVal, Cursor, Navigable, TraceReader};
18use crate::trace::cursor::cursor_list;
19use crate::trace::implementations::containers::BatchContainer;
20
21pub fn join_traces<'scope, Tr1, Tr2, KC, L, CB>(arranged1: Arranged<'scope, Tr1>, arranged2: Arranged<'scope, Tr2>, name: &str, result: L) -> Stream<'scope, Tr1::Time, CB::Container>
35where
36 Tr1: TraceReader<Batch: Navigable>+'static,
37 Tr2: TraceReader<Batch: Navigable, Time = Tr1::Time>+'static,
38 KC: BatchContainer,
39 BatchCursor<Tr1>: Cursor<Time = Tr1::Time, KeyContainer = KC>,
40 for<'a> BatchCursor<Tr1>: Cursor<Key<'a> = KC::ReadItem<'a>>,
41 for<'a> BatchCursor<Tr2>: Cursor<Key<'a> = KC::ReadItem<'a>, Time = Tr1::Time>,
42 L: FnMut(KC::ReadItem<'_>,BatchVal<'_, Tr1>,BatchVal<'_, Tr2>,Tr1::Time,&BatchDiff<Tr1>,&BatchDiff<Tr2>,&mut CB)+'static,
43 CB: ContainerBuilder<Container: Default> + 'static,
44{
45 join_with_tactic(arranged1, arranged2, name, CursorTactic::<Tr1::Batch, Tr2::Batch, _, CB>::new(result))
46}
47
48
49pub struct CursorTactic<B0, B1, L, CB>
61where
62 B0: Navigable,
63 B1: Navigable,
64 B1::Cursor: for<'a> Cursor<Key<'a> = <B0::Cursor as Cursor>::Key<'a>, Time = <B0::Cursor as Cursor>::Time>,
65{
66 logic: Rc<RefCell<L>>,
67 _marker: std::marker::PhantomData<(B0, B1, CB)>,
68}
69
70impl<B0, B1, L, CB> CursorTactic<B0, B1, L, CB>
71where
72 B0: Navigable,
73 B1: Navigable,
74 B1::Cursor: for<'a> Cursor<Key<'a> = <B0::Cursor as Cursor>::Key<'a>, Time = <B0::Cursor as Cursor>::Time>,
75{
76 pub fn new(logic: L) -> Self {
78 CursorTactic { logic: Rc::new(RefCell::new(logic)), _marker: std::marker::PhantomData }
79 }
80}
81
82impl<B0, B1, L, CB> JoinTactic<<B0::Cursor as Cursor>::Time, B0, B1, CB::Container> for CursorTactic<B0, B1, L, CB>
83where
84 B0: Navigable + 'static,
85 B1: Navigable + 'static,
86 B1::Cursor: for<'a> Cursor<Key<'a> = <B0::Cursor as Cursor>::Key<'a>, Time = <B0::Cursor as Cursor>::Time>,
87 CB: ContainerBuilder<Container: Default> + 'static,
88 L: for<'a> FnMut(<B0::Cursor as Cursor>::Key<'a>, <B0::Cursor as Cursor>::Val<'a>, <B1::Cursor as Cursor>::Val<'a>, <B0::Cursor as Cursor>::Time, &<B0::Cursor as Cursor>::Diff, &<B1::Cursor as Cursor>::Diff, &mut CB) + 'static,
89{
90 fn prep(&mut self, input0: Vec<B0>, input1: Vec<B1>, fresh: Fresh, meet: <B0::Cursor as Cursor>::Time) -> Box<dyn Iterator<Item = CB::Container>> {
91 let (cursor1, storage1) = cursor_list(input0);
104 let (cursor2, storage2) = cursor_list(input1);
105 let (advance1, advance2) = match fresh {
106 Fresh::Input0 => (false, true),
107 Fresh::Input1 => (true, false),
108 };
109 Box::new(DeferredIter {
110 cursor1,
111 storage1,
112 cursor2,
113 storage2,
114 meet,
115 advance1,
116 advance2,
117 logic: Rc::clone(&self.logic),
118 builder: CB::default(),
119 ready: VecDeque::new(),
120 done: false,
121 })
122 }
123}
124
125struct DeferredIter<T, C1, C2, L, CB>
134where
135 T: Timestamp+Lattice,
136 C1: Cursor<Time=T>,
137 C2: for<'a> Cursor<Key<'a>=C1::Key<'a>, Time=T>,
138 CB: ContainerBuilder,
139{
140 cursor1: C1,
141 storage1: C1::Storage,
142 cursor2: C2,
143 storage2: C2::Storage,
144 meet: T,
146 advance1: bool,
148 advance2: bool,
149 logic: Rc<RefCell<L>>,
151 builder: CB,
153 ready: VecDeque<CB::Container>,
155 done: bool,
156}
157
158impl<T, C1, C2, L, CB> Iterator for DeferredIter<T, C1, C2, L, CB>
159where
160 T: Timestamp+Lattice,
161 C1: Cursor<Time=T>,
162 C2: for<'a> Cursor<Key<'a>=C1::Key<'a>, Time=T>,
163 CB: ContainerBuilder<Container: Default>,
164 L: for<'a> FnMut(C1::Key<'a>, C1::Val<'a>, C2::Val<'a>, T, &C1::Diff, &C2::Diff, &mut CB),
165{
166 type Item = CB::Container;
167
168 #[inline(never)]
170 fn next(&mut self) -> Option<CB::Container> {
171 if let Some(container) = self.ready.pop_front() { return Some(container); }
173 if self.done { return None; }
174
175 let meet1 = if self.advance1 { Some(&self.meet) } else { None };
179 let meet2 = if self.advance2 { Some(&self.meet) } else { None };
180
181 let storage1 = &self.storage1;
182 let storage2 = &self.storage2;
183 let cursor1 = &mut self.cursor1;
184 let cursor2 = &mut self.cursor2;
185 let builder = &mut self.builder;
186 let ready = &mut self.ready;
187 let mut logic = self.logic.borrow_mut();
188 let logic = &mut *logic;
189
190 let mut thinker = JoinThinker::new();
191 let mut exhausted = false;
192
193 while ready.is_empty() {
194 match (cursor1.get_key(storage1), cursor2.get_key(storage2)) {
195 (Some(key1), Some(key2)) => match key1.cmp(&key2) {
196 Ordering::Less => cursor1.seek_key(storage1, key2),
197 Ordering::Greater => cursor2.seek_key(storage2, key1),
198 Ordering::Equal => {
199
200 load_current(&mut thinker.history1, cursor1, storage1, meet1);
201 load_current(&mut thinker.history2, cursor2, storage2, meet2);
202
203 thinker.think(|v1,v2,t,r1,r2| {
204 logic(key1, v1, v2, t, r1, r2, builder);
205 });
206
207 cursor1.step_key(storage1);
208 cursor2.step_key(storage2);
209
210 thinker.history1.clear();
211 thinker.history2.clear();
212
213 while let Some(container) = builder.extract() {
215 ready.push_back(std::mem::take(container));
217 }
218 }
219 },
220 _ => { exhausted = true; break; }
222 }
223 }
224
225 if exhausted {
226 self.done = true;
227 while let Some(container) = builder.finish() {
229 ready.push_back(std::mem::take(container));
231 }
232 }
233
234 ready.pop_front()
235 }
236}
237
238struct JoinThinker<V1, V2, T, D1, D2> {
239 pub history1: ValueHistory<V1, T, D1>,
240 pub history2: ValueHistory<V2, T, D2>,
241}
242
243impl<V1, V2, T, D1, D2> JoinThinker<V1, V2, T, D1, D2>
244where
245 V1: Copy + Ord,
246 V2: Copy + Ord,
247 T: Ord + Clone + Lattice,
248 D1: Clone + crate::difference::Semigroup,
249 D2: Clone + crate::difference::Semigroup,
250{
251 fn new() -> Self {
252 JoinThinker {
253 history1: ValueHistory::new(),
254 history2: ValueHistory::new(),
255 }
256 }
257
258 fn think<F: FnMut(V1, V2, T, &D1, &D2)>(&mut self, mut results: F) {
259
260 if self.history1.edit_len() < 10 || self.history2.edit_len() < 10 {
262 self.history1.map_edits(|v1, t1, d1| {
263 self.history2.map_edits(|v2, t2, d2| {
264 results(v1, v2, t1.join(t2), d1, d2);
265 })
266 })
267 }
268 else {
269
270 let mut replay1 = self.history1.replay();
271 let mut replay2 = self.history2.replay();
272
273 while !replay1.is_done() && !replay2.is_done() {
280
281 if replay1.time().unwrap().cmp(replay2.time().unwrap()) == ::std::cmp::Ordering::Less {
282 replay2.advance_buffer_by(replay1.meet().unwrap());
283 for &((val2, ref time2), ref diff2) in replay2.buffer().iter() {
284 let (val1, time1, diff1) = replay1.edit().unwrap();
285 results(val1, val2, time1.join(time2), diff1, diff2);
286 }
287 replay1.step();
288 }
289 else {
290 replay1.advance_buffer_by(replay2.meet().unwrap());
291 for &((val1, ref time1), ref diff1) in replay1.buffer().iter() {
292 let (val2, time2, diff2) = replay2.edit().unwrap();
293 results(val1, val2, time1.join(time2), diff1, diff2);
294 }
295 replay2.step();
296 }
297 }
298
299 while !replay1.is_done() {
300 replay2.advance_buffer_by(replay1.meet().unwrap());
301 for &((val2, ref time2), ref diff2) in replay2.buffer().iter() {
302 let (val1, time1, diff1) = replay1.edit().unwrap();
303 results(val1, val2, time1.join(time2), diff1, diff2);
304 }
305 replay1.step();
306 }
307 while !replay2.is_done() {
308 replay1.advance_buffer_by(replay2.meet().unwrap());
309 for &((val1, ref time1), ref diff1) in replay1.buffer().iter() {
310 let (val2, time2, diff2) = replay2.edit().unwrap();
311 results(val1, val2, time1.join(time2), diff1, diff2);
312 }
313 replay2.step();
314 }
315 }
316 }
317}