command.revert(rev=rev, all=True) has timing dependent results after former commit

Peer Stritzinger peerst at
Tue Oct 25 14:41:01 CDT 2011

I'm trying to debug a problem in the "hg collaps" movedescendants funtion.

Basically what this function does is walk a sorted list of descendant
revisions of a collapsed set and recreates the topology on top of the
collapsed revision.  This is achieved by the following pseudocode:

   for rev in all revisions to move
        repo.dirstate.setparents to the mapped target parents

        commands.revert(rev=rev, all=True)

        update map for mapping parents

Detailed code of this is here:

Disclaimer: didn't write the movedescendants code just trying to
understand it to get it working well.

This method works quite well most of the times, but it breaks timing
dependent on certain repo structures.  A test case where I can
reproduce it looks like this before the collapse:

                             4 --- 5 --- 6
                            /               \
    0 --- 1 ---- 2 ---- 3                 9 --- 10 --- 11 --- 12
                            \                /
                             7------------ 8

Basically a file gets added in each changeset.

When I collapse 0:3 it creates a collapsed changeset and the iterates
through 4, 5 and 6 having added 3 more files.

When the algorithm reverts to 7 it should remove the 3 files added in
4:6 but this removing is timing dependent:

If I test this code it runs about 25 times ok and then fails to remove
all files added in 4:6 when going to 7.

I experimented with the timing and found out if I add a sleep for some
seconds at the beginning of the loop it fails everytime in a
deterministic way:
It removes only the file added in rev 6 and doesn't remove the 2 files
that were added in rev 4 and 5.
The files added in rev 4 and 5 are removed during the next step from 7 to 8.

More detailed logging and the repo structure before the collapse can
be seen here:

The testcase that makes this fail (about every 25 times on my machine)
is this one:

Having single stepped through the commands.revert() call I can that
only the file that was added in changeset 6 is considered and handled
and everything looks normal.  I suspect the algorithm only works if it
is fast enough so that all files have unset timestamps which somehow
makes the revert work even if it shouldn't.  Is this correct?

OTOH if I imagine doing a manual revert from directory parent 6 to -r
7 I would expect this to work.

After adding a bunch of tests to hg collapse and fixing several bugs
and missing features I'm pretty sure this is the last bug in it ;-)

But somehow I'm stuck debugging it.

Any help appreciated.
-- Peer

More information about the Mercurial-devel mailing list