Mercurial > hg
view tests/test-ssh-clone-r.t @ 43709:039fbd14d4e2
lock: fix race in lock-breaking code
With low frequency, I see hg pulls fail with output like:
abort: no such file or directory: .hg/store/lock
I think what happens is, in lock.py, in:
def _testlock(self, locker):
if not self._lockshouldbebroken(locker):
return locker
# if locker dead, break lock. must do this with another lock
# held, or can race and break valid lock.
try:
with lock(self.vfs, self.f + b'.break', timeout=0):
self.vfs.unlink(self.f)
except error.LockError:
return locker
if a lock is breakable on disk, and two hg processes concurrently get
to the "if locker dead" comment, a possible interleaving is: process1
finishes executing the function and then process2 finishes executing
the function. If that happens, process2 will either get ENOENT in
self.vfs.unlink (resulting in the spurious failure above), or break a
valid lock and potentially cause repository corruption.
The fix is simple enough: make sure the lock is breakable _inside_ the
critical section, because only then can we know that no other process
can invalidate our knowledge on the lock on disk.
I don't think there are tests for this. I've tested this manually
with:
diff --git a/mercurial/lock.py b/mercurial/lock.py
--- a/mercurial/lock.py
+++ b/mercurial/lock.py
@@ -351,6 +351,8 @@ class lock(object):
if not self._lockshouldbebroken(locker):
return locker
+ import random
+ time.sleep(1. + random.random())
# if locker dead, break lock. must do this with another lock
# held, or can race and break valid lock.
try:
@@ -358,6 +360,7 @@ class lock(object):
self.vfs.unlink(self.f)
except error.LockError:
return locker
+ time.sleep(1)
def testlock(self):
"""return id of locker if lock is valid, else None.
and I see this change of behavior before/after this commit:
$ $hg init repo
$ cd repo
$ ln -s $HOSTNAME/effffffc:987654321 .hg/wlock
$ touch a
$ $hg commit -Am_ & $hg commit -Am _; wait
-abort: No such file or directory: '/tmp/repo/.hg/wlock'
adding a
+warning: ignoring unknown working parent 679a8959a8ca!
+nothing changed
Differential Revision: https://phab.mercurial-scm.org/D7199
author | Valentin Gatien-Baron <valentin.gatienbaron@gmail.com> |
---|---|
date | Mon, 18 Nov 2019 20:10:38 -0800 |
parents | f1186c292d03 |
children | a28a7dcb9158 |
line wrap: on
line source
This test tries to exercise the ssh functionality with a dummy script #testcases sshv1 sshv2 #if sshv2 $ cat >> $HGRCPATH << EOF > [experimental] > sshpeer.advertise-v2 = true > sshserver.support-v2 = true > EOF #endif creating 'remote' repo $ hg init remote $ cd remote $ hg unbundle "$TESTDIR/bundles/remote.hg" adding changesets adding manifests adding file changes added 9 changesets with 7 changes to 4 files (+1 heads) new changesets bfaf4b5cbf01:916f1afdef90 (9 drafts) (run 'hg heads' to see heads, 'hg merge' to merge) $ hg up tip 1 files updated, 0 files merged, 0 files removed, 0 files unresolved $ cd .. clone remote via stream $ for i in 0 1 2 3 4 5 6 7 8; do > hg clone -e "\"$PYTHON\" \"$TESTDIR/dummyssh\"" --stream -r "$i" ssh://user@dummy/remote test-"$i" > if cd test-"$i"; then > hg verify > cd .. > fi > done adding changesets adding manifests adding file changes added 1 changesets with 1 changes to 1 files new changesets bfaf4b5cbf01 updating to branch default 1 files updated, 0 files merged, 0 files removed, 0 files unresolved checking changesets checking manifests crosschecking files in changesets and manifests checking files checked 1 changesets with 1 changes to 1 files adding changesets adding manifests adding file changes added 2 changesets with 2 changes to 1 files new changesets bfaf4b5cbf01:21f32785131f updating to branch default 1 files updated, 0 files merged, 0 files removed, 0 files unresolved checking changesets checking manifests crosschecking files in changesets and manifests checking files checked 2 changesets with 2 changes to 1 files adding changesets adding manifests adding file changes added 3 changesets with 3 changes to 1 files new changesets bfaf4b5cbf01:4ce51a113780 updating to branch default 1 files updated, 0 files merged, 0 files removed, 0 files unresolved checking changesets checking manifests crosschecking files in changesets and manifests checking files checked 3 changesets with 3 changes to 1 files adding changesets adding manifests adding file changes added 4 changesets with 4 changes to 1 files new changesets bfaf4b5cbf01:93ee6ab32777 updating to branch default 1 files updated, 0 files merged, 0 files removed, 0 files unresolved checking changesets checking manifests crosschecking files in changesets and manifests checking files checked 4 changesets with 4 changes to 1 files adding changesets adding manifests adding file changes added 2 changesets with 2 changes to 1 files new changesets bfaf4b5cbf01:c70afb1ee985 updating to branch default 1 files updated, 0 files merged, 0 files removed, 0 files unresolved checking changesets checking manifests crosschecking files in changesets and manifests checking files checked 2 changesets with 2 changes to 1 files adding changesets adding manifests adding file changes added 3 changesets with 3 changes to 1 files new changesets bfaf4b5cbf01:f03ae5a9b979 updating to branch default 1 files updated, 0 files merged, 0 files removed, 0 files unresolved checking changesets checking manifests crosschecking files in changesets and manifests checking files checked 3 changesets with 3 changes to 1 files adding changesets adding manifests adding file changes added 4 changesets with 5 changes to 2 files new changesets bfaf4b5cbf01:095cb14b1b4d updating to branch default 2 files updated, 0 files merged, 0 files removed, 0 files unresolved checking changesets checking manifests crosschecking files in changesets and manifests checking files checked 4 changesets with 5 changes to 2 files adding changesets adding manifests adding file changes added 5 changesets with 6 changes to 3 files new changesets bfaf4b5cbf01:faa2e4234c7a updating to branch default 2 files updated, 0 files merged, 0 files removed, 0 files unresolved checking changesets checking manifests crosschecking files in changesets and manifests checking files checked 5 changesets with 6 changes to 3 files adding changesets adding manifests adding file changes added 5 changesets with 5 changes to 2 files new changesets bfaf4b5cbf01:916f1afdef90 updating to branch default 1 files updated, 0 files merged, 0 files removed, 0 files unresolved checking changesets checking manifests crosschecking files in changesets and manifests checking files checked 5 changesets with 5 changes to 2 files $ cd test-8 $ hg pull ../test-7 pulling from ../test-7 searching for changes adding changesets adding manifests adding file changes added 4 changesets with 2 changes to 3 files (+1 heads) new changesets c70afb1ee985:faa2e4234c7a (run 'hg heads' to see heads, 'hg merge' to merge) $ hg verify checking changesets checking manifests crosschecking files in changesets and manifests checking files checked 9 changesets with 7 changes to 4 files $ cd .. $ cd test-1 $ hg pull -e "\"$PYTHON\" \"$TESTDIR/dummyssh\"" -r 4 ssh://user@dummy/remote pulling from ssh://user@dummy/remote searching for changes adding changesets adding manifests adding file changes added 1 changesets with 0 changes to 0 files (+1 heads) new changesets c70afb1ee985 (run 'hg heads' to see heads, 'hg merge' to merge) $ hg verify checking changesets checking manifests crosschecking files in changesets and manifests checking files checked 3 changesets with 2 changes to 1 files $ hg pull -e "\"$PYTHON\" \"$TESTDIR/dummyssh\"" ssh://user@dummy/remote pulling from ssh://user@dummy/remote searching for changes adding changesets adding manifests adding file changes added 6 changesets with 5 changes to 4 files new changesets 4ce51a113780:916f1afdef90 (run 'hg update' to get a working copy) $ cd .. $ cd test-2 $ hg pull -e "\"$PYTHON\" \"$TESTDIR/dummyssh\"" -r 5 ssh://user@dummy/remote pulling from ssh://user@dummy/remote searching for changes adding changesets adding manifests adding file changes added 2 changesets with 0 changes to 0 files (+1 heads) new changesets c70afb1ee985:f03ae5a9b979 (run 'hg heads' to see heads, 'hg merge' to merge) $ hg verify checking changesets checking manifests crosschecking files in changesets and manifests checking files checked 5 changesets with 3 changes to 1 files $ hg pull -e "\"$PYTHON\" \"$TESTDIR/dummyssh\"" ssh://user@dummy/remote pulling from ssh://user@dummy/remote searching for changes adding changesets adding manifests adding file changes added 4 changesets with 4 changes to 4 files new changesets 93ee6ab32777:916f1afdef90 (run 'hg update' to get a working copy) $ hg verify checking changesets checking manifests crosschecking files in changesets and manifests checking files checked 9 changesets with 7 changes to 4 files $ cd ..