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.

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 shouldRunAfter
>> rules.
>> 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
>
>

Reply via email to