annotate mercurial/lock.py @ 2837:19b3bc840182

Merge: save away mode bit so that we don't need manifest later
author Matt Mackall <mpm@selenic.com>
date Wed, 09 Aug 2006 17:11:01 -0500
parents 0875cda033fd
children 345bac2bc4ec
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
161
0b4c5cb953d9 Simply repository locking
mpm@selenic.com
parents:
diff changeset
1 # lock.py - simple locking scheme for mercurial
0b4c5cb953d9 Simply repository locking
mpm@selenic.com
parents:
diff changeset
2 #
0b4c5cb953d9 Simply repository locking
mpm@selenic.com
parents:
diff changeset
3 # Copyright 2005 Matt Mackall <mpm@selenic.com>
0b4c5cb953d9 Simply repository locking
mpm@selenic.com
parents:
diff changeset
4 #
0b4c5cb953d9 Simply repository locking
mpm@selenic.com
parents:
diff changeset
5 # This software may be used and distributed according to the terms
0b4c5cb953d9 Simply repository locking
mpm@selenic.com
parents:
diff changeset
6 # of the GNU General Public License, incorporated herein by reference.
0b4c5cb953d9 Simply repository locking
mpm@selenic.com
parents:
diff changeset
7
1836
cd5c1db2132a make lock module use demandload.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 1787
diff changeset
8 from demandload import *
1877
d314a89fa4f1 change lock format to let us detect and break stale locks.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 1836
diff changeset
9 demandload(globals(), 'errno os socket time util')
161
0b4c5cb953d9 Simply repository locking
mpm@selenic.com
parents:
diff changeset
10
2016
ff5c9a92f556 fix backtrace printed when cannot get lock.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 1877
diff changeset
11 class LockException(IOError):
ff5c9a92f556 fix backtrace printed when cannot get lock.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 1877
diff changeset
12 def __init__(self, errno, strerror, filename, desc):
ff5c9a92f556 fix backtrace printed when cannot get lock.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 1877
diff changeset
13 IOError.__init__(self, errno, strerror, filename)
ff5c9a92f556 fix backtrace printed when cannot get lock.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 1877
diff changeset
14 self.desc = desc
ff5c9a92f556 fix backtrace printed when cannot get lock.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 1877
diff changeset
15
1753
e6e70450edb9 Raise a different exception when the lock is not available
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 1559
diff changeset
16 class LockHeld(LockException):
2016
ff5c9a92f556 fix backtrace printed when cannot get lock.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 1877
diff changeset
17 def __init__(self, errno, filename, desc, locker):
ff5c9a92f556 fix backtrace printed when cannot get lock.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 1877
diff changeset
18 LockException.__init__(self, errno, 'Lock held', filename, desc)
ff5c9a92f556 fix backtrace printed when cannot get lock.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 1877
diff changeset
19 self.locker = locker
ff5c9a92f556 fix backtrace printed when cannot get lock.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 1877
diff changeset
20
1753
e6e70450edb9 Raise a different exception when the lock is not available
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 1559
diff changeset
21 class LockUnavailable(LockException):
161
0b4c5cb953d9 Simply repository locking
mpm@selenic.com
parents:
diff changeset
22 pass
0b4c5cb953d9 Simply repository locking
mpm@selenic.com
parents:
diff changeset
23
1559
59b3639df0a9 Convert all classes to new-style classes by deriving them from object.
Eric Hopper <hopper@omnifarious.org>
parents: 1530
diff changeset
24 class lock(object):
1877
d314a89fa4f1 change lock format to let us detect and break stale locks.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 1836
diff changeset
25 # 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
26
d314a89fa4f1 change lock format to let us detect and break stale locks.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 1836
diff changeset
27 # 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
28 # 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
29
d314a89fa4f1 change lock format to let us detect and break stale locks.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 1836
diff changeset
30 # 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
31 # 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
32
2016
ff5c9a92f556 fix backtrace printed when cannot get lock.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 1877
diff changeset
33 def __init__(self, file, timeout=-1, releasefn=None, desc=None):
161
0b4c5cb953d9 Simply repository locking
mpm@selenic.com
parents:
diff changeset
34 self.f = file
0b4c5cb953d9 Simply repository locking
mpm@selenic.com
parents:
diff changeset
35 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
36 self.timeout = timeout
1530
abfab59fce79 add a releasefn keyword to lock.lock
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 1062
diff changeset
37 self.releasefn = releasefn
1877
d314a89fa4f1 change lock format to let us detect and break stale locks.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 1836
diff changeset
38 self.id = None
d314a89fa4f1 change lock format to let us detect and break stale locks.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 1836
diff changeset
39 self.host = None
d314a89fa4f1 change lock format to let us detect and break stale locks.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 1836
diff changeset
40 self.pid = None
2016
ff5c9a92f556 fix backtrace printed when cannot get lock.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 1877
diff changeset
41 self.desc = desc
161
0b4c5cb953d9 Simply repository locking
mpm@selenic.com
parents:
diff changeset
42 self.lock()
0b4c5cb953d9 Simply repository locking
mpm@selenic.com
parents:
diff changeset
43
0b4c5cb953d9 Simply repository locking
mpm@selenic.com
parents:
diff changeset
44 def __del__(self):
0b4c5cb953d9 Simply repository locking
mpm@selenic.com
parents:
diff changeset
45 self.release()
0b4c5cb953d9 Simply repository locking
mpm@selenic.com
parents:
diff changeset
46
0b4c5cb953d9 Simply repository locking
mpm@selenic.com
parents:
diff changeset
47 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
48 timeout = self.timeout
161
0b4c5cb953d9 Simply repository locking
mpm@selenic.com
parents:
diff changeset
49 while 1:
0b4c5cb953d9 Simply repository locking
mpm@selenic.com
parents:
diff changeset
50 try:
0b4c5cb953d9 Simply repository locking
mpm@selenic.com
parents:
diff changeset
51 self.trylock()
0b4c5cb953d9 Simply repository locking
mpm@selenic.com
parents:
diff changeset
52 return 1
0b4c5cb953d9 Simply repository locking
mpm@selenic.com
parents:
diff changeset
53 except LockHeld, 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
54 if timeout != 0:
161
0b4c5cb953d9 Simply repository locking
mpm@selenic.com
parents:
diff changeset
55 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
56 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
57 timeout -= 1
161
0b4c5cb953d9 Simply repository locking
mpm@selenic.com
parents:
diff changeset
58 continue
2016
ff5c9a92f556 fix backtrace printed when cannot get lock.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 1877
diff changeset
59 raise LockHeld(errno.ETIMEDOUT, inst.filename, self.desc,
ff5c9a92f556 fix backtrace printed when cannot get lock.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 1877
diff changeset
60 inst.locker)
515
03f27b1381f9 Whitespace cleanups
mpm@selenic.com
parents: 503
diff changeset
61
161
0b4c5cb953d9 Simply repository locking
mpm@selenic.com
parents:
diff changeset
62 def trylock(self):
1877
d314a89fa4f1 change lock format to let us detect and break stale locks.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 1836
diff changeset
63 if self.id is None:
d314a89fa4f1 change lock format to let us detect and break stale locks.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 1836
diff changeset
64 self.host = socket.gethostname()
d314a89fa4f1 change lock format to let us detect and break stale locks.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 1836
diff changeset
65 self.pid = os.getpid()
d314a89fa4f1 change lock format to let us detect and break stale locks.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 1836
diff changeset
66 self.id = '%s:%s' % (self.host, self.pid)
d314a89fa4f1 change lock format to let us detect and break stale locks.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 1836
diff changeset
67 while not self.held:
d314a89fa4f1 change lock format to let us detect and break stale locks.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 1836
diff changeset
68 try:
d314a89fa4f1 change lock format to let us detect and break stale locks.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 1836
diff changeset
69 util.makelock(self.id, self.f)
d314a89fa4f1 change lock format to let us detect and break stale locks.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 1836
diff changeset
70 self.held = 1
d314a89fa4f1 change lock format to let us detect and break stale locks.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 1836
diff changeset
71 except (OSError, IOError), why:
d314a89fa4f1 change lock format to let us detect and break stale locks.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 1836
diff changeset
72 if why.errno == errno.EEXIST:
d314a89fa4f1 change lock format to let us detect and break stale locks.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 1836
diff changeset
73 locker = self.testlock()
d314a89fa4f1 change lock format to let us detect and break stale locks.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 1836
diff changeset
74 if locker:
2016
ff5c9a92f556 fix backtrace printed when cannot get lock.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 1877
diff changeset
75 raise LockHeld(errno.EAGAIN, self.f, self.desc,
ff5c9a92f556 fix backtrace printed when cannot get lock.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 1877
diff changeset
76 locker)
1877
d314a89fa4f1 change lock format to let us detect and break stale locks.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 1836
diff changeset
77 else:
2016
ff5c9a92f556 fix backtrace printed when cannot get lock.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 1877
diff changeset
78 raise LockUnavailable(why.errno, why.strerror,
ff5c9a92f556 fix backtrace printed when cannot get lock.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 1877
diff changeset
79 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
80
d314a89fa4f1 change lock format to let us detect and break stale locks.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 1836
diff changeset
81 def testlock(self):
d314a89fa4f1 change lock format to let us detect and break stale locks.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 1836
diff changeset
82 '''return id of locker if lock is valid, else None.'''
d314a89fa4f1 change lock format to let us detect and break stale locks.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 1836
diff changeset
83 # if old-style lock, we cannot tell what machine locker is on.
d314a89fa4f1 change lock format to let us detect and break stale locks.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 1836
diff changeset
84 # with new-style lock, if locker is on this machine, we can
d314a89fa4f1 change lock format to let us detect and break stale locks.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 1836
diff changeset
85 # see if locker is alive. if locker is on this machine but
d314a89fa4f1 change lock format to let us detect and break stale locks.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 1836
diff changeset
86 # not alive, we can safely break lock.
d314a89fa4f1 change lock format to let us detect and break stale locks.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 1836
diff changeset
87 locker = util.readlock(self.f)
2579
0875cda033fd use __contains__, index or split instead of str.find
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 2016
diff changeset
88 try:
0875cda033fd use __contains__, index or split instead of str.find
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 2016
diff changeset
89 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
90 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
91 return locker
d314a89fa4f1 change lock format to let us detect and break stale locks.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 1836
diff changeset
92 if host != self.host:
d314a89fa4f1 change lock format to let us detect and break stale locks.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 1836
diff changeset
93 return locker
161
0b4c5cb953d9 Simply repository locking
mpm@selenic.com
parents:
diff changeset
94 try:
2579
0875cda033fd use __contains__, index or split instead of str.find
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 2016
diff changeset
95 pid = int(pid)
1877
d314a89fa4f1 change lock format to let us detect and break stale locks.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 1836
diff changeset
96 except:
d314a89fa4f1 change lock format to let us detect and break stale locks.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 1836
diff changeset
97 return locker
d314a89fa4f1 change lock format to let us detect and break stale locks.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 1836
diff changeset
98 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
99 return locker
d314a89fa4f1 change lock format to let us detect and break stale locks.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 1836
diff changeset
100 # 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
101 # 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
102 try:
d314a89fa4f1 change lock format to let us detect and break stale locks.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 1836
diff changeset
103 l = lock(self.f + '.break')
d314a89fa4f1 change lock format to let us detect and break stale locks.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 1836
diff changeset
104 l.trylock()
d314a89fa4f1 change lock format to let us detect and break stale locks.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 1836
diff changeset
105 os.unlink(self.f)
d314a89fa4f1 change lock format to let us detect and break stale locks.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 1836
diff changeset
106 l.release()
d314a89fa4f1 change lock format to let us detect and break stale locks.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 1836
diff changeset
107 except (LockHeld, LockUnavailable):
d314a89fa4f1 change lock format to let us detect and break stale locks.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 1836
diff changeset
108 return locker
161
0b4c5cb953d9 Simply repository locking
mpm@selenic.com
parents:
diff changeset
109
0b4c5cb953d9 Simply repository locking
mpm@selenic.com
parents:
diff changeset
110 def release(self):
0b4c5cb953d9 Simply repository locking
mpm@selenic.com
parents:
diff changeset
111 if self.held:
0b4c5cb953d9 Simply repository locking
mpm@selenic.com
parents:
diff changeset
112 self.held = 0
1530
abfab59fce79 add a releasefn keyword to lock.lock
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 1062
diff changeset
113 if self.releasefn:
abfab59fce79 add a releasefn keyword to lock.lock
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 1062
diff changeset
114 self.releasefn()
503
c6a2e41c8c60 Fix troubles with clone and exception handling
mpm@selenic.com
parents: 429
diff changeset
115 try:
c6a2e41c8c60 Fix troubles with clone and exception handling
mpm@selenic.com
parents: 429
diff changeset
116 os.unlink(self.f)
c6a2e41c8c60 Fix troubles with clone and exception handling
mpm@selenic.com
parents: 429
diff changeset
117 except: pass
161
0b4c5cb953d9 Simply repository locking
mpm@selenic.com
parents:
diff changeset
118