##// END OF EJS Templates
Use format string for lockname again (was changed by 3e25a6eb5c9a)
Thomas Arendsen Hein -
r4959:8933b8ea default
parent child Browse files
Show More
@@ -1,120 +1,120 b''
1 1 # lock.py - simple locking scheme for mercurial
2 2 #
3 3 # Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
4 4 #
5 5 # This software may be used and distributed according to the terms
6 6 # of the GNU General Public License, incorporated herein by reference.
7 7
8 8 import errno, os, socket, time, util
9 9
10 10 class LockException(IOError):
11 11 def __init__(self, errno, strerror, filename, desc):
12 12 IOError.__init__(self, errno, strerror, filename)
13 13 self.desc = desc
14 14
15 15 class LockHeld(LockException):
16 16 def __init__(self, errno, filename, desc, locker):
17 17 LockException.__init__(self, errno, 'Lock held', filename, desc)
18 18 self.locker = locker
19 19
20 20 class LockUnavailable(LockException):
21 21 pass
22 22
23 23 class lock(object):
24 24 # lock is symlink on platforms that support it, file on others.
25 25
26 26 # symlink is used because create of directory entry and contents
27 27 # are atomic even over nfs.
28 28
29 29 # old-style lock: symlink to pid
30 30 # new-style lock: symlink to hostname:pid
31 31
32 32 _host = None
33 33
34 34 def __init__(self, file, timeout=-1, releasefn=None, desc=None):
35 35 self.f = file
36 36 self.held = 0
37 37 self.timeout = timeout
38 38 self.releasefn = releasefn
39 39 self.desc = desc
40 40 self.lock()
41 41
42 42 def __del__(self):
43 43 self.release()
44 44
45 45 def lock(self):
46 46 timeout = self.timeout
47 47 while 1:
48 48 try:
49 49 self.trylock()
50 50 return 1
51 51 except LockHeld, inst:
52 52 if timeout != 0:
53 53 time.sleep(1)
54 54 if timeout > 0:
55 55 timeout -= 1
56 56 continue
57 57 raise LockHeld(errno.ETIMEDOUT, inst.filename, self.desc,
58 58 inst.locker)
59 59
60 60 def trylock(self):
61 61 if lock._host is None:
62 62 lock._host = socket.gethostname()
63 lockname = lock._host + ':' + str(os.getpid())
63 lockname = '%s:%s' % (lock._host, os.getpid())
64 64 while not self.held:
65 65 try:
66 66 util.makelock(lockname, self.f)
67 67 self.held = 1
68 68 except (OSError, IOError), why:
69 69 if why.errno == errno.EEXIST:
70 70 locker = self.testlock()
71 71 if locker is not None:
72 72 raise LockHeld(errno.EAGAIN, self.f, self.desc,
73 73 locker)
74 74 else:
75 75 raise LockUnavailable(why.errno, why.strerror,
76 76 why.filename, self.desc)
77 77
78 78 def testlock(self):
79 79 """return id of locker if lock is valid, else None.
80 80
81 81 If old-style lock, we cannot tell what machine locker is on.
82 82 with new-style lock, if locker is on this machine, we can
83 83 see if locker is alive. If locker is on this machine but
84 84 not alive, we can safely break lock.
85 85
86 86 The lock file is only deleted when None is returned.
87 87
88 88 """
89 89 locker = util.readlock(self.f)
90 90 try:
91 91 host, pid = locker.split(":", 1)
92 92 except ValueError:
93 93 return locker
94 94 if host != lock._host:
95 95 return locker
96 96 try:
97 97 pid = int(pid)
98 98 except:
99 99 return locker
100 100 if util.testpid(pid):
101 101 return locker
102 102 # if locker dead, break lock. must do this with another lock
103 103 # held, or can race and break valid lock.
104 104 try:
105 105 l = lock(self.f + '.break')
106 106 l.trylock()
107 107 os.unlink(self.f)
108 108 l.release()
109 109 except (LockHeld, LockUnavailable):
110 110 return locker
111 111
112 112 def release(self):
113 113 if self.held:
114 114 self.held = 0
115 115 if self.releasefn:
116 116 self.releasefn()
117 117 try:
118 118 os.unlink(self.f)
119 119 except: pass
120 120
General Comments 0
You need to be logged in to leave comments. Login now