package edu.washington.escience.myria.operator; import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableList; import edu.washington.escience.myria.Schema; import edu.washington.escience.myria.column.Column; import edu.washington.escience.myria.column.ConstantValueColumn; import edu.washington.escience.myria.storage.TupleBatch; /** * Given a singleton right child, cross the left child with it in a way that minimizes state and does not construct new * tuples. */ public class CrossWithSingleton extends BinaryOperator { /** Required for Java serialization. */ private static final long serialVersionUID = 1L; /** The singleton tuple from the right child. */ private TupleBatch rightTuple; /** * Instantiate a new operator to cross all tuples in the left child with the singleton tuple from the right child. * * @param left the left child, which may have any number of tuples. * @param right the right child, which may only have one tuple. */ public CrossWithSingleton(final Operator left, final Operator right) { super(left, right); rightTuple = null; } @Override protected TupleBatch fetchNextReady() throws Exception { /* Before we can do anything, get the singleton tuple from the right child, and ensure that it is a singleton. */ Operator right = getRight(); while (!right.eos()) { TupleBatch tb = right.nextReady(); if (tb == null) { /* The right child may have realized it's EOS now. If so, we must move onto left child to avoid livelock. */ if (right.eos()) { break; } return null; } Preconditions.checkState( rightTuple == null, "Expecting a singleton right child, but received a batch with %s additional tuples", tb.numTuples()); Preconditions.checkState( tb.numTuples() == 1, "Expecting a singleton right child, instead received a batch with %s tuples", tb.numTuples()); rightTuple = tb; } /* Verify that the right child did produce a tuple. */ Preconditions.checkState( rightTuple != null, "Expecting a singleton right child, but right child is EOS and no tuples received."); Operator left = getLeft(); Schema schema = getSchema(); while (!left.eos()) { TupleBatch tb = left.nextReady(); if (tb == null) { break; } ImmutableList.Builder<Column<?>> columns = ImmutableList.builder(); for (Column<?> c : tb.getDataColumns()) { columns.add(c); } for (Column<?> c : rightTuple.getDataColumns()) { columns.add(new ConstantValueColumn(c.getObject(0), c.getType(), tb.numTuples())); } return new TupleBatch(schema, columns.build()); } return null; } @Override protected Schema generateSchema() { Operator left = getLeft(); Operator right = getRight(); if (left == null || right == null) { return null; } Schema leftSchema = left.getSchema(); Schema rightSchema = right.getSchema(); if (leftSchema == null || rightSchema == null) { return null; } return Schema.merge(leftSchema, rightSchema); } }