Avoid double-scheduling build edges in another case
authorBrad King <brad.king@kitware.com>
Tue, 11 Aug 2015 17:17:12 +0000 (13:17 -0400)
committerBrad King <brad.king@kitware.com>
Wed, 3 Feb 2016 21:23:11 +0000 (16:23 -0500)
commite8d855f2622693a4b616cba96084cd7a58cb0611
treea8c0acd4cd1e0d35eb9f4aab2586f469836d55cf
parentca5fc795f38c77e42657e9d276f1dfc5127a8243
Avoid double-scheduling build edges in another case

The change in commit v1.2.0~3^2~3^2~3 (Fix duplicate edge Pool crash in
the minimally invasive way, 2013-03-18) avoids double-scheduling in a
case involving duplicate out edges.  However, double-scheduling may also
occur on a consistent graph when an edge and one of its dependencies
share an order-only input:

    $ cat build.ninja
    ...
    build c: touch
    build b: touch || c
    build a: touch | b || c
    $ ninja a
    $ rm a c
    $ ninja a

In this case 'c' will build first.  When NodeFinished('c') loops over
the out edges it will find AllInputsReady is true for 'b' and call
EdgeFinished('b') since it is not wanted (up to date).  This will
call NodeFinished('b') which will loop over its out edges, find
AllInputsReady is true for 'a', and call ScheduleEdge('a').  When
we eventually return to the loop in NodeFinished('c') it will move
on to its second output and find that AllInputsReady is true for
'a' and call ScheduleEdge('a') again.

Teach ScheduleEdge to tolerate duplicate calls for an edge that has
already been scheduled.  Avoid calling EdgeScheduled more than once
for the same edge.
src/build.cc
src/build_test.cc