annotate mercurial/lock.py @ 2016:ff5c9a92f556

fix backtrace printed when cannot get lock. change lock error handling code so exceptions have useful info and exception handling in one place. add test case for when cannot get lock.
author Vadim Gelfer <vadim.gelfer@gmail.com>
date Tue, 28 Mar 2006 09:01:07 -0800
parents d314a89fa4f1
children
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)
d314a89fa4f1 change lock format to let us detect and break stale locks.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 1836
diff changeset
88 c = locker.find(':')
d314a89fa4f1 change lock format to let us detect and break stale locks.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 1836
diff changeset
89 if c == -1:
d314a89fa4f1 change lock format to let us detect and break stale locks.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 1836
diff changeset
90 return locker
d314a89fa4f1 change lock format to let us detect and break stale locks.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 1836
diff changeset
91 host = locker[:c]
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:
1877
d314a89fa4f1 change lock format to let us detect and break stale locks.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 1836
diff changeset
95 pid = int(locker[c+1:])
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