use std::rc::Rc;
use std::default::Default;
use timely::dataflow::operators::{Enter, Map};
use timely::order::{PartialOrder, TotalOrder};
use timely::dataflow::{Scope, Stream};
use timely::dataflow::operators::generic::Operator;
use timely::dataflow::channels::pact::{ParallelizationContract, Pipeline, Exchange};
use timely::progress::Timestamp;
use timely::progress::frontier::Antichain;
use timely::dataflow::operators::Capability;
use timely_sort::Unsigned;
use ::{Data, ExchangeData, Collection, AsCollection, Hashable};
use ::difference::Monoid;
use lattice::Lattice;
use trace::{Trace, TraceReader, Batch, BatchReader, Batcher, Cursor};
use trace::implementations::ord::OrdValSpine as DefaultValTrace;
use trace::implementations::ord::OrdKeySpine as DefaultKeyTrace;
use trace::wrappers::enter::{TraceEnter, BatchEnter};
use trace::wrappers::enter_at::TraceEnter as TraceEnterAt;
use trace::wrappers::enter_at::BatchEnter as BatchEnterAt;
use trace::wrappers::filter::{TraceFilter, BatchFilter};
use super::TraceAgent;
pub struct Arranged<G: Scope, Tr>
where
G::Timestamp: Lattice+Ord,
Tr: TraceReader+Clone,
{
pub stream: Stream<G, Tr::Batch>,
pub trace: Tr,
}
impl<G: Scope, Tr> Clone for Arranged<G, Tr>
where
G::Timestamp: Lattice+Ord,
Tr: TraceReader<Time=G::Timestamp> + Clone,
Tr::Batch: BatchReader<Tr::Key, Tr::Val, G::Timestamp, Tr::R>,
Tr::Cursor: Cursor<Tr::Key, Tr::Val, G::Timestamp, Tr::R>,
{
fn clone(&self) -> Self {
Arranged {
stream: self.stream.clone(),
trace: self.trace.clone(),
}
}
}
use ::timely::dataflow::scopes::Child;
use ::timely::progress::timestamp::Refines;
impl<G: Scope, Tr> Arranged<G, Tr>
where
G::Timestamp: Lattice+Ord,
Tr: TraceReader<Time=G::Timestamp> + Clone,
Tr::Batch: BatchReader<Tr::Key, Tr::Val, G::Timestamp, Tr::R>,
Tr::Cursor: Cursor<Tr::Key, Tr::Val, G::Timestamp, Tr::R>,
{
pub fn enter<'a, TInner>(&self, child: &Child<'a, G, TInner>)
-> Arranged<Child<'a, G, TInner>, TraceEnter<Tr, TInner>>
where
Tr::Key: 'static,
Tr::Val: 'static,
Tr::R: 'static,
G::Timestamp: Clone+Default+'static,
TInner: Refines<G::Timestamp>+Lattice+Timestamp+Clone+Default+'static,
{
Arranged {
stream: self.stream.enter(child).map(|bw| BatchEnter::make_from(bw)),
trace: TraceEnter::make_from(self.trace.clone()),
}
}
pub fn enter_region<'a>(&self, child: &Child<'a, G, G::Timestamp>)
-> Arranged<Child<'a, G, G::Timestamp>, Tr>
where
Tr::Key: 'static,
Tr::Val: 'static,
Tr::R: 'static,
G::Timestamp: Clone+Default+'static,
{
Arranged {
stream: self.stream.enter(child),
trace: self.trace.clone(),
}
}
pub fn enter_at<'a, TInner, F>(&self, child: &Child<'a, G, TInner>, logic: F)
-> Arranged<Child<'a, G, TInner>, TraceEnterAt<Tr, TInner, F>>
where
Tr::Key: 'static,
Tr::Val: 'static,
Tr::R: 'static,
G::Timestamp: Clone+Default+'static,
TInner: Refines<G::Timestamp>+Lattice+Timestamp+Clone+Default+'static,
F: Fn(&Tr::Key, &Tr::Val, &G::Timestamp)->TInner+'static,
{
let logic = Rc::new(logic);
Arranged {
trace: TraceEnterAt::make_from(self.trace.clone(), logic.clone()),
stream: self.stream.enter(child).map(move |bw| BatchEnterAt::make_from(bw, logic.clone())),
}
}
pub fn filter<F>(&self, logic: F)
-> Arranged<G, TraceFilter<Tr, F>>
where
Tr::Key: 'static,
Tr::Val: 'static,
Tr::R: 'static,
G::Timestamp: Clone+Default+'static,
F: Fn(&Tr::Key, &Tr::Val)->bool+'static,
{
let logic = Rc::new(logic);
Arranged {
trace: TraceFilter::make_from(self.trace.clone(), logic.clone()),
stream: self.stream.map(move |bw| BatchFilter::make_from(bw, logic.clone())),
}
}
pub fn as_collection<D: Data, L>(&self, logic: L) -> Collection<G, D, Tr::R>
where
Tr::R: Monoid,
L: Fn(&Tr::Key, &Tr::Val) -> D+'static,
{
self.flat_map_ref(move |key, val| Some(logic(key,val)))
}
pub fn flat_map_ref<I, L>(&self, logic: L) -> Collection<G, I::Item, Tr::R>
where
Tr::R: Monoid,
I: IntoIterator,
I::Item: Data,
L: Fn(&Tr::Key, &Tr::Val) -> I+'static,
{
self.stream.unary(Pipeline, "AsCollection", move |_,_| move |input, output| {
input.for_each(|time, data| {
let mut session = output.session(&time);
for wrapper in data.iter() {
let batch = &wrapper;
let mut cursor = batch.cursor();
while let Some(key) = cursor.get_key(batch) {
while let Some(val) = cursor.get_val(batch) {
for datum in logic(key, val) {
cursor.map_times(batch, |time, diff| {
session.give((datum.clone(), time.clone(), diff.clone()));
});
}
cursor.step_val(batch);
}
cursor.step_key(batch);
}
}
});
})
.as_collection()
}
pub fn lookup(&self, queries: &Stream<G, (Tr::Key, G::Timestamp)>) -> Stream<G, (Tr::Key, Tr::Val, G::Timestamp, Tr::R)>
where
G::Timestamp: Data+Lattice+Ord+TotalOrder,
Tr::Key: ExchangeData+Hashable,
Tr::Val: ExchangeData,
Tr::R: ExchangeData+Monoid,
Tr: 'static,
{
let exchange = Exchange::new(move |update: &(Tr::Key,G::Timestamp)| update.0.hashed().as_u64());
queries.binary_frontier(&self.stream, exchange, Pipeline, "TraceQuery", move |_capability, _info| {
let mut trace = Some(self.trace.clone());
trace.as_mut().unwrap().distinguish_since(&[]);
let mut stash = Vec::new();
let mut capability: Option<Capability<G::Timestamp>> = None;
let mut active = Vec::new();
let mut retain = Vec::new();
let mut working: Vec<(G::Timestamp, Tr::Val, Tr::R)> = Vec::new();
let mut working2: Vec<(Tr::Val, Tr::R)> = Vec::new();
move |input1, input2, output| {
input1.for_each(|time, data| {
if capability.is_none() || time.time().less_than(capability.as_ref().unwrap().time()) {
capability = Some(time.retain());
}
stash.extend(data.iter().cloned());
});
input2.for_each(|_time, _data| { });
assert_eq!(capability.is_none(), stash.is_empty());
let mut drained = false;
if let Some(capability) = capability.as_mut() {
if !input2.frontier().less_equal(capability.time()) {
for datum in stash.drain(..) {
if !input2.frontier().less_equal(&datum.1) {
active.push(datum);
}
else {
retain.push(datum);
}
}
drained = !active.is_empty();
::std::mem::swap(&mut stash, &mut retain);
active.sort_unstable_by(|x,y| x.0.cmp(&y.0));
let (mut cursor, storage) = trace.as_mut().unwrap().cursor();
let mut session = output.session(&capability);
let mut active_finger = 0;
while active_finger < active.len() {
let key = &active[active_finger].0;
let mut same_key = active_finger;
while active.get(same_key).map(|x| &x.0) == Some(key) {
same_key += 1;
}
cursor.seek_key(&storage, key);
if cursor.get_key(&storage) == Some(key) {
let mut active = &active[active_finger .. same_key];
while let Some(val) = cursor.get_val(&storage) {
cursor.map_times(&storage, |t,d| working.push((t.clone(), val.clone(), d.clone())));
cursor.step_val(&storage);
}
working.sort_by(|x,y| x.0.cmp(&y.0));
for (time, val, diff) in working.drain(..) {
if !active.is_empty() && active[0].1.less_than(&time) {
::trace::consolidate(&mut working2, 0);
while !active.is_empty() && active[0].1.less_than(&time) {
for &(ref val, ref count) in working2.iter() {
session.give((key.clone(), val.clone(), active[0].1.clone(), count.clone()));
}
active = &active[1..];
}
}
working2.push((val, diff));
}
if !active.is_empty() {
::trace::consolidate(&mut working2, 0);
while !active.is_empty() {
for &(ref val, ref count) in working2.iter() {
session.give((key.clone(), val.clone(), active[0].1.clone(), count.clone()));
}
active = &active[1..];
}
}
}
active_finger = same_key;
}
active.clear();
}
}
if drained {
if stash.is_empty() { capability = None; }
if let Some(capability) = capability.as_mut() {
let mut min_time = stash[0].1.clone();
for datum in stash[1..].iter() {
if datum.1.less_than(&min_time) {
min_time = datum.1.clone();
}
}
capability.downgrade(&min_time);
}
}
let frontier = [
capability.as_ref().map(|c| c.time().clone()),
input1.frontier().frontier().get(0).cloned(),
].into_iter().cloned().filter_map(|t| t).min();
if let Some(frontier) = frontier {
trace.as_mut().map(|t| t.advance_by(&[frontier]));
}
else {
trace = None;
}
}
})
}
}
impl<'a, G: Scope, Tr> Arranged<Child<'a, G, G::Timestamp>, Tr>
where
G::Timestamp: Lattice+Ord,
Tr: TraceReader<Time=G::Timestamp> + Clone,
Tr::Batch: BatchReader<Tr::Key, Tr::Val, G::Timestamp, Tr::R>,
Tr::Cursor: Cursor<Tr::Key, Tr::Val, G::Timestamp, Tr::R>,
{
pub fn leave_region(&self) -> Arranged<G, Tr> {
use timely::dataflow::operators::Leave;
Arranged {
stream: self.stream.leave(),
trace: self.trace.clone(),
}
}
}
pub trait Arrange<G: Scope, K, V, R: Monoid>
where
G::Timestamp: Lattice,
K: Data,
V: Data,
{
fn arrange<Tr>(&self) -> Arranged<G, TraceAgent<Tr>>
where
K: ExchangeData+Hashable,
V: ExchangeData,
R: ExchangeData,
Tr: Trace+TraceReader<Key=K,Val=V,Time=G::Timestamp,R=R>+'static,
Tr::Batch: Batch<K, V, G::Timestamp, R>,
Tr::Cursor: Cursor<K, V, G::Timestamp, R>,
{
self.arrange_named("Arrange")
}
fn arrange_named<Tr>(&self, name: &str) -> Arranged<G, TraceAgent<Tr>>
where
K: ExchangeData+Hashable,
V: ExchangeData,
R: ExchangeData,
Tr: Trace+TraceReader<Key=K,Val=V,Time=G::Timestamp,R=R>+'static,
Tr::Batch: Batch<K, V, G::Timestamp, R>,
Tr::Cursor: Cursor<K, V, G::Timestamp, R>,
{
let exchange = Exchange::new(move |update: &((K,V),G::Timestamp,R)| (update.0).0.hashed().as_u64());
self.arrange_core(exchange, name)
}
fn arrange_core<P, Tr>(&self, pact: P, name: &str) -> Arranged<G, TraceAgent<Tr>>
where
P: ParallelizationContract<G::Timestamp, ((K,V),G::Timestamp,R)>,
Tr: Trace+TraceReader<Key=K,Val=V,Time=G::Timestamp,R=R>+'static,
Tr::Batch: Batch<K, V, G::Timestamp, R>,
Tr::Cursor: Cursor<K, V, G::Timestamp, R>,
;
}
impl<G, K, V, R> Arrange<G, K, V, R> for Collection<G, (K, V), R>
where
G: Scope,
G::Timestamp: Lattice+Ord,
K: ExchangeData+Hashable,
V: ExchangeData,
R: Monoid+ExchangeData,
{
fn arrange_core<P, Tr>(&self, pact: P, name: &str) -> Arranged<G, TraceAgent<Tr>>
where
P: ParallelizationContract<G::Timestamp, ((K,V),G::Timestamp,R)>,
Tr: Trace+TraceReader<Key=K,Val=V,Time=G::Timestamp,R=R>+'static,
Tr::Batch: Batch<K, V, G::Timestamp, R>,
Tr::Cursor: Cursor<K, V, G::Timestamp, R>,
{
let mut reader: Option<TraceAgent<Tr>> = None;
let stream = {
let reader = &mut reader;
self.inner.unary_frontier(pact, name, move |_capability, _info| {
let logger = {
let scope = self.scope();
let register = scope.log_register();
register.get::<::logging::DifferentialEvent>("differential/arrange")
};
let mut batcher = <Tr::Batch as Batch<K,V,G::Timestamp,R>>::Batcher::new();
let mut capabilities = Antichain::<Capability<G::Timestamp>>::new();
let mut buffer = Vec::new();
let empty_trace = Tr::new(_info, logger);
let (reader_local, mut writer) = TraceAgent::new(empty_trace);
*reader = Some(reader_local);
let mut input_frontier = vec![Default::default()];
move |input, output| {
input.for_each(|cap, data| {
capabilities.insert(cap.retain());
data.swap(&mut buffer);
batcher.push_batch(&mut buffer);
});
assert!(input.frontier().frontier().iter().all(|t1| input_frontier.iter().any(|t2: &G::Timestamp| t2.less_equal(t1))));
let progress = input_frontier.iter().any(|t2| !input.frontier().less_equal(t2));
if progress {
if capabilities.elements().iter().any(|c| !input.frontier().less_equal(c.time())) {
let mut upper = Antichain::new();
for (index, capability) in capabilities.elements().iter().enumerate() {
if !input.frontier().less_equal(capability.time()) {
upper.clear();
for time in input.frontier().frontier().iter() {
upper.insert(time.clone());
}
for other_capability in &capabilities.elements()[(index + 1) .. ] {
upper.insert(other_capability.time().clone());
}
let batch = batcher.seal(upper.elements());
writer.insert(batch.clone(), Some(capability.time().clone()));
output.session(&capabilities.elements()[index]).give(batch);
}
}
let mut new_capabilities = Antichain::new();
for time in batcher.frontier() {
if let Some(capability) = capabilities.elements().iter().find(|c| c.time().less_equal(time)) {
new_capabilities.insert(capability.delayed(time));
}
else {
panic!("failed to find capability");
}
}
capabilities = new_capabilities;
}
else {
let _batch = batcher.seal(&input.frontier().frontier()[..]);
writer.seal(&input.frontier().frontier());
}
input_frontier.clear();
input_frontier.extend(input.frontier().frontier().iter().cloned());
}
}
})
};
Arranged { stream: stream, trace: reader.unwrap() }
}
}
impl<G: Scope, K: ExchangeData+Hashable, R: ExchangeData+Monoid> Arrange<G, K, (), R> for Collection<G, K, R>
where
G::Timestamp: Lattice+Ord,
{
fn arrange_core<P, Tr>(&self, pact: P, name: &str) -> Arranged<G, TraceAgent<Tr>>
where
P: ParallelizationContract<G::Timestamp, ((K,()),G::Timestamp,R)>,
Tr: Trace+TraceReader<Key=K, Val=(), Time=G::Timestamp, R=R>+'static,
Tr::Batch: Batch<K, (), G::Timestamp, R>,
Tr::Cursor: Cursor<K, (), G::Timestamp, R>,
{
self.map(|k| (k, ()))
.arrange_core(pact, name)
}
}
pub trait ArrangeByKey<G: Scope, K: Data+Hashable, V: Data, R: Monoid>
where G::Timestamp: Lattice+Ord {
fn arrange_by_key(&self) -> Arranged<G, TraceAgent<DefaultValTrace<K, V, G::Timestamp, R>>>;
}
impl<G: Scope, K: ExchangeData+Hashable, V: ExchangeData, R: ExchangeData+Monoid> ArrangeByKey<G, K, V, R> for Collection<G, (K,V), R>
where
G::Timestamp: Lattice+Ord
{
fn arrange_by_key(&self) -> Arranged<G, TraceAgent<DefaultValTrace<K, V, G::Timestamp, R>>> {
self.arrange()
}
}
pub trait ArrangeBySelf<G: Scope, K: Data+Hashable, R: Monoid>
where
G::Timestamp: Lattice+Ord
{
fn arrange_by_self(&self) -> Arranged<G, TraceAgent<DefaultKeyTrace<K, G::Timestamp, R>>>;
}
impl<G: Scope, K: ExchangeData+Hashable, R: ExchangeData+Monoid> ArrangeBySelf<G, K, R> for Collection<G, K, R>
where
G::Timestamp: Lattice+Ord
{
fn arrange_by_self(&self) -> Arranged<G, TraceAgent<DefaultKeyTrace<K, G::Timestamp, R>>> {
self.map(|k| (k, ()))
.arrange()
}
}