merge: fix race that could cause wrong size in dirstate
The problem is that hg merge/update/etc work the following way:
1. figure out what files to update
2. apply the update to disk
3. apply the update to in-memory dirstate
4. write dirstate
where step3 looks at the filesystem and assumes it sees the result of
step2. If a file is changed between step2 and step3, step3 will record
incorrect information in the dirstate.
I avoid this by passing the size step3 needs directly from step2, for
the common path (not implemented for change/delete conflicts for
instance).
I didn't fix the same race for the exec bit for now, because it's less
likely to be problematic and I had trouble due to the fact that the
dirstate stores the permissions differently from the manifest (st_mode
vs '' 'l' 'x'), in combination with tests that pretend that symlinks
are not supported.
However, I moved the lstat from step3 to step2, which should tighten
the race window markedly, both for the exec bit and for the mtime.
Differential Revision: https://phab.mercurial-scm.org/D6475
Checking the size/permissions/file-type of files stored in the
dirstate after an update where the files are changed concurrently
outside of hg's control.
$ hg init repo
$ cd repo
$ echo a > a
$ hg commit -qAm _
$ echo aa > a
$ hg commit -m _
$ hg debugdirstate --no-dates
n 644 3 (set |unset) a (re)
$ cat >> $TESTTMP/dirstaterace.py << EOF
> from mercurial import (
> extensions,
> merge,
> )
> def extsetup(ui):
> extensions.wrapfunction(merge, 'applyupdates', wrap)
> def wrap(orig, *args, **kwargs):
> res = orig(*args, **kwargs)
> with open("a", "w"):
> pass # just truncate the file
> return res
> EOF
Do an update where file 'a' is changed between hg writing it to disk
and hg writing the dirstate. The dirstate is correct nonetheless, and
so hg status correctly shows a as clean.
$ hg up -r 0 --config extensions.race=$TESTTMP/dirstaterace.py
1 files updated, 0 files merged, 0 files removed, 0 files unresolved
$ hg debugdirstate --no-dates
n 644 2 (set |unset) a (re)
$ echo a > a; hg status; hg diff