Mercurial > hg
comparison mercurial/lock.py @ 30921:1f151a33af8e
lock: include Linux pid namespace identifier in prefix
Previously, the lock only contains a hostname as an attempt to detect pid
namespace difference. However, that's not enough on modern Linux - a single
hostname could have different pid namespaces.
That means if people run hg inside different PID namespaces with a same UTS
namespae, the lock would be broken - an hg proccess in pid namespace A will
think the lock having a "random" pid in pid namespace B is "dead" and remove
it.
This patch solves the above issue by appending an PID namespace identifier of
the current process to the lock prefix ("hostname"). It depends on /proc
being mounted properly. But I don't think there is a better way to get pid
namespace identifier reliably.
author | Jun Wu <quark@fb.com> |
---|---|
date | Fri, 10 Feb 2017 13:56:31 -0800 |
parents | dc9f086c7691 |
children | e6a2b625e0d9 |
comparison
equal
deleted
inserted
replaced
30920:dc9f086c7691 | 30921:1f151a33af8e |
---|---|
7 | 7 |
8 from __future__ import absolute_import | 8 from __future__ import absolute_import |
9 | 9 |
10 import contextlib | 10 import contextlib |
11 import errno | 11 import errno |
12 import os | |
12 import socket | 13 import socket |
13 import time | 14 import time |
14 import warnings | 15 import warnings |
15 | 16 |
16 from . import ( | 17 from . import ( |
17 error, | 18 error, |
19 pycompat, | |
18 util, | 20 util, |
19 ) | 21 ) |
20 | 22 |
21 def _getlockprefix(): | 23 def _getlockprefix(): |
22 """Return a string which is used to differentiate pid namespaces | 24 """Return a string which is used to differentiate pid namespaces |
23 | 25 |
24 It's useful to detect "dead" processes and remove stale locks with | 26 It's useful to detect "dead" processes and remove stale locks with |
25 confidence. Typically it's just hostname. | 27 confidence. Typically it's just hostname. On modern linux, we include an |
28 extra Linux-specific pid namespace identifier. | |
26 """ | 29 """ |
27 return socket.gethostname() | 30 result = socket.gethostname() |
31 if pycompat.sysplatform.startswith('linux'): | |
32 try: | |
33 result += '/%x' % os.stat('/proc/self/ns/pid').st_ino | |
34 except OSError as ex: | |
35 if ex.errno not in (errno.ENOENT, errno.EACCES, errno.ENOTDIR): | |
36 raise | |
37 return result | |
28 | 38 |
29 class lock(object): | 39 class lock(object): |
30 '''An advisory lock held by one process to control access to a set | 40 '''An advisory lock held by one process to control access to a set |
31 of files. Non-cooperating processes or incorrectly written scripts | 41 of files. Non-cooperating processes or incorrectly written scripts |
32 can ignore Mercurial's locking scheme and stomp all over the | 42 can ignore Mercurial's locking scheme and stomp all over the |