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
