package edu.washington.escience.myria.operator; import java.util.Objects; import javax.annotation.Nonnull; import com.google.common.base.Preconditions; import com.google.common.primitives.Ints; import edu.washington.escience.myria.DbException; import edu.washington.escience.myria.Schema; import edu.washington.escience.myria.storage.TupleBatch; /** * A poor implementation of a Limit operator, which emits the first N tuples then closes the child operator from further * feeding tuples. * */ public final class Limit extends UnaryOperator { /** Required for Java serialization. */ private static final long serialVersionUID = 1L; /** The limit. */ private final long limit; /** The number of tuples left to emit. */ private long toEmit; /** * A limit operator keeps the first <code>limit</code> tuples produced by its child. * * @param limit the number of tuples to keep. * @param child the source of tuples. */ public Limit(@Nonnull final Long limit, final Operator child) { super(child); this.limit = Objects.requireNonNull(limit, "limit"); Preconditions.checkArgument(limit >= 0L, "limit must be non-negative"); toEmit = this.limit; } @Override protected TupleBatch fetchNextReady() throws DbException { Operator child = getChild(); if (child.isOpen()) { TupleBatch tb = child.nextReady(); TupleBatch result = null; if (tb != null) { if (tb.numTuples() <= toEmit) { toEmit -= tb.numTuples(); result = tb; } else if (toEmit > 0) { result = tb.prefix(Ints.checkedCast(toEmit)); toEmit = 0; } if (toEmit == 0) { /* Close child. No more stream is needed. */ child.close(); } } return result; } return null; } @Override public Schema generateSchema() { Operator child = getChild(); if (child == null) { return null; } return child.getSchema(); } }