package com.bigdata.relation.rule.eval.pipeline;
import java.util.concurrent.Future;
import org.apache.log4j.Logger;
import com.bigdata.bop.IBindingSet;
import com.bigdata.mdi.PartitionLocator;
import com.bigdata.relation.accesspath.BlockingBuffer;
import com.bigdata.relation.accesspath.UnsynchronizedArrayBuffer;
import com.bigdata.relation.rule.eval.IJoinNexus;
import com.bigdata.service.IBigdataFederation;
/**
* An object used by a {@link JoinTask} to write on another {@link JoinTask}
* providing a sink for a specific index partition.
*
* @author <a href="mailto:thompsonbry@users.sourceforge.net">Bryan Thompson</a>
* @version $Id$
*/
public class JoinTaskSink {
protected static final Logger log = Logger.getLogger(JoinTaskSink.class);
/**
* True iff the {@link #log} level is INFO or less.
*/
protected static final boolean INFO = log.isInfoEnabled();
/**
* True iff the {@link #log} level is DEBUG or less.
*/
protected static final boolean DEBUG = log.isDebugEnabled();
/**
* The future may be used to cancel or interrupt the downstream
* {@link JoinTask}.
*/
private Future future;
/**
* The {@link Future} of the downstream {@link JoinTask}. This may be
* used to cancel or interrupt that {@link JoinTask}.
*/
public Future getFuture() {
if (future == null)
throw new IllegalStateException();
return future;
}
protected void setFuture(final Future f) {
if (future != null)
throw new IllegalStateException();
this.future = f;
if(DEBUG)
log.debug("sinkOrderIndex=" + sinkOrderIndex
+ ", sinkPartitionId=" + locator.getPartitionId());
}
/**
* The orderIndex for the sink {@link JoinTask}.
*/
final int sinkOrderIndex;
/**
* The index partition that is served by the sink.
*/
final PartitionLocator locator;
/**
* The individual {@link IBindingSet}s are written onto this
* unsynchronized buffer. The buffer gathers those {@link IBindingSet}s
* into chunks and writes those chunks onto the {@link #blockingBuffer}.
*/
final UnsynchronizedArrayBuffer<IBindingSet> unsyncBuffer;
/**
* This buffer provides {@link IBindingSet} chunks to the downstream
* {@link JoinTask}. That join task reads those chunks from a proxy for
* the {@link BlockingBuffer#iterator()}.
*/
final BlockingBuffer<IBindingSet[]> blockingBuffer;
public String toString() {
return "JoinSinkTask{ sinkOrderIndex=" + sinkOrderIndex
+ ", sinkPartitionId=" + locator.getPartitionId() + "}";
}
/**
* Setups up the local buffers for a downstream {@link JoinTask}.
* <p>
* Note: The caller MUST create the task using a factory pattern on the
* target data service and assign its future to the returned object
* using {@link #setFuture(Future)}.
*
* @param fed
* The federation.
* @param locator
* The locator for the index partition.
* @param sourceJoinTask
* The current join dimension.
*/
public JoinTaskSink(final IBigdataFederation fed,
final PartitionLocator locator, final JoinTask sourceJoinTask) {
if (fed == null)
throw new IllegalArgumentException();
if (locator == null)
throw new IllegalArgumentException();
if (sourceJoinTask == null)
throw new IllegalArgumentException();
this.locator = locator;
final IJoinNexus joinNexus = sourceJoinTask.joinNexus;
this.sinkOrderIndex = sourceJoinTask.orderIndex + 1;
/*
* The sink JoinTask will read from the asynchronous iterator
* drawing on the [blockingBuffer]. When we first create the sink
* JoinTask, the [blockingBuffer] will be empty, but the JoinTask
* will simply wait until there is something to be read from the
* asynchronous iterator.
*/
this.blockingBuffer = new BlockingBuffer<IBindingSet[]>(joinNexus
.getChunkOfChunksCapacity());
/*
* The JoinTask adds bindingSets to this buffer. On overflow, the
* binding sets are added as a chunk to the [blockingBuffer]. Once
* on the [blockingBuffer] they are available to be read by the sink
* JoinTask.
*/
this.unsyncBuffer = new UnsynchronizedArrayBuffer<IBindingSet>(
blockingBuffer, IBindingSet.class, joinNexus.getChunkCapacity());
/*
* Note: The caller MUST create the task using a factory pattern on
* the target data service and assign its future.
*/
this.future = null;
}
}