Mercurial > hg
comparison mercurial/lock.py @ 43076:2372284d9457
formatting: blacken the codebase
This is using my patch to black
(https://github.com/psf/black/pull/826) so we don't un-wrap collection
literals.
Done with:
hg files 'set:**.py - mercurial/thirdparty/** - "contrib/python-zstandard/**"' | xargs black -S
# skip-blame mass-reformatting only
# no-check-commit reformats foo_bar functions
Differential Revision: https://phab.mercurial-scm.org/D6971
author | Augie Fackler <augie@google.com> |
---|---|
date | Sun, 06 Oct 2019 09:45:02 -0400 |
parents | ead71b15efd5 |
children | 687b865b95ad |
comparison
equal
deleted
inserted
replaced
43075:57875cf423c9 | 43076:2372284d9457 |
---|---|
22 error, | 22 error, |
23 pycompat, | 23 pycompat, |
24 util, | 24 util, |
25 ) | 25 ) |
26 | 26 |
27 from .utils import ( | 27 from .utils import procutil |
28 procutil, | 28 |
29 ) | |
30 | 29 |
31 def _getlockprefix(): | 30 def _getlockprefix(): |
32 """Return a string which is used to differentiate pid namespaces | 31 """Return a string which is used to differentiate pid namespaces |
33 | 32 |
34 It's useful to detect "dead" processes and remove stale locks with | 33 It's useful to detect "dead" processes and remove stale locks with |
41 result += '/%x' % os.stat('/proc/self/ns/pid').st_ino | 40 result += '/%x' % os.stat('/proc/self/ns/pid').st_ino |
42 except OSError as ex: | 41 except OSError as ex: |
43 if ex.errno not in (errno.ENOENT, errno.EACCES, errno.ENOTDIR): | 42 if ex.errno not in (errno.ENOENT, errno.EACCES, errno.ENOTDIR): |
44 raise | 43 raise |
45 return result | 44 return result |
45 | |
46 | 46 |
47 @contextlib.contextmanager | 47 @contextlib.contextmanager |
48 def _delayedinterrupt(): | 48 def _delayedinterrupt(): |
49 """Block signal interrupt while doing something critical | 49 """Block signal interrupt while doing something critical |
50 | 50 |
58 assertedsigs = [] | 58 assertedsigs = [] |
59 blocked = False | 59 blocked = False |
60 orighandlers = {} | 60 orighandlers = {} |
61 | 61 |
62 def raiseinterrupt(num): | 62 def raiseinterrupt(num): |
63 if (num == getattr(signal, 'SIGINT', None) or | 63 if num == getattr(signal, 'SIGINT', None) or num == getattr( |
64 num == getattr(signal, 'CTRL_C_EVENT', None)): | 64 signal, 'CTRL_C_EVENT', None |
65 ): | |
65 raise KeyboardInterrupt | 66 raise KeyboardInterrupt |
66 else: | 67 else: |
67 raise error.SignalInterrupt | 68 raise error.SignalInterrupt |
69 | |
68 def catchterm(num, frame): | 70 def catchterm(num, frame): |
69 if blocked: | 71 if blocked: |
70 assertedsigs.append(num) | 72 assertedsigs.append(num) |
71 else: | 73 else: |
72 raiseinterrupt(num) | 74 raiseinterrupt(num) |
80 orighandlers[num] = signal.getsignal(num) | 82 orighandlers[num] = signal.getsignal(num) |
81 try: | 83 try: |
82 for num in orighandlers: | 84 for num in orighandlers: |
83 signal.signal(num, catchterm) | 85 signal.signal(num, catchterm) |
84 except ValueError: | 86 except ValueError: |
85 pass # in a thread? no luck | 87 pass # in a thread? no luck |
86 | 88 |
87 blocked = True | 89 blocked = True |
88 yield | 90 yield |
89 finally: | 91 finally: |
90 # no simple way to reliably restore all signal handlers because | 92 # no simple way to reliably restore all signal handlers because |
93 blocked = False | 95 blocked = False |
94 try: | 96 try: |
95 for num, handler in orighandlers.items(): | 97 for num, handler in orighandlers.items(): |
96 signal.signal(num, handler) | 98 signal.signal(num, handler) |
97 except ValueError: | 99 except ValueError: |
98 pass # in a thread? | 100 pass # in a thread? |
99 | 101 |
100 # re-raise interrupt exception if any, which may be shadowed by a new | 102 # re-raise interrupt exception if any, which may be shadowed by a new |
101 # interrupt occurred while re-raising the first one | 103 # interrupt occurred while re-raising the first one |
102 if assertedsigs: | 104 if assertedsigs: |
103 raiseinterrupt(assertedsigs[0]) | 105 raiseinterrupt(assertedsigs[0]) |
106 | |
104 | 107 |
105 def trylock(ui, vfs, lockname, timeout, warntimeout, *args, **kwargs): | 108 def trylock(ui, vfs, lockname, timeout, warntimeout, *args, **kwargs): |
106 """return an acquired lock or raise an a LockHeld exception | 109 """return an acquired lock or raise an a LockHeld exception |
107 | 110 |
108 This function is responsible to issue warnings and or debug messages about | 111 This function is responsible to issue warnings and or debug messages about |
111 def printwarning(printer, locker): | 114 def printwarning(printer, locker): |
112 """issue the usual "waiting on lock" message through any channel""" | 115 """issue the usual "waiting on lock" message through any channel""" |
113 # show more details for new-style locks | 116 # show more details for new-style locks |
114 if ':' in locker: | 117 if ':' in locker: |
115 host, pid = locker.split(":", 1) | 118 host, pid = locker.split(":", 1) |
116 msg = (_("waiting for lock on %s held by process %r on host %r\n") | 119 msg = _( |
117 % (pycompat.bytestr(l.desc), pycompat.bytestr(pid), | 120 "waiting for lock on %s held by process %r on host %r\n" |
118 pycompat.bytestr(host))) | 121 ) % ( |
119 else: | 122 pycompat.bytestr(l.desc), |
120 msg = (_("waiting for lock on %s held by %r\n") | 123 pycompat.bytestr(pid), |
121 % (l.desc, pycompat.bytestr(locker))) | 124 pycompat.bytestr(host), |
125 ) | |
126 else: | |
127 msg = _("waiting for lock on %s held by %r\n") % ( | |
128 l.desc, | |
129 pycompat.bytestr(locker), | |
130 ) | |
122 printer(msg) | 131 printer(msg) |
123 | 132 |
124 l = lock(vfs, lockname, 0, *args, dolock=False, **kwargs) | 133 l = lock(vfs, lockname, 0, *args, dolock=False, **kwargs) |
125 | 134 |
126 debugidx = 0 if (warntimeout and timeout) else -1 | 135 debugidx = 0 if (warntimeout and timeout) else -1 |
139 if delay == debugidx: | 148 if delay == debugidx: |
140 printwarning(ui.debug, inst.locker) | 149 printwarning(ui.debug, inst.locker) |
141 if delay == warningidx: | 150 if delay == warningidx: |
142 printwarning(ui.warn, inst.locker) | 151 printwarning(ui.warn, inst.locker) |
143 if timeout <= delay: | 152 if timeout <= delay: |
144 raise error.LockHeld(errno.ETIMEDOUT, inst.filename, | 153 raise error.LockHeld( |
145 l.desc, inst.locker) | 154 errno.ETIMEDOUT, inst.filename, l.desc, inst.locker |
155 ) | |
146 time.sleep(1) | 156 time.sleep(1) |
147 delay += 1 | 157 delay += 1 |
148 | 158 |
149 l.delay = delay | 159 l.delay = delay |
150 if l.delay: | 160 if l.delay: |
153 else: | 163 else: |
154 ui.debug("got lock after %d seconds\n" % l.delay) | 164 ui.debug("got lock after %d seconds\n" % l.delay) |
155 if l.acquirefn: | 165 if l.acquirefn: |
156 l.acquirefn() | 166 l.acquirefn() |
157 return l | 167 return l |
168 | |
158 | 169 |
159 class lock(object): | 170 class lock(object): |
160 '''An advisory lock held by one process to control access to a set | 171 '''An advisory lock held by one process to control access to a set |
161 of files. Non-cooperating processes or incorrectly written scripts | 172 of files. Non-cooperating processes or incorrectly written scripts |
162 can ignore Mercurial's locking scheme and stomp all over the | 173 can ignore Mercurial's locking scheme and stomp all over the |
174 # old-style lock: symlink to pid | 185 # old-style lock: symlink to pid |
175 # new-style lock: symlink to hostname:pid | 186 # new-style lock: symlink to hostname:pid |
176 | 187 |
177 _host = None | 188 _host = None |
178 | 189 |
179 def __init__(self, vfs, fname, timeout=-1, releasefn=None, acquirefn=None, | 190 def __init__( |
180 desc=None, inheritchecker=None, parentlock=None, | 191 self, |
181 signalsafe=True, dolock=True): | 192 vfs, |
193 fname, | |
194 timeout=-1, | |
195 releasefn=None, | |
196 acquirefn=None, | |
197 desc=None, | |
198 inheritchecker=None, | |
199 parentlock=None, | |
200 signalsafe=True, | |
201 dolock=True, | |
202 ): | |
182 self.vfs = vfs | 203 self.vfs = vfs |
183 self.f = fname | 204 self.f = fname |
184 self.held = 0 | 205 self.held = 0 |
185 self.timeout = timeout | 206 self.timeout = timeout |
186 self.releasefn = releasefn | 207 self.releasefn = releasefn |
192 self._inherited = False | 213 self._inherited = False |
193 if signalsafe: | 214 if signalsafe: |
194 self._maybedelayedinterrupt = _delayedinterrupt | 215 self._maybedelayedinterrupt = _delayedinterrupt |
195 else: | 216 else: |
196 self._maybedelayedinterrupt = util.nullcontextmanager | 217 self._maybedelayedinterrupt = util.nullcontextmanager |
197 self.postrelease = [] | 218 self.postrelease = [] |
198 self.pid = self._getpid() | 219 self.pid = self._getpid() |
199 if dolock: | 220 if dolock: |
200 self.delay = self.lock() | 221 self.delay = self.lock() |
201 if self.acquirefn: | 222 if self.acquirefn: |
202 self.acquirefn() | 223 self.acquirefn() |
207 def __exit__(self, exc_type, exc_value, exc_tb): | 228 def __exit__(self, exc_type, exc_value, exc_tb): |
208 self.release() | 229 self.release() |
209 | 230 |
210 def __del__(self): | 231 def __del__(self): |
211 if self.held: | 232 if self.held: |
212 warnings.warn(r"use lock.release instead of del lock", | 233 warnings.warn( |
213 category=DeprecationWarning, | 234 r"use lock.release instead of del lock", |
214 stacklevel=2) | 235 category=DeprecationWarning, |
236 stacklevel=2, | |
237 ) | |
215 | 238 |
216 # ensure the lock will be removed | 239 # ensure the lock will be removed |
217 # even if recursive locking did occur | 240 # even if recursive locking did occur |
218 self.held = 1 | 241 self.held = 1 |
219 | 242 |
233 if timeout != 0: | 256 if timeout != 0: |
234 time.sleep(1) | 257 time.sleep(1) |
235 if timeout > 0: | 258 if timeout > 0: |
236 timeout -= 1 | 259 timeout -= 1 |
237 continue | 260 continue |
238 raise error.LockHeld(errno.ETIMEDOUT, inst.filename, self.desc, | 261 raise error.LockHeld( |
239 inst.locker) | 262 errno.ETIMEDOUT, inst.filename, self.desc, inst.locker |
263 ) | |
240 | 264 |
241 def _trylock(self): | 265 def _trylock(self): |
242 if self.held: | 266 if self.held: |
243 self.held += 1 | 267 self.held += 1 |
244 return | 268 return |
266 self._parentheld = True | 290 self._parentheld = True |
267 self.held = 1 | 291 self.held = 1 |
268 return | 292 return |
269 locker = self._testlock(locker) | 293 locker = self._testlock(locker) |
270 if locker is not None: | 294 if locker is not None: |
271 raise error.LockHeld(errno.EAGAIN, | 295 raise error.LockHeld( |
272 self.vfs.join(self.f), self.desc, | 296 errno.EAGAIN, |
273 locker) | 297 self.vfs.join(self.f), |
298 self.desc, | |
299 locker, | |
300 ) | |
274 else: | 301 else: |
275 raise error.LockUnavailable(why.errno, why.strerror, | 302 raise error.LockUnavailable( |
276 why.filename, self.desc) | 303 why.errno, why.strerror, why.filename, self.desc |
304 ) | |
277 | 305 |
278 if not self.held: | 306 if not self.held: |
279 # use empty locker to mean "busy for frequent lock/unlock | 307 # use empty locker to mean "busy for frequent lock/unlock |
280 # by many processes" | 308 # by many processes" |
281 raise error.LockHeld(errno.EAGAIN, | 309 raise error.LockHeld( |
282 self.vfs.join(self.f), self.desc, "") | 310 errno.EAGAIN, self.vfs.join(self.f), self.desc, "" |
311 ) | |
283 | 312 |
284 def _readlock(self): | 313 def _readlock(self): |
285 """read lock and return its value | 314 """read lock and return its value |
286 | 315 |
287 Returns None if no lock exists, pid for old-style locks, and host:pid | 316 Returns None if no lock exists, pid for old-style locks, and host:pid |
340 Communicating this string to the subprocess needs to be done separately | 369 Communicating this string to the subprocess needs to be done separately |
341 -- typically by an environment variable. | 370 -- typically by an environment variable. |
342 """ | 371 """ |
343 if not self.held: | 372 if not self.held: |
344 raise error.LockInheritanceContractViolation( | 373 raise error.LockInheritanceContractViolation( |
345 'inherit can only be called while lock is held') | 374 'inherit can only be called while lock is held' |
375 ) | |
346 if self._inherited: | 376 if self._inherited: |
347 raise error.LockInheritanceContractViolation( | 377 raise error.LockInheritanceContractViolation( |
348 'inherit cannot be called while lock is already inherited') | 378 'inherit cannot be called while lock is already inherited' |
379 ) | |
349 if self._inheritchecker is not None: | 380 if self._inheritchecker is not None: |
350 self._inheritchecker() | 381 self._inheritchecker() |
351 if self.releasefn: | 382 if self.releasefn: |
352 self.releasefn() | 383 self.releasefn() |
353 if self._parentheld: | 384 if self._parentheld: |
389 for callback in self.postrelease: | 420 for callback in self.postrelease: |
390 callback() | 421 callback() |
391 # Prevent double usage and help clear cycles. | 422 # Prevent double usage and help clear cycles. |
392 self.postrelease = None | 423 self.postrelease = None |
393 | 424 |
425 | |
394 def release(*locks): | 426 def release(*locks): |
395 for lock in locks: | 427 for lock in locks: |
396 if lock is not None: | 428 if lock is not None: |
397 lock.release() | 429 lock.release() |