Mercurial > hg
annotate mercurial/lock.py @ 2439:e8c4f3d3df8c
extend network protocol to stop clients from locking servers
now all repositories have capabilities slot, tuple with list of names.
if 'unbundle' capability present, repo supports push where client does
not need to lock server. repository classes that have unbundle capability
also have unbundle method.
implemented for ssh now, will be base for push over http.
unbundle protocol acts this way. server tells client what heads it
has during normal negotiate step. client starts unbundle by repeat
server's heads back to it. if server has new heads, abort immediately.
otherwise, transfer changes to server. once data transferred, server
locks and checks heads again. if heads same, changes can be added.
else someone else added heads, and server aborts.
if client wants to force server to add heads, sends special heads list of
'force'.
author | Vadim Gelfer <vadim.gelfer@gmail.com> |
---|---|
date | Thu, 15 Jun 2006 16:37:23 -0700 |
parents | ff5c9a92f556 |
children | 0875cda033fd |
rev | line source |
---|---|
161 | 1 # lock.py - simple locking scheme for mercurial |
2 # | |
3 # Copyright 2005 Matt Mackall <mpm@selenic.com> | |
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 | |
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 | 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 | 22 pass |
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 | 34 self.f = file |
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 | 42 self.lock() |
43 | |
44 def __del__(self): | |
45 self.release() | |
46 | |
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 | 49 while 1: |
50 try: | |
51 self.trylock() | |
52 return 1 | |
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 | 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 | 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 | 61 |
161 | 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 | 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 | 109 |
110 def release(self): | |
111 if self.held: | |
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 | 118 |