On 12/02/2013, at 5:56 AM, Marcin Erdmann wrote:

> On 29/01/13 07:44, Adam Murdoch wrote:
>> Implementation-wise, I would think about busting up building the task graph 
>> into 2 steps:
>> 
>> 1. Build the task graph proper, with a node for each task in the graph and 
>> edges to represent the various types of dependencies.
>> 2. Once the graph is built, calculate the execution plan:
>>  - Take each node that has no incoming edges, sort them and then traverse 
>> each in turn.
>>  - To traverse a node
>>  - Take each soft dependency, sort them and traverse each in turn.
>>  - Take each hard dependency, sort them and traverse each in turn.
> 
> I've finally managed to get the stuff that was preventing me from working on 
> that out of the door and I'm looking into this again.
> 
> Buildinng a task graph seems to be a bit of an overkill to me for this 
> feature as we can get away without it for now. There are two main problems I 
> see with building the graph:
> - we would need to have three phases instead of the two you are mentioning - 
> first build the graph with only 'hard' dependencies, then go through all 
> nodes and add 'soft' dependencies (soft/always runs after dependencies can 
> only be added when the nodes of the graph are known as a 'soft' dependency 
> only kicks in if the task we should run after is in the graph) and only then 
> perform a toposort

Not necessarily. You can add the nodes for the soft dependencies, and mark the 
node as 'not required'. When a hard dependency is added for a node, the node is 
marked as 'required'. When building the plan, you skip those nodes that are not 
required.

> - I don't feel competent enough to come up with how that graph should look 
> like from the implementation point of view, what methods it should expose, etc

It's all internal, so it doesn't really matter too much.

> 
> I believe the following is simpler and better for now:
> - every time DefaultTaskExecutionPlan.addToTaskGraph() is called then 
> create/update an unordered set of tasks that have to be executed and maintain 
> a set of tasks that aren't dependencies of other tasks (have no incoming 
> edges); the first set would be then used to check if a given 'soft' 
> dependency should be taken into account when ordering and the second set 
> would serve as the starting point for the toposort
> - add a CachingTaskDependencyResolveContext field to reuse resolved task 
> dependecies between the two phases of the algorithm
> - add determineExecutionPlan() method that has to be called before any call 
> to getTaskToExecute() and that performs a toposort the way you have described 
> in the second phase of your algorithm with the result being what currently is 
> the executionPlan field after the last call to addTaskToGraph() but with 
> 'soft' dependencies taken into account.
> 
> I will start implementing it this way. Please let me know if you don't 
> believe that this is the right way to go.


That's fine - which ever way you prefer. At some point later, we can rework it 
into a graph. For example, we'll need this to make parallel execution do a 
better job of scheduling tasks. I suspect as we add more interesting types of 
ordering rules, a graph will simplify things.


--
Adam Murdoch
Gradle Co-founder
http://www.gradle.org
VP of Engineering, Gradleware Inc. - Gradle Training, Support, Consulting
http://www.gradleware.com

Reply via email to