Mercurial > hg
annotate mercurial/lock.py @ 8745:8fd6f6b8b37d
merge: drop 'remote deleted' case
author | Matt Mackall <mpm@selenic.com> |
---|---|
date | Mon, 08 Jun 2009 18:14:44 -0500 |
parents | b87a50b7125c |
children | cfdcb7a465af |
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 # |
8225
46293a0c7e9f
updated license to be explicit about GPL version 2
Martin Geisler <mg@lazybytes.net>
parents:
8113
diff
changeset
|
5 # This software may be used and distributed according to the terms of the |
46293a0c7e9f
updated license to be explicit about GPL version 2
Martin Geisler <mg@lazybytes.net>
parents:
8113
diff
changeset
|
6 # GNU General Public License version 2, incorporated herein by reference. |
161 | 7 |
8312
b87a50b7125c
separate import lines from mercurial and general python modules
Simon Heimberg <simohe@besonet.ch>
parents:
8225
diff
changeset
|
8 import util, error |
b87a50b7125c
separate import lines from mercurial and general python modules
Simon Heimberg <simohe@besonet.ch>
parents:
8225
diff
changeset
|
9 import errno, os, socket, time |
8113
87a1605979e4
add a deprecation warning for gc based lock releasing
Ronny Pfannschmidt <Ronny.Pfannschmidt@gmx.de>
parents:
8108
diff
changeset
|
10 import warnings |
161 | 11 |
1559
59b3639df0a9
Convert all classes to new-style classes by deriving them from object.
Eric Hopper <hopper@omnifarious.org>
parents:
1530
diff
changeset
|
12 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
|
13 # 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
|
14 |
d314a89fa4f1
change lock format to let us detect and break stale locks.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
1836
diff
changeset
|
15 # 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
|
16 # 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
|
17 |
d314a89fa4f1
change lock format to let us detect and break stale locks.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
1836
diff
changeset
|
18 # 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
|
19 # 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
|
20 |
4947
3e25a6eb5c9a
lock.py: cache hostname, but not pid, in case we fork
Bryan O'Sullivan <bos@serpentine.com>
parents:
3877
diff
changeset
|
21 _host = None |
3e25a6eb5c9a
lock.py: cache hostname, but not pid, in case we fork
Bryan O'Sullivan <bos@serpentine.com>
parents:
3877
diff
changeset
|
22 |
2016
ff5c9a92f556
fix backtrace printed when cannot get lock.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
1877
diff
changeset
|
23 def __init__(self, file, timeout=-1, releasefn=None, desc=None): |
161 | 24 self.f = file |
25 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
|
26 self.timeout = timeout |
1530
abfab59fce79
add a releasefn keyword to lock.lock
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents:
1062
diff
changeset
|
27 self.releasefn = releasefn |
2016
ff5c9a92f556
fix backtrace printed when cannot get lock.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
1877
diff
changeset
|
28 self.desc = desc |
161 | 29 self.lock() |
30 | |
31 def __del__(self): | |
8108
a26d33749bd8
made repo locks recursive and deprecate refcounting based lock releasing
Ronny Pfannschmidt <Ronny.Pfannschmidt@gmx.de>
parents:
7640
diff
changeset
|
32 if self.held: |
8113
87a1605979e4
add a deprecation warning for gc based lock releasing
Ronny Pfannschmidt <Ronny.Pfannschmidt@gmx.de>
parents:
8108
diff
changeset
|
33 warnings.warn("use lock.release instead of del lock", |
87a1605979e4
add a deprecation warning for gc based lock releasing
Ronny Pfannschmidt <Ronny.Pfannschmidt@gmx.de>
parents:
8108
diff
changeset
|
34 category=DeprecationWarning, |
87a1605979e4
add a deprecation warning for gc based lock releasing
Ronny Pfannschmidt <Ronny.Pfannschmidt@gmx.de>
parents:
8108
diff
changeset
|
35 stacklevel=2) |
87a1605979e4
add a deprecation warning for gc based lock releasing
Ronny Pfannschmidt <Ronny.Pfannschmidt@gmx.de>
parents:
8108
diff
changeset
|
36 |
8108
a26d33749bd8
made repo locks recursive and deprecate refcounting based lock releasing
Ronny Pfannschmidt <Ronny.Pfannschmidt@gmx.de>
parents:
7640
diff
changeset
|
37 # ensure the lock will be removed |
a26d33749bd8
made repo locks recursive and deprecate refcounting based lock releasing
Ronny Pfannschmidt <Ronny.Pfannschmidt@gmx.de>
parents:
7640
diff
changeset
|
38 # even if recursive locking did occur |
a26d33749bd8
made repo locks recursive and deprecate refcounting based lock releasing
Ronny Pfannschmidt <Ronny.Pfannschmidt@gmx.de>
parents:
7640
diff
changeset
|
39 self.held = 1 |
a26d33749bd8
made repo locks recursive and deprecate refcounting based lock releasing
Ronny Pfannschmidt <Ronny.Pfannschmidt@gmx.de>
parents:
7640
diff
changeset
|
40 |
161 | 41 self.release() |
42 | |
43 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
|
44 timeout = self.timeout |
161 | 45 while 1: |
46 try: | |
47 self.trylock() | |
48 return 1 | |
7640 | 49 except error.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
|
50 if timeout != 0: |
161 | 51 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
|
52 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
|
53 timeout -= 1 |
161 | 54 continue |
7640 | 55 raise error.LockHeld(errno.ETIMEDOUT, inst.filename, self.desc, |
56 inst.locker) | |
515 | 57 |
161 | 58 def trylock(self): |
8108
a26d33749bd8
made repo locks recursive and deprecate refcounting based lock releasing
Ronny Pfannschmidt <Ronny.Pfannschmidt@gmx.de>
parents:
7640
diff
changeset
|
59 if self.held: |
a26d33749bd8
made repo locks recursive and deprecate refcounting based lock releasing
Ronny Pfannschmidt <Ronny.Pfannschmidt@gmx.de>
parents:
7640
diff
changeset
|
60 self.held += 1 |
a26d33749bd8
made repo locks recursive and deprecate refcounting based lock releasing
Ronny Pfannschmidt <Ronny.Pfannschmidt@gmx.de>
parents:
7640
diff
changeset
|
61 return |
4947
3e25a6eb5c9a
lock.py: cache hostname, but not pid, in case we fork
Bryan O'Sullivan <bos@serpentine.com>
parents:
3877
diff
changeset
|
62 if lock._host is None: |
3e25a6eb5c9a
lock.py: cache hostname, but not pid, in case we fork
Bryan O'Sullivan <bos@serpentine.com>
parents:
3877
diff
changeset
|
63 lock._host = socket.gethostname() |
4959
8933b8ea871a
Use format string for lockname again (was changed by 3e25a6eb5c9a)
Thomas Arendsen Hein <thomas@intevation.de>
parents:
4947
diff
changeset
|
64 lockname = '%s:%s' % (lock._host, os.getpid()) |
1877
d314a89fa4f1
change lock format to let us detect and break stale locks.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
1836
diff
changeset
|
65 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
|
66 try: |
4947
3e25a6eb5c9a
lock.py: cache hostname, but not pid, in case we fork
Bryan O'Sullivan <bos@serpentine.com>
parents:
3877
diff
changeset
|
67 util.makelock(lockname, self.f) |
1877
d314a89fa4f1
change lock format to let us detect and break stale locks.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
1836
diff
changeset
|
68 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
|
69 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
|
70 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
|
71 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
|
72 if locker is not None: |
7640 | 73 raise error.LockHeld(errno.EAGAIN, self.f, self.desc, |
74 locker) | |
1877
d314a89fa4f1
change lock format to let us detect and break stale locks.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
1836
diff
changeset
|
75 else: |
7640 | 76 raise error.LockUnavailable(why.errno, why.strerror, |
77 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
|
78 |
d314a89fa4f1
change lock format to let us detect and break stale locks.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
1836
diff
changeset
|
79 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
|
80 """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
|
81 |
4308f4cdc07b
Don't step into an endless loop when lock file is empty.
Thomas Arendsen Hein <thomas@intevation.de>
parents:
2859
diff
changeset
|
82 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
|
83 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
|
84 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
|
85 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
|
86 |
4308f4cdc07b
Don't step into an endless loop when lock file is empty.
Thomas Arendsen Hein <thomas@intevation.de>
parents:
2859
diff
changeset
|
87 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
|
88 |
4308f4cdc07b
Don't step into an endless loop when lock file is empty.
Thomas Arendsen Hein <thomas@intevation.de>
parents:
2859
diff
changeset
|
89 """ |
1877
d314a89fa4f1
change lock format to let us detect and break stale locks.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
1836
diff
changeset
|
90 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
|
91 try: |
0875cda033fd
use __contains__, index or split instead of str.find
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents:
2016
diff
changeset
|
92 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
|
93 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
|
94 return locker |
4947
3e25a6eb5c9a
lock.py: cache hostname, but not pid, in case we fork
Bryan O'Sullivan <bos@serpentine.com>
parents:
3877
diff
changeset
|
95 if host != lock._host: |
1877
d314a89fa4f1
change lock format to let us detect and break stale locks.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
1836
diff
changeset
|
96 return locker |
161 | 97 try: |
2579
0875cda033fd
use __contains__, index or split instead of str.find
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents:
2016
diff
changeset
|
98 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
|
99 except: |
d314a89fa4f1
change lock format to let us detect and break stale locks.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
1836
diff
changeset
|
100 return locker |
d314a89fa4f1
change lock format to let us detect and break stale locks.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
1836
diff
changeset
|
101 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
|
102 return locker |
d314a89fa4f1
change lock format to let us detect and break stale locks.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
1836
diff
changeset
|
103 # 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
|
104 # 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
|
105 try: |
d314a89fa4f1
change lock format to let us detect and break stale locks.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
1836
diff
changeset
|
106 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
|
107 l.trylock() |
d314a89fa4f1
change lock format to let us detect and break stale locks.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
1836
diff
changeset
|
108 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
|
109 l.release() |
7640 | 110 except error.LockError: |
1877
d314a89fa4f1
change lock format to let us detect and break stale locks.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
1836
diff
changeset
|
111 return locker |
161 | 112 |
113 def release(self): | |
8108
a26d33749bd8
made repo locks recursive and deprecate refcounting based lock releasing
Ronny Pfannschmidt <Ronny.Pfannschmidt@gmx.de>
parents:
7640
diff
changeset
|
114 if self.held > 1: |
a26d33749bd8
made repo locks recursive and deprecate refcounting based lock releasing
Ronny Pfannschmidt <Ronny.Pfannschmidt@gmx.de>
parents:
7640
diff
changeset
|
115 self.held -= 1 |
a26d33749bd8
made repo locks recursive and deprecate refcounting based lock releasing
Ronny Pfannschmidt <Ronny.Pfannschmidt@gmx.de>
parents:
7640
diff
changeset
|
116 elif self.held is 1: |
161 | 117 self.held = 0 |
1530
abfab59fce79
add a releasefn keyword to lock.lock
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents:
1062
diff
changeset
|
118 if self.releasefn: |
abfab59fce79
add a releasefn keyword to lock.lock
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents:
1062
diff
changeset
|
119 self.releasefn() |
503
c6a2e41c8c60
Fix troubles with clone and exception handling
mpm@selenic.com
parents:
429
diff
changeset
|
120 try: |
c6a2e41c8c60
Fix troubles with clone and exception handling
mpm@selenic.com
parents:
429
diff
changeset
|
121 os.unlink(self.f) |
c6a2e41c8c60
Fix troubles with clone and exception handling
mpm@selenic.com
parents:
429
diff
changeset
|
122 except: pass |
161 | 123 |
8108
a26d33749bd8
made repo locks recursive and deprecate refcounting based lock releasing
Ronny Pfannschmidt <Ronny.Pfannschmidt@gmx.de>
parents:
7640
diff
changeset
|
124 def release(*locks): |
a26d33749bd8
made repo locks recursive and deprecate refcounting based lock releasing
Ronny Pfannschmidt <Ronny.Pfannschmidt@gmx.de>
parents:
7640
diff
changeset
|
125 for lock in locks: |
a26d33749bd8
made repo locks recursive and deprecate refcounting based lock releasing
Ronny Pfannschmidt <Ronny.Pfannschmidt@gmx.de>
parents:
7640
diff
changeset
|
126 if lock is not None: |
a26d33749bd8
made repo locks recursive and deprecate refcounting based lock releasing
Ronny Pfannschmidt <Ronny.Pfannschmidt@gmx.de>
parents:
7640
diff
changeset
|
127 lock.release() |
a26d33749bd8
made repo locks recursive and deprecate refcounting based lock releasing
Ronny Pfannschmidt <Ronny.Pfannschmidt@gmx.de>
parents:
7640
diff
changeset
|
128 |