void Dispatcher::batchTasksWalk( Dispatcher::TaskBatchPtr parent, const ExecutableNode::Task &task, BatchMap ¤tBatches, TaskToBatchMap &tasksToBatches, std::set<const TaskBatch *> &ancestors ) { TaskBatchPtr batch = acquireBatch( task, currentBatches, tasksToBatches ); TaskBatches &parentRequirements = parent->requirements(); if ( std::find( parentRequirements.begin(), parentRequirements.end(), batch ) == parentRequirements.end() ) { if ( ancestors.find( batch.get() ) != ancestors.end() ) { throw IECore::Exception( ( boost::format( "Dispatched nodes cannot have cyclic dependencies. %s and %s are involved in a cycle." ) % batch->node()->relativeName( batch->node()->scriptNode() ) % parent->node()->relativeName( parent->node()->scriptNode() ) ).str() ); } parentRequirements.push_back( batch ); } ExecutableNode::Tasks taskRequirements; task.node()->requirements( task.context(), taskRequirements ); ancestors.insert( parent.get() ); for ( ExecutableNode::Tasks::const_iterator it = taskRequirements.begin(); it != taskRequirements.end(); ++it ) { batchTasksWalk( batch, *it, currentBatches, tasksToBatches, ancestors ); } ancestors.erase( parent.get() ); }
Dispatcher::TaskBatchPtr Dispatcher::batchTasks( const ExecutableNode::Tasks &tasks ) { TaskBatchPtr root = new TaskBatch; BatchMap currentBatches; TaskToBatchMap tasksToBatches; for ( ExecutableNode::Tasks::const_iterator it = tasks.begin(); it != tasks.end(); ++it ) { batchTasksWalk( root, *it, currentBatches, tasksToBatches ); } return root; }
void Dispatcher::batchTasksWalk( Dispatcher::TaskBatchPtr parent, const ExecutableNode::Task &task, BatchMap ¤tBatches, TaskToBatchMap &tasksToBatches ) { TaskBatchPtr batch = acquireBatch( task, currentBatches, tasksToBatches ); TaskBatches &parentRequirements = parent->requirements(); if ( ( batch != parent ) && std::find( parentRequirements.begin(), parentRequirements.end(), batch ) == parentRequirements.end() ) { parentRequirements.push_back( batch ); } ExecutableNode::Tasks taskRequirements; task.node()->requirements( task.context(), taskRequirements ); for ( ExecutableNode::Tasks::const_iterator it = taskRequirements.begin(); it != taskRequirements.end(); ++it ) { batchTasksWalk( batch, *it, currentBatches, tasksToBatches ); } }
void Dispatcher::dispatch( const std::vector<NodePtr> &nodes ) const { // clear job directory, so that if our node validation fails, // jobDirectory() won't return the result from the previous dispatch. m_jobDirectory = ""; // validate the nodes we've been given if ( nodes.empty() ) { throw IECore::Exception( getName().string() + ": Must specify at least one node to dispatch." ); } std::vector<ExecutableNodePtr> executables; const ScriptNode *script = (*nodes.begin())->scriptNode(); for ( std::vector<NodePtr>::const_iterator nIt = nodes.begin(); nIt != nodes.end(); ++nIt ) { const ScriptNode *currentScript = (*nIt)->scriptNode(); if ( !currentScript || currentScript != script ) { throw IECore::Exception( getName().string() + ": Dispatched nodes must all belong to the same ScriptNode." ); } if ( ExecutableNode *executable = runTimeCast<ExecutableNode>( nIt->get() ) ) { executables.push_back( executable ); } else if ( const Box *box = runTimeCast<const Box>( nIt->get() ) ) { for ( RecursiveOutputPlugIterator plugIt( box ); plugIt != plugIt.end(); ++plugIt ) { Node *sourceNode = plugIt->get()->source<Plug>()->node(); if ( ExecutableNode *executable = runTimeCast<ExecutableNode>( sourceNode ) ) { executables.push_back( executable ); } } } else { throw IECore::Exception( getName().string() + ": Dispatched nodes must be ExecutableNodes or Boxes containing ExecutableNodes." ); } } // create the job directory now, so it's available in preDispatchSignal(). const Context *context = Context::current(); m_jobDirectory = createJobDirectory( context ); // this object calls this->preDispatchSignal() in its constructor and this->postDispatchSignal() // in its destructor, thereby guaranteeing that we always call this->postDispatchSignal(). DispatcherSignalGuard signalGuard( this, executables ); if ( signalGuard.cancelledByPreDispatch() ) { return; } std::vector<FrameList::Frame> frames; FrameListPtr frameList = frameRange( script, context ); frameList->asList( frames ); size_t i = 0; ExecutableNode::Tasks tasks; tasks.reserve( executables.size() * frames.size() ); for ( std::vector<FrameList::Frame>::const_iterator fIt = frames.begin(); fIt != frames.end(); ++fIt ) { for ( std::vector<ExecutableNodePtr>::const_iterator nIt = executables.begin(); nIt != executables.end(); ++nIt, ++i ) { ContextPtr frameContext = new Context( *context, Context::Borrowed ); frameContext->setFrame( *fIt ); tasks.push_back( ExecutableNode::Task( *nIt, frameContext ) ); } } TaskBatchPtr rootBatch = batchTasks( tasks ); if ( !rootBatch->requirements().empty() ) { doDispatch( rootBatch.get() ); } // inform the guard that the process has been completed, so it can pass this info to // postDispatchSignal(): signalGuard.success(); }
void Dispatcher::dispatch( const std::vector<NodePtr> &nodes ) const { if ( nodes.empty() ) { throw IECore::Exception( getName().string() + ": Must specify at least one node to dispatch." ); } std::vector<ExecutableNodePtr> executables; const ScriptNode *script = (*nodes.begin())->scriptNode(); for ( std::vector<NodePtr>::const_iterator nIt = nodes.begin(); nIt != nodes.end(); ++nIt ) { const ScriptNode *currentScript = (*nIt)->scriptNode(); if ( !currentScript || currentScript != script ) { throw IECore::Exception( getName().string() + ": Dispatched nodes must all belong to the same ScriptNode." ); } if ( ExecutableNode *executable = runTimeCast<ExecutableNode>( nIt->get() ) ) { executables.push_back( executable ); } else if ( const Box *box = runTimeCast<const Box>( nIt->get() ) ) { for ( RecursiveOutputPlugIterator plugIt( box ); plugIt != plugIt.end(); ++plugIt ) { Node *sourceNode = plugIt->get()->source<Plug>()->node(); if ( ExecutableNode *executable = runTimeCast<ExecutableNode>( sourceNode ) ) { executables.push_back( executable ); } } } else { throw IECore::Exception( getName().string() + ": Dispatched nodes must be ExecutableNodes or Boxes containing ExecutableNodes." ); } } if ( preDispatchSignal()( this, executables ) ) { /// \todo: communicate the cancellation to the user return; } const Context *context = Context::current(); std::vector<FrameList::Frame> frames; FrameListPtr frameList = frameRange( script, context ); frameList->asList( frames ); size_t i = 0; ExecutableNode::Tasks tasks; tasks.reserve( executables.size() * frames.size() ); for ( std::vector<FrameList::Frame>::const_iterator fIt = frames.begin(); fIt != frames.end(); ++fIt ) { for ( std::vector<ExecutableNodePtr>::const_iterator nIt = executables.begin(); nIt != executables.end(); ++nIt, ++i ) { ContextPtr frameContext = new Context( *context, Context::Borrowed ); frameContext->setFrame( *fIt ); tasks.push_back( ExecutableNode::Task( *nIt, frameContext ) ); } } TaskBatchPtr rootBatch = batchTasks( tasks ); if ( !rootBatch->requirements().empty() ) { doDispatch( rootBatch.get() ); } postDispatchSignal()( this, executables ); }