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