package com.zillabyte.motherbrain.flow.aggregation; import java.util.LinkedList; import org.eclipse.jdt.annotation.NonNullByDefault; import org.javatuples.Pair; import com.google.common.collect.LinkedListMultimap; import com.google.common.collect.Lists; import com.zillabyte.motherbrain.flow.App; import com.zillabyte.motherbrain.flow.operations.AggregationOperation; import com.zillabyte.motherbrain.flow.operations.GroupBy; import com.zillabyte.motherbrain.flow.operations.Join; import com.zillabyte.motherbrain.flow.operations.Operation; import com.zillabyte.motherbrain.flow.operations.OperationException; import com.zillabyte.motherbrain.flow.operations.Sink; import com.zillabyte.motherbrain.flow.operations.Source; @NonNullByDefault public final class FlowAggregationSplitter { public static LinkedListMultimap<AggregationOperation, Operation> getAggregationPredecessors(App flow) throws OperationException { // Init final LinkedListMultimap<AggregationOperation, Operation> ret = LinkedListMultimap.create(); /* * Just calls constructor. */ assert (ret != null); // Prime the queue... LinkedList<Pair<AggregationOperation, Operation>> queue = Lists.newLinkedList(); for(Operation o : flow.getOperations()) { if (o != null && o instanceof Sink) { queue.add(new Pair<AggregationOperation, Operation>(null, o)); } } // BFS while(queue.size() > 0) { // Init Pair<AggregationOperation, Operation> p = queue.removeFirst(); AggregationOperation tailAgg = p.getValue0(); Operation thisOp = p.getValue1(); if (thisOp instanceof Join) { Join joiner = (Join) thisOp; queue.add(new Pair<AggregationOperation, Operation>(joiner, joiner.lhsPrevOperation())); queue.add(new Pair<AggregationOperation, Operation>(joiner, joiner.rhsPrevOperation())); queue.add(new Pair<>(tailAgg, joiner.lhsPrevOperation())); queue.add(new Pair<>(tailAgg, joiner.rhsPrevOperation())); ret.put(joiner, joiner.lhsPrevOperation()); ret.put(joiner, joiner.rhsPrevOperation()); } else if (thisOp instanceof GroupBy) { GroupBy grouper = (GroupBy) thisOp; queue.add(new Pair<AggregationOperation, Operation>(grouper, grouper.prevNonLoopOperation())); queue.add(new Pair<>(tailAgg, grouper.prevNonLoopOperation())); ret.put(grouper, grouper.prevNonLoopOperation()); } else if (thisOp instanceof AggregationOperation) { throw (OperationException) new OperationException(thisOp, "unknown agg type").setUserMessage("Unknown aggregation type "+thisOp.type()); } else if (thisOp instanceof Source) { // Source, do nothing.. } else if (tailAgg != null) { // We already have an aggregation for the tail, keep it going.. queue.add(new Pair<>(tailAgg, thisOp.prevNonLoopOperation())); ret.put(tailAgg, thisOp.prevNonLoopOperation()); } else { // No aggregator, so just keep traversing backwards queue.add(new Pair<AggregationOperation, Operation>(null, thisOp.prevNonLoopOperation())); } } // Done return ret; } }