##// END OF EJS Templates
add a deprecation warning for gc based lock releasing
Ronny Pfannschmidt -
r8113:87a16059 default
parent child Browse files
Show More
@@ -1,122 +1,127
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, error
8 import errno, os, socket, time, util, error
9 import warnings
9
10
10 class lock(object):
11 class lock(object):
11 # lock is symlink on platforms that support it, file on others.
12 # lock is symlink on platforms that support it, file on others.
12
13
13 # symlink is used because create of directory entry and contents
14 # symlink is used because create of directory entry and contents
14 # are atomic even over nfs.
15 # are atomic even over nfs.
15
16
16 # old-style lock: symlink to pid
17 # old-style lock: symlink to pid
17 # new-style lock: symlink to hostname:pid
18 # new-style lock: symlink to hostname:pid
18
19
19 _host = None
20 _host = None
20
21
21 def __init__(self, file, timeout=-1, releasefn=None, desc=None):
22 def __init__(self, file, timeout=-1, releasefn=None, desc=None):
22 self.f = file
23 self.f = file
23 self.held = 0
24 self.held = 0
24 self.timeout = timeout
25 self.timeout = timeout
25 self.releasefn = releasefn
26 self.releasefn = releasefn
26 self.desc = desc
27 self.desc = desc
27 self.lock()
28 self.lock()
28
29
29 def __del__(self):
30 def __del__(self):
30 if self.held:
31 if self.held:
32 warnings.warn("use lock.release instead of del lock",
33 category=DeprecationWarning,
34 stacklevel=2)
35
31 # ensure the lock will be removed
36 # ensure the lock will be removed
32 # even if recursive locking did occur
37 # even if recursive locking did occur
33 self.held = 1
38 self.held = 1
34
39
35 self.release()
40 self.release()
36
41
37 def lock(self):
42 def lock(self):
38 timeout = self.timeout
43 timeout = self.timeout
39 while 1:
44 while 1:
40 try:
45 try:
41 self.trylock()
46 self.trylock()
42 return 1
47 return 1
43 except error.LockHeld, inst:
48 except error.LockHeld, inst:
44 if timeout != 0:
49 if timeout != 0:
45 time.sleep(1)
50 time.sleep(1)
46 if timeout > 0:
51 if timeout > 0:
47 timeout -= 1
52 timeout -= 1
48 continue
53 continue
49 raise error.LockHeld(errno.ETIMEDOUT, inst.filename, self.desc,
54 raise error.LockHeld(errno.ETIMEDOUT, inst.filename, self.desc,
50 inst.locker)
55 inst.locker)
51
56
52 def trylock(self):
57 def trylock(self):
53 if self.held:
58 if self.held:
54 self.held += 1
59 self.held += 1
55 return
60 return
56 if lock._host is None:
61 if lock._host is None:
57 lock._host = socket.gethostname()
62 lock._host = socket.gethostname()
58 lockname = '%s:%s' % (lock._host, os.getpid())
63 lockname = '%s:%s' % (lock._host, os.getpid())
59 while not self.held:
64 while not self.held:
60 try:
65 try:
61 util.makelock(lockname, self.f)
66 util.makelock(lockname, self.f)
62 self.held = 1
67 self.held = 1
63 except (OSError, IOError), why:
68 except (OSError, IOError), why:
64 if why.errno == errno.EEXIST:
69 if why.errno == errno.EEXIST:
65 locker = self.testlock()
70 locker = self.testlock()
66 if locker is not None:
71 if locker is not None:
67 raise error.LockHeld(errno.EAGAIN, self.f, self.desc,
72 raise error.LockHeld(errno.EAGAIN, self.f, self.desc,
68 locker)
73 locker)
69 else:
74 else:
70 raise error.LockUnavailable(why.errno, why.strerror,
75 raise error.LockUnavailable(why.errno, why.strerror,
71 why.filename, self.desc)
76 why.filename, self.desc)
72
77
73 def testlock(self):
78 def testlock(self):
74 """return id of locker if lock is valid, else None.
79 """return id of locker if lock is valid, else None.
75
80
76 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.
77 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
78 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
79 not alive, we can safely break lock.
84 not alive, we can safely break lock.
80
85
81 The lock file is only deleted when None is returned.
86 The lock file is only deleted when None is returned.
82
87
83 """
88 """
84 locker = util.readlock(self.f)
89 locker = util.readlock(self.f)
85 try:
90 try:
86 host, pid = locker.split(":", 1)
91 host, pid = locker.split(":", 1)
87 except ValueError:
92 except ValueError:
88 return locker
93 return locker
89 if host != lock._host:
94 if host != lock._host:
90 return locker
95 return locker
91 try:
96 try:
92 pid = int(pid)
97 pid = int(pid)
93 except:
98 except:
94 return locker
99 return locker
95 if util.testpid(pid):
100 if util.testpid(pid):
96 return locker
101 return locker
97 # if locker dead, break lock. must do this with another lock
102 # if locker dead, break lock. must do this with another lock
98 # held, or can race and break valid lock.
103 # held, or can race and break valid lock.
99 try:
104 try:
100 l = lock(self.f + '.break')
105 l = lock(self.f + '.break')
101 l.trylock()
106 l.trylock()
102 os.unlink(self.f)
107 os.unlink(self.f)
103 l.release()
108 l.release()
104 except error.LockError:
109 except error.LockError:
105 return locker
110 return locker
106
111
107 def release(self):
112 def release(self):
108 if self.held > 1:
113 if self.held > 1:
109 self.held -= 1
114 self.held -= 1
110 elif self.held is 1:
115 elif self.held is 1:
111 self.held = 0
116 self.held = 0
112 if self.releasefn:
117 if self.releasefn:
113 self.releasefn()
118 self.releasefn()
114 try:
119 try:
115 os.unlink(self.f)
120 os.unlink(self.f)
116 except: pass
121 except: pass
117
122
118 def release(*locks):
123 def release(*locks):
119 for lock in locks:
124 for lock in locks:
120 if lock is not None:
125 if lock is not None:
121 lock.release()
126 lock.release()
122
127
General Comments 0
You need to be logged in to leave comments. Login now