package com.bigdata.relation.rule.eval.pipeline; import java.util.Iterator; import org.apache.log4j.Logger; import com.bigdata.bop.IBindingSet; import com.bigdata.bop.IPredicate; import com.bigdata.mdi.PartitionLocator; import com.bigdata.relation.accesspath.AbstractUnsynchronizedArrayBuffer; import com.bigdata.relation.rule.eval.IJoinNexus; import com.bigdata.service.AbstractScaleOutFederation; import com.bigdata.service.IBigdataFederation; /** * Unsynchronized buffer maps the {@link IBindingSet}s across the index * partition(s) for the target scale-out index when it overflows. * * @author <a href="mailto:thompsonbry@users.sourceforge.net">Bryan Thompson</a> * @version $Id$ * @param <E> * The generic type of the elements in the buffer. */ class UnsyncDistributedOutputBuffer<E extends IBindingSet> extends AbstractUnsynchronizedArrayBuffer<E> { private static final Logger log = Logger .getLogger(UnsyncDistributedOutputBuffer.class); private final DistributedJoinTask joinTask; /** The evaluation order of the next predicate. */ private final int nextOrderIndex; /** The tailIndex of the next predicate to be evaluated. */ final int nextTailIndex; final IBigdataFederation<?> fed; /** * * @param fed * @param joinTask * @param capacity */ public UnsyncDistributedOutputBuffer(final AbstractScaleOutFederation<?> fed, final DistributedJoinTask joinTask, final int capacity) { super(capacity, (Class<? extends E>) IBindingSet.class); if (fed == null) throw new IllegalArgumentException(); if (joinTask == null) throw new IllegalArgumentException(); this.fed = fed; this.joinTask = joinTask; this.nextOrderIndex = joinTask.orderIndex + 1; this.nextTailIndex = joinTask.getTailIndex(nextOrderIndex); } /** * Maps the chunk of {@link IBindingSet}s across the index partition(s) for * the sink join dimension. * * @param a * A chunk of {@link IBindingSet}s. * * FIXME optimize locator lookup. * <p> * Note: We always use a read-consistent view for the join evaluation so we * are permitted to cache the locators just as much as we like. * <p> * When the buffer overflow()s, we generate the asBound() predicates, SORT * them by their [fromKey] (or its predicate level equivalence), and process * the sorted asBound() predicates. Since they are sorted and since they are * all for the same predicate pattern (optionals will leave some variables * unbound - does that cause a problem?) we know that the first partitionId * is GTE to the last partitionId of the last asBound predicate. We can test * the rightSeparatorKey on the PartitionLocator and immediately determine * whether the asBound predicate in fact starts and (and possibly ends) * within the same index partition. We only need to do a locatorScan when * the asBound predicate actually crosses into the next index partition, * which could also be handled by an MDI#find(key). */ protected void handleChunk(final E[] chunk) { if (log.isDebugEnabled()) log.debug("chunkSize=" + chunk.length); int bindingSetsOut = 0; // the next predicate to be evaluated. final IPredicate<?> nextPred = joinTask.rule.getTail(nextTailIndex); final IJoinNexus joinNexus = joinTask.joinNexus; final JoinStats stats = joinTask.stats; final int naccepted = chunk.length; for (int i = 0; i < naccepted; i++) { // an accepted binding set. final IBindingSet bindingSet = chunk[i]; /* * Locator scan for the index partitions for that predicate as * bound. */ final Iterator<PartitionLocator> itr = joinNexus.locatorScan( joinTask.fed, nextPred.asBound(bindingSet)); while (itr.hasNext()) { final PartitionLocator locator = itr.next(); if (log.isTraceEnabled()) log.trace("adding bindingSet to buffer: nextOrderIndex=" + nextOrderIndex + ", partitionId=" + locator.getPartitionId() + ", bindingSet=" + bindingSet); // obtain sink JoinTask from cache or dataService. final JoinTaskSink sink; try { sink = joinTask.getSink(locator); } catch (InterruptedException ex) { throw new RuntimeException(ex); } // add binding set to the sink. if (sink.unsyncBuffer.add2(bindingSet)) { // another chunk out to this sink. stats.bindingSetChunksOut++; } // #of bindingSets out across all sinks for this join task. bindingSetsOut++; } } stats.bindingSetsOut += bindingSetsOut; } }