// Walk through all children and for each one that isn't done, try to retrieve a batch
// When all sources are done, set the termination flag on that batch
RelationalNode[] children = getChildren();
int activeSources = 0;
TupleBatch batch = null;
for(int i=0; i<children.length; i++) {
if(children[i] != null && ! sourceDone[i]) {
activeSources++;
if(batch == null) {
try {
batch = children[i].nextBatch();
// Got a batch
if(batch.getTerminationFlag() == true) {
// Mark source as being done and decrement the activeSources counter
sourceDone[i] = true;
activeSources--;
if (reserved > 0) {
getBufferManager().releaseBuffers(schemaSize);
reserved-=schemaSize;
}
}
} catch(BlockedException e) {
// no problem - try the next one
}
} else {
// We already have a batch, so we know that
// 1) we have a batch to return and
// 2) this isn't the last active source, so we're not returning the last batch
// This is sufficient to break the loop - we won't learn anything new after this
break;
}
}
}
// Determine what to return
TupleBatch outputBatch = null;
if(batch != null) {
// Rebuild the batch to reset the output row
outputBatch = new TupleBatch(outputRow, batch.getTuples());
// This is the last unioned batch if:
// 1) This batch is a termination batch from the child
// 2) No other active sources exist
outputBatch.setTerminationFlag(batch.getTerminationFlag() == true && activeSources == 0);
// Update output row for next batch
outputRow += outputBatch.getRowCount();
} else if(activeSources > 0) {
// Didn't get a batch but there are active sources so we are blocked
throw BlockedException.INSTANCE;
} else {
// No batch and no active sources - return empty termination batch (should never happen but just in case)
outputBatch = new TupleBatch(outputRow, Collections.EMPTY_LIST);
outputBatch.setTerminationFlag(true);
}
return outputBatch;
}