Mercurial > hg
annotate mercurial/lock.py @ 4379:80c7fa620a4d
Merge with stable
author | Matt Mackall <mpm@selenic.com> |
---|---|
date | Thu, 26 Apr 2007 18:41:18 -0500 |
parents | abaee83ce0a6 |
children | 3e25a6eb5c9a |
rev | line source |
---|---|
161 | 1 # lock.py - simple locking scheme for mercurial |
2 # | |
2859 | 3 # Copyright 2005, 2006 Matt Mackall <mpm@selenic.com> |
161 | 4 # |
5 # This software may be used and distributed according to the terms | |
6 # of the GNU General Public License, incorporated herein by reference. | |
7 | |
3877
abaee83ce0a6
Replace demandload with new demandimport
Matt Mackall <mpm@selenic.com>
parents:
3686
diff
changeset
|
8 import errno, os, socket, time, util |
161 | 9 |
2016
ff5c9a92f556
fix backtrace printed when cannot get lock.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
1877
diff
changeset
|
10 class LockException(IOError): |
ff5c9a92f556
fix backtrace printed when cannot get lock.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
1877
diff
changeset
|
11 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
|
12 IOError.__init__(self, errno, strerror, filename) |
ff5c9a92f556
fix backtrace printed when cannot get lock.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
1877
diff
changeset
|
13 self.desc = desc |
ff5c9a92f556
fix backtrace printed when cannot get lock.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
1877
diff
changeset
|
14 |
1753
e6e70450edb9
Raise a different exception when the lock is not available
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents:
1559
diff
changeset
|
15 class LockHeld(LockException): |
2016
ff5c9a92f556
fix backtrace printed when cannot get lock.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
1877
diff
changeset
|
16 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
|
17 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
|
18 self.locker = locker |
ff5c9a92f556
fix backtrace printed when cannot get lock.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
1877
diff
changeset
|
19 |
1753
e6e70450edb9
Raise a different exception when the lock is not available
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents:
1559
diff
changeset
|
20 class LockUnavailable(LockException): |
161 | 21 pass |
22 | |
1559
59b3639df0a9
Convert all classes to new-style classes by deriving them from object.
Eric Hopper <hopper@omnifarious.org>
parents:
1530
diff
changeset
|
23 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
|
24 # 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
|
25 |
d314a89fa4f1
change lock format to let us detect and break stale locks.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
1836
diff
changeset
|
26 # 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
|
27 # 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
|
28 |
d314a89fa4f1
change lock format to let us detect and break stale locks.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
1836
diff
changeset
|
29 # 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
|
30 # 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
|
31 |
2016
ff5c9a92f556
fix backtrace printed when cannot get lock.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
1877
diff
changeset
|
32 def __init__(self, file, timeout=-1, releasefn=None, desc=None): |
161 | 33 self.f = file |
34 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
|
35 self.timeout = timeout |
1530
abfab59fce79
add a releasefn keyword to lock.lock
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents:
1062
diff
changeset
|
36 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
|
37 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
|
38 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
|
39 self.pid = None |
2016
ff5c9a92f556
fix backtrace printed when cannot get lock.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
1877
diff
changeset
|
40 self.desc = desc |
161 | 41 self.lock() |
42 | |
43 def __del__(self): | |
44 self.release() | |
45 | |
46 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
|
47 timeout = self.timeout |
161 | 48 while 1: |
49 try: | |
50 self.trylock() | |
51 return 1 | |
52 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
|
53 if timeout != 0: |
161 | 54 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
|
55 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
|
56 timeout -= 1 |
161 | 57 continue |
2016
ff5c9a92f556
fix backtrace printed when cannot get lock.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
1877
diff
changeset
|
58 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
|
59 inst.locker) |
515 | 60 |
161 | 61 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
|
62 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
|
63 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
|
64 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
|
65 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
|
66 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
|
67 try: |
d314a89fa4f1
change lock format to let us detect and break stale locks.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
1836
diff
changeset
|
68 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
|
69 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
|
70 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
|
71 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
|
72 locker = self.testlock() |
3686
4308f4cdc07b
Don't step into an endless loop when lock file is empty.
Thomas Arendsen Hein <thomas@intevation.de>
parents:
2859
diff
changeset
|
73 if locker is not None: |
2016
ff5c9a92f556
fix backtrace printed when cannot get lock.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
1877
diff
changeset
|
74 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
|
75 locker) |
1877
d314a89fa4f1
change lock format to let us detect and break stale locks.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
1836
diff
changeset
|
76 else: |
2016
ff5c9a92f556
fix backtrace printed when cannot get lock.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
1877
diff
changeset
|
77 raise LockUnavailable(why.errno, why.strerror, |
ff5c9a92f556
fix backtrace printed when cannot get lock.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
1877
diff
changeset
|
78 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
|
79 |
d314a89fa4f1
change lock format to let us detect and break stale locks.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
1836
diff
changeset
|
80 def testlock(self): |
3686
4308f4cdc07b
Don't step into an endless loop when lock file is empty.
Thomas Arendsen Hein <thomas@intevation.de>
parents:
2859
diff
changeset
|
81 """return id of locker if lock is valid, else None. |
4308f4cdc07b
Don't step into an endless loop when lock file is empty.
Thomas Arendsen Hein <thomas@intevation.de>
parents:
2859
diff
changeset
|
82 |
4308f4cdc07b
Don't step into an endless loop when lock file is empty.
Thomas Arendsen Hein <thomas@intevation.de>
parents:
2859
diff
changeset
|
83 If old-style lock, we cannot tell what machine locker is on. |
4308f4cdc07b
Don't step into an endless loop when lock file is empty.
Thomas Arendsen Hein <thomas@intevation.de>
parents:
2859
diff
changeset
|
84 with new-style lock, if locker is on this machine, we can |
4308f4cdc07b
Don't step into an endless loop when lock file is empty.
Thomas Arendsen Hein <thomas@intevation.de>
parents:
2859
diff
changeset
|
85 see if locker is alive. If locker is on this machine but |
4308f4cdc07b
Don't step into an endless loop when lock file is empty.
Thomas Arendsen Hein <thomas@intevation.de>
parents:
2859
diff
changeset
|
86 not alive, we can safely break lock. |
4308f4cdc07b
Don't step into an endless loop when lock file is empty.
Thomas Arendsen Hein <thomas@intevation.de>
parents:
2859
diff
changeset
|
87 |
4308f4cdc07b
Don't step into an endless loop when lock file is empty.
Thomas Arendsen Hein <thomas@intevation.de>
parents:
2859
diff
changeset
|
88 The lock file is only deleted when None is returned. |
4308f4cdc07b
Don't step into an endless loop when lock file is empty.
Thomas Arendsen Hein <thomas@intevation.de>
parents:
2859
diff
changeset
|
89 |
4308f4cdc07b
Don't step into an endless loop when lock file is empty.
Thomas Arendsen Hein <thomas@intevation.de>
parents:
2859
diff
changeset
|
90 """ |
1877
d314a89fa4f1
change lock format to let us detect and break stale locks.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
1836
diff
changeset
|
91 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
|
92 try: |
0875cda033fd
use __contains__, index or split instead of str.find
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents:
2016
diff
changeset
|
93 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
|
94 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
|
95 return locker |
d314a89fa4f1
change lock format to let us detect and break stale locks.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
1836
diff
changeset
|
96 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
|
97 return locker |
161 | 98 try: |
2579
0875cda033fd
use __contains__, index or split instead of str.find
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents:
2016
diff
changeset
|
99 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
|
100 except: |
d314a89fa4f1
change lock format to let us detect and break stale locks.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
1836
diff
changeset
|
101 return locker |
d314a89fa4f1
change lock format to let us detect and break stale locks.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
1836
diff
changeset
|
102 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
|
103 return locker |
d314a89fa4f1
change lock format to let us detect and break stale locks.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
1836
diff
changeset
|
104 # 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
|
105 # 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
|
106 try: |
d314a89fa4f1
change lock format to let us detect and break stale locks.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
1836
diff
changeset
|
107 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
|
108 l.trylock() |
d314a89fa4f1
change lock format to let us detect and break stale locks.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
1836
diff
changeset
|
109 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
|
110 l.release() |
d314a89fa4f1
change lock format to let us detect and break stale locks.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
1836
diff
changeset
|
111 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
|
112 return locker |
161 | 113 |
114 def release(self): | |
115 if self.held: | |
116 self.held = 0 | |
1530
abfab59fce79
add a releasefn keyword to lock.lock
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents:
1062
diff
changeset
|
117 if self.releasefn: |
abfab59fce79
add a releasefn keyword to lock.lock
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents:
1062
diff
changeset
|
118 self.releasefn() |
503
c6a2e41c8c60
Fix troubles with clone and exception handling
mpm@selenic.com
parents:
429
diff
changeset
|
119 try: |
c6a2e41c8c60
Fix troubles with clone and exception handling
mpm@selenic.com
parents:
429
diff
changeset
|
120 os.unlink(self.f) |
c6a2e41c8c60
Fix troubles with clone and exception handling
mpm@selenic.com
parents:
429
diff
changeset
|
121 except: pass |
161 | 122 |