package com.bigdata.bop.bset;
import java.util.Map;
import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask;
import com.bigdata.bop.BOp;
import com.bigdata.bop.BOpContext;
import com.bigdata.bop.BOpEvaluationContext;
import com.bigdata.bop.IBindingSet;
import com.bigdata.bop.PipelineOp;
import com.bigdata.bop.solutions.SliceOp;
import com.bigdata.relation.accesspath.IBlockingBuffer;
import cutthecrap.utils.striterators.ICloseableIterator;
/**
* A operator which may be used at the end of query pipelines when there is a
* requirement to marshal solutions back to the query controller but no
* requirement to {@link SliceOp slice} solutions. The primary use case for
* {@link EndOp} is on a cluster, where it is evaluated on the query controller
* so the results will be streamed back to the query controller from the nodes
* of the cluster. You MUST specify {@link BOp.Annotations#EVALUATION_CONTEXT}
* as {@link BOpEvaluationContext#CONTROLLER} when it is to be used for this
* purpose.
*
* @see https://sourceforge.net/apps/trac/bigdata/ticket/227
*/
public class EndOp extends PipelineOp {
/**
*
*/
private static final long serialVersionUID = 1L;
public EndOp(EndOp op) {
super(op);
}
public EndOp(BOp[] args, Map<String, Object> annotations) {
super(args, annotations);
switch (getEvaluationContext()) {
case CONTROLLER:
break;
default:
throw new UnsupportedOperationException(
Annotations.EVALUATION_CONTEXT + "="
+ getEvaluationContext());
}
}
public FutureTask<Void> eval(final BOpContext<IBindingSet> context) {
return new FutureTask<Void>(new OpTask(/*this, */context));
}
/**
* Copy the source to the sink or the alternative sink depending on the
* condition.
*/
static private class OpTask implements Callable<Void> {
// private final PipelineOp op;
private final BOpContext<IBindingSet> context;
OpTask(final BOpContext<IBindingSet> context) {
this.context = context;
}
public Void call() throws Exception {
final ICloseableIterator<IBindingSet[]> source = context
.getSource();
final IBlockingBuffer<IBindingSet[]> sink = context.getSink();
try {
boolean didRun = false;
while (source.hasNext()) {
final IBindingSet[] chunk = source.next();
sink.add(chunk);
didRun = true;
}
if (didRun)
sink.flush();
return null;
} finally {
sink.close();
}
}
}
}