newFlow.notify();
}
}
break;
case CancelFlow:
FlowId cancelId = (FlowId) nextOp.getDatum();
cancelFlow(cancelId);
break;
case CancelAll:
cancelAllFlows();
break;
case ShutdownThread:
isFinished = true;
break;
case WatchFlow:
WatchRequest watchReq = (WatchRequest) nextOp.getDatum();
watch(watchReq);
break;
case UnwatchFlow:
WatchRequest unwatchReq = (WatchRequest) nextOp.getDatum();
watch(unwatchReq); // the request has the isWatch flag set false.
break;
case GetWatchList:
Pair<SessionId, List<FlowId>> getReq =
(Pair<SessionId, List<FlowId>>) nextOp.getDatum();
getWatchList(getReq.getLeft(), getReq.getRight());
break;
case SetFlowName:
Pair<FlowId, String> flowNameData =
(Pair<FlowId, String>) nextOp.getDatum();
setFlowName(flowNameData.getLeft(), flowNameData.getRight());
case Noop:
// Don't do any control operation; skip ahead to event processing.
break;
case ElementComplete:
// Remove a specific FlowElement from service; it's done.
LocalCompletionEvent completionEvent = (LocalCompletionEvent) nextOp.getDatum();
try {
LocalContext context = completionEvent.getContext();
List<SelectableQueue<Object>> downstreamQueues =
context.getDownstreamQueues();
List<FlowElement> downstreamElements = context.getDownstream();
if (null == downstreamElements || downstreamElements.size() == 0) {
// We have received close() notification from the last element in a flow.
// Remove the entire flow from service.
// TODO(aaron): Are multiple SinkFlowElemContexts possible per flow?
// If so, we need to wait for the last of these...
SinkFlowElemContext sinkContext = (SinkFlowElemContext) context;
FlowId id = sinkContext.getFlowId();
LOG.info("Processing complete for flow: " + id);
if (isActive(id)) {
// If the flow is closing naturally, cancel it. If it's
// already canceled (inactive), don't do this twice.
cancelFlow(id);
}
} else if (null == downstreamQueues || downstreamQueues.size() == 0) {
// Has elements, but no queues. Notify the downstream
// FlowElement(s) to close too.
for (FlowElement downstream : downstreamElements) {
downstream.closeUpstream();
}
} else {
// May have downstream queues. For each downstream element, close it
// immediately if it has no queue, or an empty queue. Otherwise,
// watch these queues for emptiness.
assert downstreamQueues.size() == downstreamElements.size();
for (int i = 0; i < downstreamElements.size(); i++) {
SelectableQueue<Object> downstreamQueue = downstreamQueues.get(i);
FlowElement downstreamElement = downstreamElements.get(i);
if (downstreamQueue == null) {
// Close directly.
downstreamElement.closeUpstream();
} else if (downstreamQueue.size() == 0) {
// Queue's dry, close it down.
closeQueue(downstreamQueue, downstreamElement);
} else {
// Watch this queue for completion.
mCloseQueues.add(downstreamQueue);
}
}
}
} catch (IOException ioe) {
LOG.error("IOException closing flow element: " + ioe);
} catch (InterruptedException ie) {
LOG.error("Interruption closing downstream element: " + ie);
}
break;
case Join:
FlowJoinRequest joinReq = (FlowJoinRequest) nextOp.getDatum();
FlowId id = joinReq.getFlowId();
Ref<Boolean> waitObj = joinReq.getJoinObj();
ActiveFlowData flowData = mActiveFlows.get(id);
if (null == flowData) {
// This flow id is already canceled. Return immediately.
synchronized (waitObj) {