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