void Foreman::initialize() { if (cpu_id_ >= 0) { // We can pin the foreman thread to a CPU if specified. ThreadUtil::BindToCPU(cpu_id_); } DEBUG_ASSERT(query_dag_ != nullptr); initializeState(); // Collect all the workorders from all the relational operators in the DAG. const dag_node_index dag_size = query_dag_->size(); for (dag_node_index index = 0; index < dag_size; ++index) { if (checkAllBlockingDependenciesMet(index)) { query_dag_->getNodePayloadMutable(index)->informAllBlockingDependenciesMet(); processOperator(index, false); } } // Dispatch the WorkOrders generated so far. dispatchWorkerMessages(0, 0); }
// TODO(harshad) - There is duplication in terms of functionality provided by // TMB and ForemanMessage class with respect to determining the message types. // Try to use TMB message types for infering the messsage types consistently. bool Foreman::processMessage(const ForemanMessage &message) { const dag_node_index dag_size = query_dag_->size(); // Get the relational operator that caused this message to be sent. dag_node_index response_op_index = message.getRelationalOpIndex(); const int worker_id = message.getWorkerID(); switch (message.getType()) { case ForemanMessage::kWorkOrderCompletion: { // Completion of a regular WorkOrder. DEBUG_ASSERT(worker_id >= 0); --queued_workorders_per_op_[response_op_index]; // As the given worker finished executing a WorkOrder, decrement its // number of queued WorkOrders. workers_->decrementNumQueuedWorkOrders(worker_id); // Check if new work orders are available and fetch them if so. fetchNormalWorkOrders( query_dag_->getNodePayloadMutable(response_op_index), response_op_index); if (checkRebuildRequired(response_op_index)) { if (checkNormalExecutionOver(response_op_index)) { if (!checkRebuildInitiated(response_op_index)) { if (initiateRebuild(response_op_index)) { // Rebuild initiated and completed right away. markOperatorFinished(response_op_index); } else { // Rebuild under progress. } } else if (checkRebuildOver(response_op_index)) { // Rebuild was under progress and now it is over. markOperatorFinished(response_op_index); } } else { // Normal execution under progress for this operator. } } else if (checkOperatorExecutionOver(response_op_index)) { // Rebuild not required for this operator and its normal execution is // complete. markOperatorFinished(response_op_index); } for (pair<dag_node_index, bool> dependent_link : query_dag_->getDependents(response_op_index)) { RelationalOperator *dependent_op = query_dag_->getNodePayloadMutable(dependent_link.first); if (checkAllBlockingDependenciesMet(dependent_link.first)) { // Process the dependent operator (of the operator whose WorkOrder // was just executed) for which all the dependencies have been met. processOperator(dependent_op, dependent_link.first, true); } } } break; case ForemanMessage::kRebuildCompletion: { DEBUG_ASSERT(worker_id >= 0); // Completion of a rebuild WorkOrder. --rebuild_status_[response_op_index].second; workers_->decrementNumQueuedWorkOrders(worker_id); if (checkRebuildOver(response_op_index)) { markOperatorFinished(response_op_index); for (pair<dag_node_index, bool> dependent_link : query_dag_->getDependents(response_op_index)) { RelationalOperator *dependent_op = query_dag_->getNodePayloadMutable(dependent_link.first); if (checkAllBlockingDependenciesMet(dependent_link.first)) { processOperator(dependent_op, dependent_link.first, true); } } } } break; case ForemanMessage::kDataPipeline: { // Data streaming message. Possible senders of this message include // InsertDestination and some operators which modify existing blocks. for (dag_node_index consumer_index : output_consumers_[response_op_index]) { RelationalOperator *consumer_op = query_dag_->getNodePayloadMutable(consumer_index); // Feed the streamed block to the consumer. Note that // output_consumers_ only contain those dependents of operator with // index = response_op_index which are eligible to receive streamed // input. consumer_op->feedInputBlock(message.getOutputBlockID(), message.getRelationID()); // Because of the streamed input just fed, check if there are any new // WorkOrders available and if so, fetch them. fetchNormalWorkOrders(consumer_op, consumer_index); } // end for (feeding input to dependents) } break; case ForemanMessage::kWorkOrdersAvailable: { // Check if new work orders are available. fetchNormalWorkOrders( query_dag_->getNodePayloadMutable(response_op_index), response_op_index); break; } default: FATAL_ERROR("Unknown ForemanMessage type"); } // Dispatch the WorkerMessages to the workers. We prefer to start the search // for the schedulable WorkOrders beginning from response_op_index. The first // candidate worker to receive the next WorkOrder is the one that sent the // response message to Foreman. dispatchWorkerMessages(((worker_id >= 0) ? worker_id : 0), response_op_index); return num_operators_finished_ == dag_size; }