Mercurial > public > mercurial-scm > hg
annotate mercurial/lock.py @ 36701:d77c3b023393
lock: block signal interrupt while making a lock file
On Windows where symlink isn't supported, util.makelock() could leave an empty
file if interrupted immediately after os.open(). This empty lock never dies
as it has no process id recorded.
ld = os.open(pathname, os.O_CREAT | os.O_WRONLY | os.O_EXCL)
# an interrupt may occur here
os.write(ld, info)
os.close(ld)
This was a long-standing bug of TortoiseHg which runs a command-server and
kills it by CTRL_C_EVENT, reported by random Windows users.
https://bitbucket.org/tortoisehg/thg/issues/4873/#comment-43591129
At first, I tried to fix makelock() to clean up a stale lock file, which
turned out to be hard because any instructions may be interrupted by a
signal.
ld = None
try:
# CALL_FUNCTION # os.open(...)
# an interrupt may occur here
# STORE_FAST # ld = ...
ld = os.open(pathname, os.O_CREAT | os.O_WRONLY | os.O_EXCL)
os.write(ld, info)
...
return True
except:
if ld:
...
os.unlink(pathname)
return False
So I decided to block signals by temporarily replacing the signal handlers
so makelcok() and held = 1 will never be interrupted.
Many thanks to Fernando Najera for investigating the issue.
author | Yuya Nishihara <yuya@tcha.org> |
---|---|
date | Sat, 03 Mar 2018 23:49:39 -0500 |
parents | 214f61abd865 |
children | a8a902d7176e |
rev | line source |
---|---|
9309
cfdcb7a465af
localrepo: document the locking scheme a little better
Greg Ward <greg-hg@gerg.ca>
parents:
8312
diff
changeset
|
1 # lock.py - simple advisory locking scheme for mercurial |
161 | 2 # |
2859 | 3 # Copyright 2005, 2006 Matt Mackall <mpm@selenic.com> |
161 | 4 # |
8225
46293a0c7e9f
updated license to be explicit about GPL version 2
Martin Geisler <mg@lazybytes.net>
parents:
8113
diff
changeset
|
5 # This software may be used and distributed according to the terms of the |
10263 | 6 # GNU General Public License version 2 or any later version. |
161 | 7 |
25956
8cd30e9277ae
lock: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents:
25660
diff
changeset
|
8 from __future__ import absolute_import |
8cd30e9277ae
lock: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents:
25660
diff
changeset
|
9 |
26473
5f94e64f182c
lock: turn prepinherit/reacquire into a single context manager
Siddharth Agarwal <sid0@fb.com>
parents:
26387
diff
changeset
|
10 import contextlib |
25956
8cd30e9277ae
lock: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents:
25660
diff
changeset
|
11 import errno |
30921
1f151a33af8e
lock: include Linux pid namespace identifier in prefix
Jun Wu <quark@fb.com>
parents:
30920
diff
changeset
|
12 import os |
36701
d77c3b023393
lock: block signal interrupt while making a lock file
Yuya Nishihara <yuya@tcha.org>
parents:
36657
diff
changeset
|
13 import signal |
25956
8cd30e9277ae
lock: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents:
25660
diff
changeset
|
14 import socket |
8cd30e9277ae
lock: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents:
25660
diff
changeset
|
15 import time |
8113
87a1605979e4
add a deprecation warning for gc based lock releasing
Ronny Pfannschmidt <Ronny.Pfannschmidt@gmx.de>
parents:
8108
diff
changeset
|
16 import warnings |
161 | 17 |
35208
1b758105b5c7
lock: add a trylock method handling the timeout and messaging logic
Boris Feld <boris.feld@octobus.net>
parents:
32088
diff
changeset
|
18 from .i18n import _ |
1b758105b5c7
lock: add a trylock method handling the timeout and messaging logic
Boris Feld <boris.feld@octobus.net>
parents:
32088
diff
changeset
|
19 |
25956
8cd30e9277ae
lock: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents:
25660
diff
changeset
|
20 from . import ( |
31375
d57aa655ce97
lock: encode result of gethostname into a bytestring
Augie Fackler <augie@google.com>
parents:
31354
diff
changeset
|
21 encoding, |
25956
8cd30e9277ae
lock: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents:
25660
diff
changeset
|
22 error, |
30921
1f151a33af8e
lock: include Linux pid namespace identifier in prefix
Jun Wu <quark@fb.com>
parents:
30920
diff
changeset
|
23 pycompat, |
25956
8cd30e9277ae
lock: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents:
25660
diff
changeset
|
24 util, |
8cd30e9277ae
lock: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents:
25660
diff
changeset
|
25 ) |
8cd30e9277ae
lock: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents:
25660
diff
changeset
|
26 |
30920
dc9f086c7691
lock: move lock._host calculation to a function
Jun Wu <quark@fb.com>
parents:
28959
diff
changeset
|
27 def _getlockprefix(): |
dc9f086c7691
lock: move lock._host calculation to a function
Jun Wu <quark@fb.com>
parents:
28959
diff
changeset
|
28 """Return a string which is used to differentiate pid namespaces |
dc9f086c7691
lock: move lock._host calculation to a function
Jun Wu <quark@fb.com>
parents:
28959
diff
changeset
|
29 |
dc9f086c7691
lock: move lock._host calculation to a function
Jun Wu <quark@fb.com>
parents:
28959
diff
changeset
|
30 It's useful to detect "dead" processes and remove stale locks with |
30921
1f151a33af8e
lock: include Linux pid namespace identifier in prefix
Jun Wu <quark@fb.com>
parents:
30920
diff
changeset
|
31 confidence. Typically it's just hostname. On modern linux, we include an |
1f151a33af8e
lock: include Linux pid namespace identifier in prefix
Jun Wu <quark@fb.com>
parents:
30920
diff
changeset
|
32 extra Linux-specific pid namespace identifier. |
30920
dc9f086c7691
lock: move lock._host calculation to a function
Jun Wu <quark@fb.com>
parents:
28959
diff
changeset
|
33 """ |
35897
4b1c04082cdc
py3: replace "if ispy3" by encoding.strtolocal()
Yuya Nishihara <yuya@tcha.org>
parents:
35209
diff
changeset
|
34 result = encoding.strtolocal(socket.gethostname()) |
30921
1f151a33af8e
lock: include Linux pid namespace identifier in prefix
Jun Wu <quark@fb.com>
parents:
30920
diff
changeset
|
35 if pycompat.sysplatform.startswith('linux'): |
1f151a33af8e
lock: include Linux pid namespace identifier in prefix
Jun Wu <quark@fb.com>
parents:
30920
diff
changeset
|
36 try: |
1f151a33af8e
lock: include Linux pid namespace identifier in prefix
Jun Wu <quark@fb.com>
parents:
30920
diff
changeset
|
37 result += '/%x' % os.stat('/proc/self/ns/pid').st_ino |
1f151a33af8e
lock: include Linux pid namespace identifier in prefix
Jun Wu <quark@fb.com>
parents:
30920
diff
changeset
|
38 except OSError as ex: |
1f151a33af8e
lock: include Linux pid namespace identifier in prefix
Jun Wu <quark@fb.com>
parents:
30920
diff
changeset
|
39 if ex.errno not in (errno.ENOENT, errno.EACCES, errno.ENOTDIR): |
1f151a33af8e
lock: include Linux pid namespace identifier in prefix
Jun Wu <quark@fb.com>
parents:
30920
diff
changeset
|
40 raise |
1f151a33af8e
lock: include Linux pid namespace identifier in prefix
Jun Wu <quark@fb.com>
parents:
30920
diff
changeset
|
41 return result |
30920
dc9f086c7691
lock: move lock._host calculation to a function
Jun Wu <quark@fb.com>
parents:
28959
diff
changeset
|
42 |
36701
d77c3b023393
lock: block signal interrupt while making a lock file
Yuya Nishihara <yuya@tcha.org>
parents:
36657
diff
changeset
|
43 @contextlib.contextmanager |
d77c3b023393
lock: block signal interrupt while making a lock file
Yuya Nishihara <yuya@tcha.org>
parents:
36657
diff
changeset
|
44 def _delayedinterrupt(): |
d77c3b023393
lock: block signal interrupt while making a lock file
Yuya Nishihara <yuya@tcha.org>
parents:
36657
diff
changeset
|
45 """Block signal interrupt while doing something critical |
d77c3b023393
lock: block signal interrupt while making a lock file
Yuya Nishihara <yuya@tcha.org>
parents:
36657
diff
changeset
|
46 |
d77c3b023393
lock: block signal interrupt while making a lock file
Yuya Nishihara <yuya@tcha.org>
parents:
36657
diff
changeset
|
47 This makes sure that the code block wrapped by this context manager won't |
d77c3b023393
lock: block signal interrupt while making a lock file
Yuya Nishihara <yuya@tcha.org>
parents:
36657
diff
changeset
|
48 be interrupted. |
d77c3b023393
lock: block signal interrupt while making a lock file
Yuya Nishihara <yuya@tcha.org>
parents:
36657
diff
changeset
|
49 |
d77c3b023393
lock: block signal interrupt while making a lock file
Yuya Nishihara <yuya@tcha.org>
parents:
36657
diff
changeset
|
50 For Windows developers: It appears not possible to guard time.sleep() |
d77c3b023393
lock: block signal interrupt while making a lock file
Yuya Nishihara <yuya@tcha.org>
parents:
36657
diff
changeset
|
51 from CTRL_C_EVENT, so please don't use time.sleep() to test if this is |
d77c3b023393
lock: block signal interrupt while making a lock file
Yuya Nishihara <yuya@tcha.org>
parents:
36657
diff
changeset
|
52 working. |
d77c3b023393
lock: block signal interrupt while making a lock file
Yuya Nishihara <yuya@tcha.org>
parents:
36657
diff
changeset
|
53 """ |
d77c3b023393
lock: block signal interrupt while making a lock file
Yuya Nishihara <yuya@tcha.org>
parents:
36657
diff
changeset
|
54 assertedsigs = [] |
d77c3b023393
lock: block signal interrupt while making a lock file
Yuya Nishihara <yuya@tcha.org>
parents:
36657
diff
changeset
|
55 blocked = False |
d77c3b023393
lock: block signal interrupt while making a lock file
Yuya Nishihara <yuya@tcha.org>
parents:
36657
diff
changeset
|
56 orighandlers = {} |
d77c3b023393
lock: block signal interrupt while making a lock file
Yuya Nishihara <yuya@tcha.org>
parents:
36657
diff
changeset
|
57 |
d77c3b023393
lock: block signal interrupt while making a lock file
Yuya Nishihara <yuya@tcha.org>
parents:
36657
diff
changeset
|
58 def raiseinterrupt(num): |
d77c3b023393
lock: block signal interrupt while making a lock file
Yuya Nishihara <yuya@tcha.org>
parents:
36657
diff
changeset
|
59 if (num == getattr(signal, 'SIGINT', None) or |
d77c3b023393
lock: block signal interrupt while making a lock file
Yuya Nishihara <yuya@tcha.org>
parents:
36657
diff
changeset
|
60 num == getattr(signal, 'CTRL_C_EVENT', None)): |
d77c3b023393
lock: block signal interrupt while making a lock file
Yuya Nishihara <yuya@tcha.org>
parents:
36657
diff
changeset
|
61 raise KeyboardInterrupt |
d77c3b023393
lock: block signal interrupt while making a lock file
Yuya Nishihara <yuya@tcha.org>
parents:
36657
diff
changeset
|
62 else: |
d77c3b023393
lock: block signal interrupt while making a lock file
Yuya Nishihara <yuya@tcha.org>
parents:
36657
diff
changeset
|
63 raise error.SignalInterrupt |
d77c3b023393
lock: block signal interrupt while making a lock file
Yuya Nishihara <yuya@tcha.org>
parents:
36657
diff
changeset
|
64 def catchterm(num, frame): |
d77c3b023393
lock: block signal interrupt while making a lock file
Yuya Nishihara <yuya@tcha.org>
parents:
36657
diff
changeset
|
65 if blocked: |
d77c3b023393
lock: block signal interrupt while making a lock file
Yuya Nishihara <yuya@tcha.org>
parents:
36657
diff
changeset
|
66 assertedsigs.append(num) |
d77c3b023393
lock: block signal interrupt while making a lock file
Yuya Nishihara <yuya@tcha.org>
parents:
36657
diff
changeset
|
67 else: |
d77c3b023393
lock: block signal interrupt while making a lock file
Yuya Nishihara <yuya@tcha.org>
parents:
36657
diff
changeset
|
68 raiseinterrupt(num) |
d77c3b023393
lock: block signal interrupt while making a lock file
Yuya Nishihara <yuya@tcha.org>
parents:
36657
diff
changeset
|
69 |
d77c3b023393
lock: block signal interrupt while making a lock file
Yuya Nishihara <yuya@tcha.org>
parents:
36657
diff
changeset
|
70 try: |
d77c3b023393
lock: block signal interrupt while making a lock file
Yuya Nishihara <yuya@tcha.org>
parents:
36657
diff
changeset
|
71 # save handlers first so they can be restored even if a setup is |
d77c3b023393
lock: block signal interrupt while making a lock file
Yuya Nishihara <yuya@tcha.org>
parents:
36657
diff
changeset
|
72 # interrupted between signal.signal() and orighandlers[] =. |
d77c3b023393
lock: block signal interrupt while making a lock file
Yuya Nishihara <yuya@tcha.org>
parents:
36657
diff
changeset
|
73 for name in ['CTRL_C_EVENT', 'SIGINT', 'SIGBREAK', 'SIGHUP', 'SIGTERM']: |
d77c3b023393
lock: block signal interrupt while making a lock file
Yuya Nishihara <yuya@tcha.org>
parents:
36657
diff
changeset
|
74 num = getattr(signal, name, None) |
d77c3b023393
lock: block signal interrupt while making a lock file
Yuya Nishihara <yuya@tcha.org>
parents:
36657
diff
changeset
|
75 if num and num not in orighandlers: |
d77c3b023393
lock: block signal interrupt while making a lock file
Yuya Nishihara <yuya@tcha.org>
parents:
36657
diff
changeset
|
76 orighandlers[num] = signal.getsignal(num) |
d77c3b023393
lock: block signal interrupt while making a lock file
Yuya Nishihara <yuya@tcha.org>
parents:
36657
diff
changeset
|
77 try: |
d77c3b023393
lock: block signal interrupt while making a lock file
Yuya Nishihara <yuya@tcha.org>
parents:
36657
diff
changeset
|
78 for num in orighandlers: |
d77c3b023393
lock: block signal interrupt while making a lock file
Yuya Nishihara <yuya@tcha.org>
parents:
36657
diff
changeset
|
79 signal.signal(num, catchterm) |
d77c3b023393
lock: block signal interrupt while making a lock file
Yuya Nishihara <yuya@tcha.org>
parents:
36657
diff
changeset
|
80 except ValueError: |
d77c3b023393
lock: block signal interrupt while making a lock file
Yuya Nishihara <yuya@tcha.org>
parents:
36657
diff
changeset
|
81 pass # in a thread? no luck |
d77c3b023393
lock: block signal interrupt while making a lock file
Yuya Nishihara <yuya@tcha.org>
parents:
36657
diff
changeset
|
82 |
d77c3b023393
lock: block signal interrupt while making a lock file
Yuya Nishihara <yuya@tcha.org>
parents:
36657
diff
changeset
|
83 blocked = True |
d77c3b023393
lock: block signal interrupt while making a lock file
Yuya Nishihara <yuya@tcha.org>
parents:
36657
diff
changeset
|
84 yield |
d77c3b023393
lock: block signal interrupt while making a lock file
Yuya Nishihara <yuya@tcha.org>
parents:
36657
diff
changeset
|
85 finally: |
d77c3b023393
lock: block signal interrupt while making a lock file
Yuya Nishihara <yuya@tcha.org>
parents:
36657
diff
changeset
|
86 # no simple way to reliably restore all signal handlers because |
d77c3b023393
lock: block signal interrupt while making a lock file
Yuya Nishihara <yuya@tcha.org>
parents:
36657
diff
changeset
|
87 # any loops, recursive function calls, except blocks, etc. can be |
d77c3b023393
lock: block signal interrupt while making a lock file
Yuya Nishihara <yuya@tcha.org>
parents:
36657
diff
changeset
|
88 # interrupted. so instead, make catchterm() raise interrupt. |
d77c3b023393
lock: block signal interrupt while making a lock file
Yuya Nishihara <yuya@tcha.org>
parents:
36657
diff
changeset
|
89 blocked = False |
d77c3b023393
lock: block signal interrupt while making a lock file
Yuya Nishihara <yuya@tcha.org>
parents:
36657
diff
changeset
|
90 try: |
d77c3b023393
lock: block signal interrupt while making a lock file
Yuya Nishihara <yuya@tcha.org>
parents:
36657
diff
changeset
|
91 for num, handler in orighandlers.items(): |
d77c3b023393
lock: block signal interrupt while making a lock file
Yuya Nishihara <yuya@tcha.org>
parents:
36657
diff
changeset
|
92 signal.signal(num, handler) |
d77c3b023393
lock: block signal interrupt while making a lock file
Yuya Nishihara <yuya@tcha.org>
parents:
36657
diff
changeset
|
93 except ValueError: |
d77c3b023393
lock: block signal interrupt while making a lock file
Yuya Nishihara <yuya@tcha.org>
parents:
36657
diff
changeset
|
94 pass # in a thread? |
d77c3b023393
lock: block signal interrupt while making a lock file
Yuya Nishihara <yuya@tcha.org>
parents:
36657
diff
changeset
|
95 |
d77c3b023393
lock: block signal interrupt while making a lock file
Yuya Nishihara <yuya@tcha.org>
parents:
36657
diff
changeset
|
96 # re-raise interrupt exception if any, which may be shadowed by a new |
d77c3b023393
lock: block signal interrupt while making a lock file
Yuya Nishihara <yuya@tcha.org>
parents:
36657
diff
changeset
|
97 # interrupt occurred while re-raising the first one |
d77c3b023393
lock: block signal interrupt while making a lock file
Yuya Nishihara <yuya@tcha.org>
parents:
36657
diff
changeset
|
98 if assertedsigs: |
d77c3b023393
lock: block signal interrupt while making a lock file
Yuya Nishihara <yuya@tcha.org>
parents:
36657
diff
changeset
|
99 raiseinterrupt(assertedsigs[0]) |
d77c3b023393
lock: block signal interrupt while making a lock file
Yuya Nishihara <yuya@tcha.org>
parents:
36657
diff
changeset
|
100 |
35209
9153871d50e0
lock: allow to configure when the lock messages are displayed
Boris Feld <boris.feld@octobus.net>
parents:
35208
diff
changeset
|
101 def trylock(ui, vfs, lockname, timeout, warntimeout, *args, **kwargs): |
35208
1b758105b5c7
lock: add a trylock method handling the timeout and messaging logic
Boris Feld <boris.feld@octobus.net>
parents:
32088
diff
changeset
|
102 """return an acquired lock or raise an a LockHeld exception |
1b758105b5c7
lock: add a trylock method handling the timeout and messaging logic
Boris Feld <boris.feld@octobus.net>
parents:
32088
diff
changeset
|
103 |
35209
9153871d50e0
lock: allow to configure when the lock messages are displayed
Boris Feld <boris.feld@octobus.net>
parents:
35208
diff
changeset
|
104 This function is responsible to issue warnings and or debug messages about |
9153871d50e0
lock: allow to configure when the lock messages are displayed
Boris Feld <boris.feld@octobus.net>
parents:
35208
diff
changeset
|
105 the held lock while trying to acquires it.""" |
35208
1b758105b5c7
lock: add a trylock method handling the timeout and messaging logic
Boris Feld <boris.feld@octobus.net>
parents:
32088
diff
changeset
|
106 |
1b758105b5c7
lock: add a trylock method handling the timeout and messaging logic
Boris Feld <boris.feld@octobus.net>
parents:
32088
diff
changeset
|
107 def printwarning(printer, locker): |
1b758105b5c7
lock: add a trylock method handling the timeout and messaging logic
Boris Feld <boris.feld@octobus.net>
parents:
32088
diff
changeset
|
108 """issue the usual "waiting on lock" message through any channel""" |
1b758105b5c7
lock: add a trylock method handling the timeout and messaging logic
Boris Feld <boris.feld@octobus.net>
parents:
32088
diff
changeset
|
109 # show more details for new-style locks |
1b758105b5c7
lock: add a trylock method handling the timeout and messaging logic
Boris Feld <boris.feld@octobus.net>
parents:
32088
diff
changeset
|
110 if ':' in locker: |
1b758105b5c7
lock: add a trylock method handling the timeout and messaging logic
Boris Feld <boris.feld@octobus.net>
parents:
32088
diff
changeset
|
111 host, pid = locker.split(":", 1) |
36642
f6efb3c08c19
py3: fix formatting of lock error message
Yuya Nishihara <yuya@tcha.org>
parents:
36640
diff
changeset
|
112 msg = (_("waiting for lock on %s held by process %r on host %r\n") |
f6efb3c08c19
py3: fix formatting of lock error message
Yuya Nishihara <yuya@tcha.org>
parents:
36640
diff
changeset
|
113 % (pycompat.bytestr(l.desc), pycompat.bytestr(pid), |
f6efb3c08c19
py3: fix formatting of lock error message
Yuya Nishihara <yuya@tcha.org>
parents:
36640
diff
changeset
|
114 pycompat.bytestr(host))) |
35208
1b758105b5c7
lock: add a trylock method handling the timeout and messaging logic
Boris Feld <boris.feld@octobus.net>
parents:
32088
diff
changeset
|
115 else: |
36642
f6efb3c08c19
py3: fix formatting of lock error message
Yuya Nishihara <yuya@tcha.org>
parents:
36640
diff
changeset
|
116 msg = (_("waiting for lock on %s held by %r\n") |
f6efb3c08c19
py3: fix formatting of lock error message
Yuya Nishihara <yuya@tcha.org>
parents:
36640
diff
changeset
|
117 % (l.desc, pycompat.bytestr(locker))) |
35208
1b758105b5c7
lock: add a trylock method handling the timeout and messaging logic
Boris Feld <boris.feld@octobus.net>
parents:
32088
diff
changeset
|
118 printer(msg) |
1b758105b5c7
lock: add a trylock method handling the timeout and messaging logic
Boris Feld <boris.feld@octobus.net>
parents:
32088
diff
changeset
|
119 |
1b758105b5c7
lock: add a trylock method handling the timeout and messaging logic
Boris Feld <boris.feld@octobus.net>
parents:
32088
diff
changeset
|
120 l = lock(vfs, lockname, 0, *args, dolock=False, **kwargs) |
1b758105b5c7
lock: add a trylock method handling the timeout and messaging logic
Boris Feld <boris.feld@octobus.net>
parents:
32088
diff
changeset
|
121 |
35209
9153871d50e0
lock: allow to configure when the lock messages are displayed
Boris Feld <boris.feld@octobus.net>
parents:
35208
diff
changeset
|
122 debugidx = 0 if (warntimeout and timeout) else -1 |
35208
1b758105b5c7
lock: add a trylock method handling the timeout and messaging logic
Boris Feld <boris.feld@octobus.net>
parents:
32088
diff
changeset
|
123 warningidx = 0 |
1b758105b5c7
lock: add a trylock method handling the timeout and messaging logic
Boris Feld <boris.feld@octobus.net>
parents:
32088
diff
changeset
|
124 if not timeout: |
1b758105b5c7
lock: add a trylock method handling the timeout and messaging logic
Boris Feld <boris.feld@octobus.net>
parents:
32088
diff
changeset
|
125 warningidx = -1 |
35209
9153871d50e0
lock: allow to configure when the lock messages are displayed
Boris Feld <boris.feld@octobus.net>
parents:
35208
diff
changeset
|
126 elif warntimeout: |
9153871d50e0
lock: allow to configure when the lock messages are displayed
Boris Feld <boris.feld@octobus.net>
parents:
35208
diff
changeset
|
127 warningidx = warntimeout |
35208
1b758105b5c7
lock: add a trylock method handling the timeout and messaging logic
Boris Feld <boris.feld@octobus.net>
parents:
32088
diff
changeset
|
128 |
1b758105b5c7
lock: add a trylock method handling the timeout and messaging logic
Boris Feld <boris.feld@octobus.net>
parents:
32088
diff
changeset
|
129 delay = 0 |
1b758105b5c7
lock: add a trylock method handling the timeout and messaging logic
Boris Feld <boris.feld@octobus.net>
parents:
32088
diff
changeset
|
130 while True: |
1b758105b5c7
lock: add a trylock method handling the timeout and messaging logic
Boris Feld <boris.feld@octobus.net>
parents:
32088
diff
changeset
|
131 try: |
1b758105b5c7
lock: add a trylock method handling the timeout and messaging logic
Boris Feld <boris.feld@octobus.net>
parents:
32088
diff
changeset
|
132 l._trylock() |
1b758105b5c7
lock: add a trylock method handling the timeout and messaging logic
Boris Feld <boris.feld@octobus.net>
parents:
32088
diff
changeset
|
133 break |
1b758105b5c7
lock: add a trylock method handling the timeout and messaging logic
Boris Feld <boris.feld@octobus.net>
parents:
32088
diff
changeset
|
134 except error.LockHeld as inst: |
35209
9153871d50e0
lock: allow to configure when the lock messages are displayed
Boris Feld <boris.feld@octobus.net>
parents:
35208
diff
changeset
|
135 if delay == debugidx: |
9153871d50e0
lock: allow to configure when the lock messages are displayed
Boris Feld <boris.feld@octobus.net>
parents:
35208
diff
changeset
|
136 printwarning(ui.debug, inst.locker) |
35208
1b758105b5c7
lock: add a trylock method handling the timeout and messaging logic
Boris Feld <boris.feld@octobus.net>
parents:
32088
diff
changeset
|
137 if delay == warningidx: |
1b758105b5c7
lock: add a trylock method handling the timeout and messaging logic
Boris Feld <boris.feld@octobus.net>
parents:
32088
diff
changeset
|
138 printwarning(ui.warn, inst.locker) |
1b758105b5c7
lock: add a trylock method handling the timeout and messaging logic
Boris Feld <boris.feld@octobus.net>
parents:
32088
diff
changeset
|
139 if timeout <= delay: |
1b758105b5c7
lock: add a trylock method handling the timeout and messaging logic
Boris Feld <boris.feld@octobus.net>
parents:
32088
diff
changeset
|
140 raise error.LockHeld(errno.ETIMEDOUT, inst.filename, |
1b758105b5c7
lock: add a trylock method handling the timeout and messaging logic
Boris Feld <boris.feld@octobus.net>
parents:
32088
diff
changeset
|
141 l.desc, inst.locker) |
1b758105b5c7
lock: add a trylock method handling the timeout and messaging logic
Boris Feld <boris.feld@octobus.net>
parents:
32088
diff
changeset
|
142 time.sleep(1) |
1b758105b5c7
lock: add a trylock method handling the timeout and messaging logic
Boris Feld <boris.feld@octobus.net>
parents:
32088
diff
changeset
|
143 delay += 1 |
1b758105b5c7
lock: add a trylock method handling the timeout and messaging logic
Boris Feld <boris.feld@octobus.net>
parents:
32088
diff
changeset
|
144 |
1b758105b5c7
lock: add a trylock method handling the timeout and messaging logic
Boris Feld <boris.feld@octobus.net>
parents:
32088
diff
changeset
|
145 l.delay = delay |
1b758105b5c7
lock: add a trylock method handling the timeout and messaging logic
Boris Feld <boris.feld@octobus.net>
parents:
32088
diff
changeset
|
146 if l.delay: |
35209
9153871d50e0
lock: allow to configure when the lock messages are displayed
Boris Feld <boris.feld@octobus.net>
parents:
35208
diff
changeset
|
147 if 0 <= warningidx <= l.delay: |
36319
c303eda316be
lock: delay is numeric, use %d for formatting
Augie Fackler <augie@google.com>
parents:
35897
diff
changeset
|
148 ui.warn(_("got lock after %d seconds\n") % l.delay) |
35209
9153871d50e0
lock: allow to configure when the lock messages are displayed
Boris Feld <boris.feld@octobus.net>
parents:
35208
diff
changeset
|
149 else: |
36319
c303eda316be
lock: delay is numeric, use %d for formatting
Augie Fackler <augie@google.com>
parents:
35897
diff
changeset
|
150 ui.debug("got lock after %d seconds\n" % l.delay) |
35208
1b758105b5c7
lock: add a trylock method handling the timeout and messaging logic
Boris Feld <boris.feld@octobus.net>
parents:
32088
diff
changeset
|
151 if l.acquirefn: |
1b758105b5c7
lock: add a trylock method handling the timeout and messaging logic
Boris Feld <boris.feld@octobus.net>
parents:
32088
diff
changeset
|
152 l.acquirefn() |
1b758105b5c7
lock: add a trylock method handling the timeout and messaging logic
Boris Feld <boris.feld@octobus.net>
parents:
32088
diff
changeset
|
153 return l |
1b758105b5c7
lock: add a trylock method handling the timeout and messaging logic
Boris Feld <boris.feld@octobus.net>
parents:
32088
diff
changeset
|
154 |
1559
59b3639df0a9
Convert all classes to new-style classes by deriving them from object.
Eric Hopper <hopper@omnifarious.org>
parents:
1530
diff
changeset
|
155 class lock(object): |
9309
cfdcb7a465af
localrepo: document the locking scheme a little better
Greg Ward <greg-hg@gerg.ca>
parents:
8312
diff
changeset
|
156 '''An advisory lock held by one process to control access to a set |
cfdcb7a465af
localrepo: document the locking scheme a little better
Greg Ward <greg-hg@gerg.ca>
parents:
8312
diff
changeset
|
157 of files. Non-cooperating processes or incorrectly written scripts |
cfdcb7a465af
localrepo: document the locking scheme a little better
Greg Ward <greg-hg@gerg.ca>
parents:
8312
diff
changeset
|
158 can ignore Mercurial's locking scheme and stomp all over the |
cfdcb7a465af
localrepo: document the locking scheme a little better
Greg Ward <greg-hg@gerg.ca>
parents:
8312
diff
changeset
|
159 repository, so don't do that. |
cfdcb7a465af
localrepo: document the locking scheme a little better
Greg Ward <greg-hg@gerg.ca>
parents:
8312
diff
changeset
|
160 |
cfdcb7a465af
localrepo: document the locking scheme a little better
Greg Ward <greg-hg@gerg.ca>
parents:
8312
diff
changeset
|
161 Typically used via localrepository.lock() to lock the repository |
cfdcb7a465af
localrepo: document the locking scheme a little better
Greg Ward <greg-hg@gerg.ca>
parents:
8312
diff
changeset
|
162 store (.hg/store/) or localrepository.wlock() to lock everything |
cfdcb7a465af
localrepo: document the locking scheme a little better
Greg Ward <greg-hg@gerg.ca>
parents:
8312
diff
changeset
|
163 else under .hg/.''' |
cfdcb7a465af
localrepo: document the locking scheme a little better
Greg Ward <greg-hg@gerg.ca>
parents:
8312
diff
changeset
|
164 |
1877
d314a89fa4f1
change lock format to let us detect and break stale locks.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
1836
diff
changeset
|
165 # lock is symlink on platforms that support it, file on others. |
d314a89fa4f1
change lock format to let us detect and break stale locks.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
1836
diff
changeset
|
166 |
d314a89fa4f1
change lock format to let us detect and break stale locks.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
1836
diff
changeset
|
167 # symlink is used because create of directory entry and contents |
d314a89fa4f1
change lock format to let us detect and break stale locks.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
1836
diff
changeset
|
168 # are atomic even over nfs. |
d314a89fa4f1
change lock format to let us detect and break stale locks.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
1836
diff
changeset
|
169 |
d314a89fa4f1
change lock format to let us detect and break stale locks.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
1836
diff
changeset
|
170 # old-style lock: symlink to pid |
d314a89fa4f1
change lock format to let us detect and break stale locks.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
1836
diff
changeset
|
171 # new-style lock: symlink to hostname:pid |
d314a89fa4f1
change lock format to let us detect and break stale locks.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
1836
diff
changeset
|
172 |
4947
3e25a6eb5c9a
lock.py: cache hostname, but not pid, in case we fork
Bryan O'Sullivan <bos@serpentine.com>
parents:
3877
diff
changeset
|
173 _host = None |
3e25a6eb5c9a
lock.py: cache hostname, but not pid, in case we fork
Bryan O'Sullivan <bos@serpentine.com>
parents:
3877
diff
changeset
|
174 |
26321
db4c192cb9b3
lock: move acquirefn call to inside the lock
Siddharth Agarwal <sid0@fb.com>
parents:
26291
diff
changeset
|
175 def __init__(self, vfs, file, timeout=-1, releasefn=None, acquirefn=None, |
35208
1b758105b5c7
lock: add a trylock method handling the timeout and messaging logic
Boris Feld <boris.feld@octobus.net>
parents:
32088
diff
changeset
|
176 desc=None, inheritchecker=None, parentlock=None, |
1b758105b5c7
lock: add a trylock method handling the timeout and messaging logic
Boris Feld <boris.feld@octobus.net>
parents:
32088
diff
changeset
|
177 dolock=True): |
20091
abfe6a8e619b
lock: take both vfs and lock file path relative to vfs to access via vfs
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
19927
diff
changeset
|
178 self.vfs = vfs |
161 | 179 self.f = file |
180 self.held = 0 | |
1787
e431344e604c
add a timeout when a lock is held (default 1024 sec)
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents:
1753
diff
changeset
|
181 self.timeout = timeout |
1530
abfab59fce79
add a releasefn keyword to lock.lock
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents:
1062
diff
changeset
|
182 self.releasefn = releasefn |
26321
db4c192cb9b3
lock: move acquirefn call to inside the lock
Siddharth Agarwal <sid0@fb.com>
parents:
26291
diff
changeset
|
183 self.acquirefn = acquirefn |
2016
ff5c9a92f556
fix backtrace printed when cannot get lock.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
1877
diff
changeset
|
184 self.desc = desc |
26498
e8564e04382d
lock: add a way to prevent locks from being inherited
Siddharth Agarwal <sid0@fb.com>
parents:
26474
diff
changeset
|
185 self._inheritchecker = inheritchecker |
26356
927fa07a2ba4
lock: introduce state to keep track of inheritance
Siddharth Agarwal <sid0@fb.com>
parents:
26321
diff
changeset
|
186 self.parentlock = parentlock |
927fa07a2ba4
lock: introduce state to keep track of inheritance
Siddharth Agarwal <sid0@fb.com>
parents:
26321
diff
changeset
|
187 self._parentheld = False |
927fa07a2ba4
lock: introduce state to keep track of inheritance
Siddharth Agarwal <sid0@fb.com>
parents:
26321
diff
changeset
|
188 self._inherited = False |
15589
cc24e4ed3e0c
lock: change name of release chain
Matt Mackall <mpm@selenic.com>
parents:
15583
diff
changeset
|
189 self.postrelease = [] |
26383
0fceb34806e1
lock: add a wrapper to os.getpid() to make testing easier
Siddharth Agarwal <sid0@fb.com>
parents:
26359
diff
changeset
|
190 self.pid = self._getpid() |
35208
1b758105b5c7
lock: add a trylock method handling the timeout and messaging logic
Boris Feld <boris.feld@octobus.net>
parents:
32088
diff
changeset
|
191 if dolock: |
1b758105b5c7
lock: add a trylock method handling the timeout and messaging logic
Boris Feld <boris.feld@octobus.net>
parents:
32088
diff
changeset
|
192 self.delay = self.lock() |
1b758105b5c7
lock: add a trylock method handling the timeout and messaging logic
Boris Feld <boris.feld@octobus.net>
parents:
32088
diff
changeset
|
193 if self.acquirefn: |
1b758105b5c7
lock: add a trylock method handling the timeout and messaging logic
Boris Feld <boris.feld@octobus.net>
parents:
32088
diff
changeset
|
194 self.acquirefn() |
161 | 195 |
27797
054abf2377e8
lock: turn a lock into a Python context manager
Bryan O'Sullivan <bryano@fb.com>
parents:
26498
diff
changeset
|
196 def __enter__(self): |
054abf2377e8
lock: turn a lock into a Python context manager
Bryan O'Sullivan <bryano@fb.com>
parents:
26498
diff
changeset
|
197 return self |
054abf2377e8
lock: turn a lock into a Python context manager
Bryan O'Sullivan <bryano@fb.com>
parents:
26498
diff
changeset
|
198 |
054abf2377e8
lock: turn a lock into a Python context manager
Bryan O'Sullivan <bryano@fb.com>
parents:
26498
diff
changeset
|
199 def __exit__(self, exc_type, exc_value, exc_tb): |
054abf2377e8
lock: turn a lock into a Python context manager
Bryan O'Sullivan <bryano@fb.com>
parents:
26498
diff
changeset
|
200 self.release() |
054abf2377e8
lock: turn a lock into a Python context manager
Bryan O'Sullivan <bryano@fb.com>
parents:
26498
diff
changeset
|
201 |
161 | 202 def __del__(self): |
8108
a26d33749bd8
made repo locks recursive and deprecate refcounting based lock releasing
Ronny Pfannschmidt <Ronny.Pfannschmidt@gmx.de>
parents:
7640
diff
changeset
|
203 if self.held: |
8113
87a1605979e4
add a deprecation warning for gc based lock releasing
Ronny Pfannschmidt <Ronny.Pfannschmidt@gmx.de>
parents:
8108
diff
changeset
|
204 warnings.warn("use lock.release instead of del lock", |
87a1605979e4
add a deprecation warning for gc based lock releasing
Ronny Pfannschmidt <Ronny.Pfannschmidt@gmx.de>
parents:
8108
diff
changeset
|
205 category=DeprecationWarning, |
87a1605979e4
add a deprecation warning for gc based lock releasing
Ronny Pfannschmidt <Ronny.Pfannschmidt@gmx.de>
parents:
8108
diff
changeset
|
206 stacklevel=2) |
87a1605979e4
add a deprecation warning for gc based lock releasing
Ronny Pfannschmidt <Ronny.Pfannschmidt@gmx.de>
parents:
8108
diff
changeset
|
207 |
8108
a26d33749bd8
made repo locks recursive and deprecate refcounting based lock releasing
Ronny Pfannschmidt <Ronny.Pfannschmidt@gmx.de>
parents:
7640
diff
changeset
|
208 # ensure the lock will be removed |
a26d33749bd8
made repo locks recursive and deprecate refcounting based lock releasing
Ronny Pfannschmidt <Ronny.Pfannschmidt@gmx.de>
parents:
7640
diff
changeset
|
209 # even if recursive locking did occur |
a26d33749bd8
made repo locks recursive and deprecate refcounting based lock releasing
Ronny Pfannschmidt <Ronny.Pfannschmidt@gmx.de>
parents:
7640
diff
changeset
|
210 self.held = 1 |
a26d33749bd8
made repo locks recursive and deprecate refcounting based lock releasing
Ronny Pfannschmidt <Ronny.Pfannschmidt@gmx.de>
parents:
7640
diff
changeset
|
211 |
161 | 212 self.release() |
213 | |
26383
0fceb34806e1
lock: add a wrapper to os.getpid() to make testing easier
Siddharth Agarwal <sid0@fb.com>
parents:
26359
diff
changeset
|
214 def _getpid(self): |
28027
14033c5dd261
util: enable getpid to be replaced
timeless <timeless@mozdev.org>
parents:
27797
diff
changeset
|
215 # wrapper around util.getpid() to make testing easier |
14033c5dd261
util: enable getpid to be replaced
timeless <timeless@mozdev.org>
parents:
27797
diff
changeset
|
216 return util.getpid() |
26383
0fceb34806e1
lock: add a wrapper to os.getpid() to make testing easier
Siddharth Agarwal <sid0@fb.com>
parents:
26359
diff
changeset
|
217 |
161 | 218 def lock(self): |
1787
e431344e604c
add a timeout when a lock is held (default 1024 sec)
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents:
1753
diff
changeset
|
219 timeout = self.timeout |
14494
1ffeeb91c55d
check-code: flag 0/1 used as constant Boolean expression
Martin Geisler <mg@lazybytes.net>
parents:
13281
diff
changeset
|
220 while True: |
161 | 221 try: |
26082
b188f60bd955
lock: make trylock private
Matt Mackall <mpm@selenic.com>
parents:
26081
diff
changeset
|
222 self._trylock() |
20380
c697b70f295f
localrepo: give a sigh of relief when getting lock after waiting for it
Mads Kiilerich <madski@unity3d.com>
parents:
20091
diff
changeset
|
223 return self.timeout - timeout |
25660
328739ea70c3
global: mass rewrite to use modern exception syntax
Gregory Szorc <gregory.szorc@gmail.com>
parents:
23032
diff
changeset
|
224 except error.LockHeld as inst: |
1787
e431344e604c
add a timeout when a lock is held (default 1024 sec)
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents:
1753
diff
changeset
|
225 if timeout != 0: |
161 | 226 time.sleep(1) |
1787
e431344e604c
add a timeout when a lock is held (default 1024 sec)
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents:
1753
diff
changeset
|
227 if timeout > 0: |
e431344e604c
add a timeout when a lock is held (default 1024 sec)
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents:
1753
diff
changeset
|
228 timeout -= 1 |
161 | 229 continue |
7640 | 230 raise error.LockHeld(errno.ETIMEDOUT, inst.filename, self.desc, |
231 inst.locker) | |
515 | 232 |
26082
b188f60bd955
lock: make trylock private
Matt Mackall <mpm@selenic.com>
parents:
26081
diff
changeset
|
233 def _trylock(self): |
8108
a26d33749bd8
made repo locks recursive and deprecate refcounting based lock releasing
Ronny Pfannschmidt <Ronny.Pfannschmidt@gmx.de>
parents:
7640
diff
changeset
|
234 if self.held: |
a26d33749bd8
made repo locks recursive and deprecate refcounting based lock releasing
Ronny Pfannschmidt <Ronny.Pfannschmidt@gmx.de>
parents:
7640
diff
changeset
|
235 self.held += 1 |
a26d33749bd8
made repo locks recursive and deprecate refcounting based lock releasing
Ronny Pfannschmidt <Ronny.Pfannschmidt@gmx.de>
parents:
7640
diff
changeset
|
236 return |
4947
3e25a6eb5c9a
lock.py: cache hostname, but not pid, in case we fork
Bryan O'Sullivan <bos@serpentine.com>
parents:
3877
diff
changeset
|
237 if lock._host is None: |
30920
dc9f086c7691
lock: move lock._host calculation to a function
Jun Wu <quark@fb.com>
parents:
28959
diff
changeset
|
238 lock._host = _getlockprefix() |
31354
e6a2b625e0d9
lock: use %d to format integer into a bytestring
Augie Fackler <augie@google.com>
parents:
30921
diff
changeset
|
239 lockname = '%s:%d' % (lock._host, self.pid) |
26081
3b6e5914edd8
lock: loop a finite number of times in trylock (issue4787)
Matt Mackall <mpm@selenic.com>
parents:
25956
diff
changeset
|
240 retry = 5 |
3b6e5914edd8
lock: loop a finite number of times in trylock (issue4787)
Matt Mackall <mpm@selenic.com>
parents:
25956
diff
changeset
|
241 while not self.held and retry: |
3b6e5914edd8
lock: loop a finite number of times in trylock (issue4787)
Matt Mackall <mpm@selenic.com>
parents:
25956
diff
changeset
|
242 retry -= 1 |
1877
d314a89fa4f1
change lock format to let us detect and break stale locks.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
1836
diff
changeset
|
243 try: |
36701
d77c3b023393
lock: block signal interrupt while making a lock file
Yuya Nishihara <yuya@tcha.org>
parents:
36657
diff
changeset
|
244 with _delayedinterrupt(): |
d77c3b023393
lock: block signal interrupt while making a lock file
Yuya Nishihara <yuya@tcha.org>
parents:
36657
diff
changeset
|
245 self.vfs.makelock(lockname, self.f) |
d77c3b023393
lock: block signal interrupt while making a lock file
Yuya Nishihara <yuya@tcha.org>
parents:
36657
diff
changeset
|
246 self.held = 1 |
25660
328739ea70c3
global: mass rewrite to use modern exception syntax
Gregory Szorc <gregory.szorc@gmail.com>
parents:
23032
diff
changeset
|
247 except (OSError, IOError) as why: |
1877
d314a89fa4f1
change lock format to let us detect and break stale locks.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
1836
diff
changeset
|
248 if why.errno == errno.EEXIST: |
26387
e16f80f89a29
lock: recognize parent locks while acquiring
Siddharth Agarwal <sid0@fb.com>
parents:
26383
diff
changeset
|
249 locker = self._readlock() |
32087
e1938d6051da
lock: avoid unintentional lock acquisition at failure of readlock
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
31378
diff
changeset
|
250 if locker is None: |
e1938d6051da
lock: avoid unintentional lock acquisition at failure of readlock
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
31378
diff
changeset
|
251 continue |
e1938d6051da
lock: avoid unintentional lock acquisition at failure of readlock
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
31378
diff
changeset
|
252 |
26387
e16f80f89a29
lock: recognize parent locks while acquiring
Siddharth Agarwal <sid0@fb.com>
parents:
26383
diff
changeset
|
253 # special case where a parent process holds the lock -- this |
e16f80f89a29
lock: recognize parent locks while acquiring
Siddharth Agarwal <sid0@fb.com>
parents:
26383
diff
changeset
|
254 # is different from the pid being different because we do |
e16f80f89a29
lock: recognize parent locks while acquiring
Siddharth Agarwal <sid0@fb.com>
parents:
26383
diff
changeset
|
255 # want the unlock and postrelease functions to be called, |
e16f80f89a29
lock: recognize parent locks while acquiring
Siddharth Agarwal <sid0@fb.com>
parents:
26383
diff
changeset
|
256 # but the lockfile to not be removed. |
e16f80f89a29
lock: recognize parent locks while acquiring
Siddharth Agarwal <sid0@fb.com>
parents:
26383
diff
changeset
|
257 if locker == self.parentlock: |
e16f80f89a29
lock: recognize parent locks while acquiring
Siddharth Agarwal <sid0@fb.com>
parents:
26383
diff
changeset
|
258 self._parentheld = True |
e16f80f89a29
lock: recognize parent locks while acquiring
Siddharth Agarwal <sid0@fb.com>
parents:
26383
diff
changeset
|
259 self.held = 1 |
e16f80f89a29
lock: recognize parent locks while acquiring
Siddharth Agarwal <sid0@fb.com>
parents:
26383
diff
changeset
|
260 return |
e16f80f89a29
lock: recognize parent locks while acquiring
Siddharth Agarwal <sid0@fb.com>
parents:
26383
diff
changeset
|
261 locker = self._testlock(locker) |
3686
4308f4cdc07b
Don't step into an endless loop when lock file is empty.
Thomas Arendsen Hein <thomas@intevation.de>
parents:
2859
diff
changeset
|
262 if locker is not None: |
36657
214f61abd865
py3: back out c77c925987d7 to store bytes filename in IOError
Yuya Nishihara <yuya@tcha.org>
parents:
36642
diff
changeset
|
263 raise error.LockHeld(errno.EAGAIN, |
214f61abd865
py3: back out c77c925987d7 to store bytes filename in IOError
Yuya Nishihara <yuya@tcha.org>
parents:
36642
diff
changeset
|
264 self.vfs.join(self.f), self.desc, |
214f61abd865
py3: back out c77c925987d7 to store bytes filename in IOError
Yuya Nishihara <yuya@tcha.org>
parents:
36642
diff
changeset
|
265 locker) |
1877
d314a89fa4f1
change lock format to let us detect and break stale locks.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
1836
diff
changeset
|
266 else: |
7640 | 267 raise error.LockUnavailable(why.errno, why.strerror, |
268 why.filename, self.desc) | |
1877
d314a89fa4f1
change lock format to let us detect and break stale locks.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
1836
diff
changeset
|
269 |
32088
0d892d820a51
lock: avoid unintentional lock acquisition at failure of readlock
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
32087
diff
changeset
|
270 if not self.held: |
0d892d820a51
lock: avoid unintentional lock acquisition at failure of readlock
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
32087
diff
changeset
|
271 # use empty locker to mean "busy for frequent lock/unlock |
0d892d820a51
lock: avoid unintentional lock acquisition at failure of readlock
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
32087
diff
changeset
|
272 # by many processes" |
0d892d820a51
lock: avoid unintentional lock acquisition at failure of readlock
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
32087
diff
changeset
|
273 raise error.LockHeld(errno.EAGAIN, |
36657
214f61abd865
py3: back out c77c925987d7 to store bytes filename in IOError
Yuya Nishihara <yuya@tcha.org>
parents:
36642
diff
changeset
|
274 self.vfs.join(self.f), self.desc, "") |
32088
0d892d820a51
lock: avoid unintentional lock acquisition at failure of readlock
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
32087
diff
changeset
|
275 |
26290
9664d32bd6cb
lock: factor code to read lock into a separate function
Siddharth Agarwal <sid0@fb.com>
parents:
26082
diff
changeset
|
276 def _readlock(self): |
9664d32bd6cb
lock: factor code to read lock into a separate function
Siddharth Agarwal <sid0@fb.com>
parents:
26082
diff
changeset
|
277 """read lock and return its value |
9664d32bd6cb
lock: factor code to read lock into a separate function
Siddharth Agarwal <sid0@fb.com>
parents:
26082
diff
changeset
|
278 |
9664d32bd6cb
lock: factor code to read lock into a separate function
Siddharth Agarwal <sid0@fb.com>
parents:
26082
diff
changeset
|
279 Returns None if no lock exists, pid for old-style locks, and host:pid |
9664d32bd6cb
lock: factor code to read lock into a separate function
Siddharth Agarwal <sid0@fb.com>
parents:
26082
diff
changeset
|
280 for new-style locks. |
9664d32bd6cb
lock: factor code to read lock into a separate function
Siddharth Agarwal <sid0@fb.com>
parents:
26082
diff
changeset
|
281 """ |
9664d32bd6cb
lock: factor code to read lock into a separate function
Siddharth Agarwal <sid0@fb.com>
parents:
26082
diff
changeset
|
282 try: |
9664d32bd6cb
lock: factor code to read lock into a separate function
Siddharth Agarwal <sid0@fb.com>
parents:
26082
diff
changeset
|
283 return self.vfs.readlock(self.f) |
9664d32bd6cb
lock: factor code to read lock into a separate function
Siddharth Agarwal <sid0@fb.com>
parents:
26082
diff
changeset
|
284 except (OSError, IOError) as why: |
9664d32bd6cb
lock: factor code to read lock into a separate function
Siddharth Agarwal <sid0@fb.com>
parents:
26082
diff
changeset
|
285 if why.errno == errno.ENOENT: |
9664d32bd6cb
lock: factor code to read lock into a separate function
Siddharth Agarwal <sid0@fb.com>
parents:
26082
diff
changeset
|
286 return None |
9664d32bd6cb
lock: factor code to read lock into a separate function
Siddharth Agarwal <sid0@fb.com>
parents:
26082
diff
changeset
|
287 raise |
9664d32bd6cb
lock: factor code to read lock into a separate function
Siddharth Agarwal <sid0@fb.com>
parents:
26082
diff
changeset
|
288 |
26291
1d33842c5b3e
lock: factor out lock testing into a separate function
Siddharth Agarwal <sid0@fb.com>
parents:
26290
diff
changeset
|
289 def _testlock(self, locker): |
26290
9664d32bd6cb
lock: factor code to read lock into a separate function
Siddharth Agarwal <sid0@fb.com>
parents:
26082
diff
changeset
|
290 if locker is None: |
9664d32bd6cb
lock: factor code to read lock into a separate function
Siddharth Agarwal <sid0@fb.com>
parents:
26082
diff
changeset
|
291 return None |
2579
0875cda033fd
use __contains__, index or split instead of str.find
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents:
2016
diff
changeset
|
292 try: |
0875cda033fd
use __contains__, index or split instead of str.find
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents:
2016
diff
changeset
|
293 host, pid = locker.split(":", 1) |
0875cda033fd
use __contains__, index or split instead of str.find
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents:
2016
diff
changeset
|
294 except ValueError: |
1877
d314a89fa4f1
change lock format to let us detect and break stale locks.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
1836
diff
changeset
|
295 return locker |
4947
3e25a6eb5c9a
lock.py: cache hostname, but not pid, in case we fork
Bryan O'Sullivan <bos@serpentine.com>
parents:
3877
diff
changeset
|
296 if host != lock._host: |
1877
d314a89fa4f1
change lock format to let us detect and break stale locks.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
1836
diff
changeset
|
297 return locker |
161 | 298 try: |
2579
0875cda033fd
use __contains__, index or split instead of str.find
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents:
2016
diff
changeset
|
299 pid = int(pid) |
9685
a820cd39d415
lock: catch specific exceptions
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents:
9680
diff
changeset
|
300 except ValueError: |
1877
d314a89fa4f1
change lock format to let us detect and break stale locks.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
1836
diff
changeset
|
301 return locker |
d314a89fa4f1
change lock format to let us detect and break stale locks.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
1836
diff
changeset
|
302 if util.testpid(pid): |
d314a89fa4f1
change lock format to let us detect and break stale locks.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
1836
diff
changeset
|
303 return locker |
d314a89fa4f1
change lock format to let us detect and break stale locks.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
1836
diff
changeset
|
304 # if locker dead, break lock. must do this with another lock |
d314a89fa4f1
change lock format to let us detect and break stale locks.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
1836
diff
changeset
|
305 # held, or can race and break valid lock. |
d314a89fa4f1
change lock format to let us detect and break stale locks.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
1836
diff
changeset
|
306 try: |
20091
abfe6a8e619b
lock: take both vfs and lock file path relative to vfs to access via vfs
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
19927
diff
changeset
|
307 l = lock(self.vfs, self.f + '.break', timeout=0) |
abfe6a8e619b
lock: take both vfs and lock file path relative to vfs to access via vfs
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
19927
diff
changeset
|
308 self.vfs.unlink(self.f) |
1877
d314a89fa4f1
change lock format to let us detect and break stale locks.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
1836
diff
changeset
|
309 l.release() |
7640 | 310 except error.LockError: |
1877
d314a89fa4f1
change lock format to let us detect and break stale locks.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
1836
diff
changeset
|
311 return locker |
161 | 312 |
26291
1d33842c5b3e
lock: factor out lock testing into a separate function
Siddharth Agarwal <sid0@fb.com>
parents:
26290
diff
changeset
|
313 def testlock(self): |
1d33842c5b3e
lock: factor out lock testing into a separate function
Siddharth Agarwal <sid0@fb.com>
parents:
26290
diff
changeset
|
314 """return id of locker if lock is valid, else None. |
1d33842c5b3e
lock: factor out lock testing into a separate function
Siddharth Agarwal <sid0@fb.com>
parents:
26290
diff
changeset
|
315 |
1d33842c5b3e
lock: factor out lock testing into a separate function
Siddharth Agarwal <sid0@fb.com>
parents:
26290
diff
changeset
|
316 If old-style lock, we cannot tell what machine locker is on. |
1d33842c5b3e
lock: factor out lock testing into a separate function
Siddharth Agarwal <sid0@fb.com>
parents:
26290
diff
changeset
|
317 with new-style lock, if locker is on this machine, we can |
1d33842c5b3e
lock: factor out lock testing into a separate function
Siddharth Agarwal <sid0@fb.com>
parents:
26290
diff
changeset
|
318 see if locker is alive. If locker is on this machine but |
1d33842c5b3e
lock: factor out lock testing into a separate function
Siddharth Agarwal <sid0@fb.com>
parents:
26290
diff
changeset
|
319 not alive, we can safely break lock. |
1d33842c5b3e
lock: factor out lock testing into a separate function
Siddharth Agarwal <sid0@fb.com>
parents:
26290
diff
changeset
|
320 |
1d33842c5b3e
lock: factor out lock testing into a separate function
Siddharth Agarwal <sid0@fb.com>
parents:
26290
diff
changeset
|
321 The lock file is only deleted when None is returned. |
1d33842c5b3e
lock: factor out lock testing into a separate function
Siddharth Agarwal <sid0@fb.com>
parents:
26290
diff
changeset
|
322 |
1d33842c5b3e
lock: factor out lock testing into a separate function
Siddharth Agarwal <sid0@fb.com>
parents:
26290
diff
changeset
|
323 """ |
1d33842c5b3e
lock: factor out lock testing into a separate function
Siddharth Agarwal <sid0@fb.com>
parents:
26290
diff
changeset
|
324 locker = self._readlock() |
1d33842c5b3e
lock: factor out lock testing into a separate function
Siddharth Agarwal <sid0@fb.com>
parents:
26290
diff
changeset
|
325 return self._testlock(locker) |
1d33842c5b3e
lock: factor out lock testing into a separate function
Siddharth Agarwal <sid0@fb.com>
parents:
26290
diff
changeset
|
326 |
26473
5f94e64f182c
lock: turn prepinherit/reacquire into a single context manager
Siddharth Agarwal <sid0@fb.com>
parents:
26387
diff
changeset
|
327 @contextlib.contextmanager |
5f94e64f182c
lock: turn prepinherit/reacquire into a single context manager
Siddharth Agarwal <sid0@fb.com>
parents:
26387
diff
changeset
|
328 def inherit(self): |
5f94e64f182c
lock: turn prepinherit/reacquire into a single context manager
Siddharth Agarwal <sid0@fb.com>
parents:
26387
diff
changeset
|
329 """context for the lock to be inherited by a Mercurial subprocess. |
26357
6979a1369185
lock: add a method to prepare the lock for inheritance
Siddharth Agarwal <sid0@fb.com>
parents:
26356
diff
changeset
|
330 |
26473
5f94e64f182c
lock: turn prepinherit/reacquire into a single context manager
Siddharth Agarwal <sid0@fb.com>
parents:
26387
diff
changeset
|
331 Yields a string that will be recognized by the lock in the subprocess. |
5f94e64f182c
lock: turn prepinherit/reacquire into a single context manager
Siddharth Agarwal <sid0@fb.com>
parents:
26387
diff
changeset
|
332 Communicating this string to the subprocess needs to be done separately |
5f94e64f182c
lock: turn prepinherit/reacquire into a single context manager
Siddharth Agarwal <sid0@fb.com>
parents:
26387
diff
changeset
|
333 -- typically by an environment variable. |
26357
6979a1369185
lock: add a method to prepare the lock for inheritance
Siddharth Agarwal <sid0@fb.com>
parents:
26356
diff
changeset
|
334 """ |
6979a1369185
lock: add a method to prepare the lock for inheritance
Siddharth Agarwal <sid0@fb.com>
parents:
26356
diff
changeset
|
335 if not self.held: |
6979a1369185
lock: add a method to prepare the lock for inheritance
Siddharth Agarwal <sid0@fb.com>
parents:
26356
diff
changeset
|
336 raise error.LockInheritanceContractViolation( |
26473
5f94e64f182c
lock: turn prepinherit/reacquire into a single context manager
Siddharth Agarwal <sid0@fb.com>
parents:
26387
diff
changeset
|
337 'inherit can only be called while lock is held') |
26357
6979a1369185
lock: add a method to prepare the lock for inheritance
Siddharth Agarwal <sid0@fb.com>
parents:
26356
diff
changeset
|
338 if self._inherited: |
6979a1369185
lock: add a method to prepare the lock for inheritance
Siddharth Agarwal <sid0@fb.com>
parents:
26356
diff
changeset
|
339 raise error.LockInheritanceContractViolation( |
26473
5f94e64f182c
lock: turn prepinherit/reacquire into a single context manager
Siddharth Agarwal <sid0@fb.com>
parents:
26387
diff
changeset
|
340 'inherit cannot be called while lock is already inherited') |
26498
e8564e04382d
lock: add a way to prevent locks from being inherited
Siddharth Agarwal <sid0@fb.com>
parents:
26474
diff
changeset
|
341 if self._inheritchecker is not None: |
e8564e04382d
lock: add a way to prevent locks from being inherited
Siddharth Agarwal <sid0@fb.com>
parents:
26474
diff
changeset
|
342 self._inheritchecker() |
26357
6979a1369185
lock: add a method to prepare the lock for inheritance
Siddharth Agarwal <sid0@fb.com>
parents:
26356
diff
changeset
|
343 if self.releasefn: |
6979a1369185
lock: add a method to prepare the lock for inheritance
Siddharth Agarwal <sid0@fb.com>
parents:
26356
diff
changeset
|
344 self.releasefn() |
6979a1369185
lock: add a method to prepare the lock for inheritance
Siddharth Agarwal <sid0@fb.com>
parents:
26356
diff
changeset
|
345 if self._parentheld: |
6979a1369185
lock: add a method to prepare the lock for inheritance
Siddharth Agarwal <sid0@fb.com>
parents:
26356
diff
changeset
|
346 lockname = self.parentlock |
6979a1369185
lock: add a method to prepare the lock for inheritance
Siddharth Agarwal <sid0@fb.com>
parents:
26356
diff
changeset
|
347 else: |
6979a1369185
lock: add a method to prepare the lock for inheritance
Siddharth Agarwal <sid0@fb.com>
parents:
26356
diff
changeset
|
348 lockname = '%s:%s' % (lock._host, self.pid) |
6979a1369185
lock: add a method to prepare the lock for inheritance
Siddharth Agarwal <sid0@fb.com>
parents:
26356
diff
changeset
|
349 self._inherited = True |
26473
5f94e64f182c
lock: turn prepinherit/reacquire into a single context manager
Siddharth Agarwal <sid0@fb.com>
parents:
26387
diff
changeset
|
350 try: |
5f94e64f182c
lock: turn prepinherit/reacquire into a single context manager
Siddharth Agarwal <sid0@fb.com>
parents:
26387
diff
changeset
|
351 yield lockname |
5f94e64f182c
lock: turn prepinherit/reacquire into a single context manager
Siddharth Agarwal <sid0@fb.com>
parents:
26387
diff
changeset
|
352 finally: |
5f94e64f182c
lock: turn prepinherit/reacquire into a single context manager
Siddharth Agarwal <sid0@fb.com>
parents:
26387
diff
changeset
|
353 if self.acquirefn: |
5f94e64f182c
lock: turn prepinherit/reacquire into a single context manager
Siddharth Agarwal <sid0@fb.com>
parents:
26387
diff
changeset
|
354 self.acquirefn() |
5f94e64f182c
lock: turn prepinherit/reacquire into a single context manager
Siddharth Agarwal <sid0@fb.com>
parents:
26387
diff
changeset
|
355 self._inherited = False |
26358
de5a52e5eb9e
lock: add a method to reacquire the lock after subprocesses exit
Siddharth Agarwal <sid0@fb.com>
parents:
26357
diff
changeset
|
356 |
161 | 357 def release(self): |
15583
926a06f7a353
lock: add mechanism to register post release callback
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents:
14494
diff
changeset
|
358 """release the lock and execute callback function if any |
926a06f7a353
lock: add mechanism to register post release callback
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents:
14494
diff
changeset
|
359 |
17537 | 360 If the lock has been acquired multiple times, the actual release is |
17510 | 361 delayed to the last release call.""" |
8108
a26d33749bd8
made repo locks recursive and deprecate refcounting based lock releasing
Ronny Pfannschmidt <Ronny.Pfannschmidt@gmx.de>
parents:
7640
diff
changeset
|
362 if self.held > 1: |
a26d33749bd8
made repo locks recursive and deprecate refcounting based lock releasing
Ronny Pfannschmidt <Ronny.Pfannschmidt@gmx.de>
parents:
7640
diff
changeset
|
363 self.held -= 1 |
9680
8cea86d73887
lock: use '==' instead of 'is' for integer equality ('is' may not work)
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents:
9309
diff
changeset
|
364 elif self.held == 1: |
161 | 365 self.held = 0 |
26383
0fceb34806e1
lock: add a wrapper to os.getpid() to make testing easier
Siddharth Agarwal <sid0@fb.com>
parents:
26359
diff
changeset
|
366 if self._getpid() != self.pid: |
18907
af9fa8d4c939
lock: if we fork, ensure that only the parent releases
Bryan O'Sullivan <bryano@fb.com>
parents:
17683
diff
changeset
|
367 # we forked, and are not the parent |
af9fa8d4c939
lock: if we fork, ensure that only the parent releases
Bryan O'Sullivan <bryano@fb.com>
parents:
17683
diff
changeset
|
368 return |
503
c6a2e41c8c60
Fix troubles with clone and exception handling
mpm@selenic.com
parents:
429
diff
changeset
|
369 try: |
23032
f484be02bd35
lock: while releasing, unlink lockfile even if the release function throws
Siddharth Agarwal <sid0@fb.com>
parents:
20380
diff
changeset
|
370 if self.releasefn: |
f484be02bd35
lock: while releasing, unlink lockfile even if the release function throws
Siddharth Agarwal <sid0@fb.com>
parents:
20380
diff
changeset
|
371 self.releasefn() |
f484be02bd35
lock: while releasing, unlink lockfile even if the release function throws
Siddharth Agarwal <sid0@fb.com>
parents:
20380
diff
changeset
|
372 finally: |
26359
c545d51c901e
lock.release: do not unlink inherited locks
Siddharth Agarwal <sid0@fb.com>
parents:
26358
diff
changeset
|
373 if not self._parentheld: |
c545d51c901e
lock.release: do not unlink inherited locks
Siddharth Agarwal <sid0@fb.com>
parents:
26358
diff
changeset
|
374 try: |
c545d51c901e
lock.release: do not unlink inherited locks
Siddharth Agarwal <sid0@fb.com>
parents:
26358
diff
changeset
|
375 self.vfs.unlink(self.f) |
c545d51c901e
lock.release: do not unlink inherited locks
Siddharth Agarwal <sid0@fb.com>
parents:
26358
diff
changeset
|
376 except OSError: |
c545d51c901e
lock.release: do not unlink inherited locks
Siddharth Agarwal <sid0@fb.com>
parents:
26358
diff
changeset
|
377 pass |
26474
431094a3b21f
lock.release: don't call postrelease functions for inherited locks
Siddharth Agarwal <sid0@fb.com>
parents:
26473
diff
changeset
|
378 # The postrelease functions typically assume the lock is not held |
431094a3b21f
lock.release: don't call postrelease functions for inherited locks
Siddharth Agarwal <sid0@fb.com>
parents:
26473
diff
changeset
|
379 # at all. |
431094a3b21f
lock.release: don't call postrelease functions for inherited locks
Siddharth Agarwal <sid0@fb.com>
parents:
26473
diff
changeset
|
380 if not self._parentheld: |
431094a3b21f
lock.release: don't call postrelease functions for inherited locks
Siddharth Agarwal <sid0@fb.com>
parents:
26473
diff
changeset
|
381 for callback in self.postrelease: |
431094a3b21f
lock.release: don't call postrelease functions for inherited locks
Siddharth Agarwal <sid0@fb.com>
parents:
26473
diff
changeset
|
382 callback() |
28959
518c3e392f75
lock: clear postrelease hooks list after usage
Gregory Szorc <gregory.szorc@gmail.com>
parents:
28027
diff
changeset
|
383 # Prevent double usage and help clear cycles. |
518c3e392f75
lock: clear postrelease hooks list after usage
Gregory Szorc <gregory.szorc@gmail.com>
parents:
28027
diff
changeset
|
384 self.postrelease = None |
161 | 385 |
8108
a26d33749bd8
made repo locks recursive and deprecate refcounting based lock releasing
Ronny Pfannschmidt <Ronny.Pfannschmidt@gmx.de>
parents:
7640
diff
changeset
|
386 def release(*locks): |
a26d33749bd8
made repo locks recursive and deprecate refcounting based lock releasing
Ronny Pfannschmidt <Ronny.Pfannschmidt@gmx.de>
parents:
7640
diff
changeset
|
387 for lock in locks: |
a26d33749bd8
made repo locks recursive and deprecate refcounting based lock releasing
Ronny Pfannschmidt <Ronny.Pfannschmidt@gmx.de>
parents:
7640
diff
changeset
|
388 if lock is not None: |
a26d33749bd8
made repo locks recursive and deprecate refcounting based lock releasing
Ronny Pfannschmidt <Ronny.Pfannschmidt@gmx.de>
parents:
7640
diff
changeset
|
389 lock.release() |