On 20/09/2013, at 9:31 AM, Marcin Erdmann <marcin.erdm...@proxerd.pl> wrote:
> I think I managed to fulfill all the requirements in the implementation I've > just pushed to my fork: https://github.com/erdi/gradle/tree/should-run-after. > > In the end I went for a simpler and what looks to be a more efficient > solution. Basically when building the execution plan I track should run after > edges that were visited and take snapshots of execution plan for any visited > task that has should run after successors. When a cycle is detected (just > like before, if we end up in a previously visited node that we haven't yet > finished processing successors for) we check if we walked through any should > run after edges. If yes then we remove that edge from the graph, restore > execution plan to the state from before visiting the 'from node' of that edge > and start processing successors of that task from scratch. If there are no > should run after edges we travelled through and we detect a cycle then we > report it. It's a neat idea. > > I'll add some docs for this over the weekend. > > Marcin > > > On Sat, Sep 14, 2013 at 4:23 PM, Marcin Erdmann <marcin.erdm...@proxerd.pl> > wrote: > Hi all, > > I started looking into how to implement shouldRunAfter task ordering rule. > Some time ago Adam wrote: > > The idea is to add a very weak task execution rule that only provides hints > for execution order and implies nothing else. So, if A shouldRunAfterB then: > > 1. If A or B are not scheduled to run, ignore the rule. > 2. Run A after B only if there are no other contradictory rules on the > ordering of A and B. That is, ignore cycles introduced by shouldRunAfterrules. > 3. The dependencies of A shouldRunAfter B and its dependencies. > 4. If B fails or is not run, A can still be run. > 5. If there is an idle worker thread and A is the only task whose > dependencies have been satisfied, then run A regardless of whether B has > beenrun or not. That is, prefer running the task over an idle worker thread. > > Similar to mustRunAfter, but different in #2 and #5 above. > > #1, #3 and #4 are straightforward. With regards to #2 the idea is to: > at the beginning of DefaultTaskExecutionPlan.determineExecutionPlan() find > all cycles in the execution graph using CachingDirectedGraphWalker the same > way as in onOrderingCycle() > find the first cycle that has no shouldRunAfter edges and throw a > CircularReferenceException > if no such cycles are found iterate over all cycles and for each remove the > first found shouldRunAfter edge (possibly with some logging?) - this will > break the cycle; it's possible that a cycle won't have a shouldRunAfter edge > as some cycles may share a shouldRunAfter edge that has been already removed > but because we checked for cycles without shouldRunAfter edges before we know > that all cycles in this phase had such edge at one point > continue with execution plan determination > The downside here is that we would be adding another graph traversal to the > process. On the other hand I don't see how we could detect and break cycles > with shouldRunAfter edges in them without doing so. > > With regards to #5, do I understand correctly that it simply means that > shouldRunAfter ordering should not be treated as a dependency in context of > TaskInfo.allDependenciesComplete()? > > Marcin > > -- Adam Murdoch Gradle Co-founder http://www.gradle.org VP of Engineering, Gradleware Inc. - Gradle Training, Support, Consulting http://www.gradleware.com Join us at the Gradle eXchange 2013, Oct 28th in London, UK: http://skillsmatter.com/event/java-jee/gradle-exchange-2013