Show More
@@ -7,6 +7,7 b'' | |||||
7 |
|
7 | |||
8 | from __future__ import absolute_import |
|
8 | from __future__ import absolute_import | |
9 |
|
9 | |||
|
10 | import contextlib | |||
10 | import errno |
|
11 | import errno | |
11 | import os |
|
12 | import os | |
12 | import socket |
|
13 | import socket | |
@@ -171,19 +172,20 b' class lock(object):' | |||||
171 | locker = self._readlock() |
|
172 | locker = self._readlock() | |
172 | return self._testlock(locker) |
|
173 | return self._testlock(locker) | |
173 |
|
174 | |||
174 | def prepinherit(self): |
|
175 | @contextlib.contextmanager | |
175 | """prepare for the lock to be inherited by a Mercurial subprocess |
|
176 | def inherit(self): | |
|
177 | """context for the lock to be inherited by a Mercurial subprocess. | |||
176 |
|
178 | |||
177 |
|
|
179 | Yields a string that will be recognized by the lock in the subprocess. | |
178 |
|
|
180 | Communicating this string to the subprocess needs to be done separately | |
179 |
|
|
181 | -- typically by an environment variable. | |
180 | """ |
|
182 | """ | |
181 | if not self.held: |
|
183 | if not self.held: | |
182 | raise error.LockInheritanceContractViolation( |
|
184 | raise error.LockInheritanceContractViolation( | |
183 |
' |
|
185 | 'inherit can only be called while lock is held') | |
184 | if self._inherited: |
|
186 | if self._inherited: | |
185 | raise error.LockInheritanceContractViolation( |
|
187 | raise error.LockInheritanceContractViolation( | |
186 |
' |
|
188 | 'inherit cannot be called while lock is already inherited') | |
187 | if self.releasefn: |
|
189 | if self.releasefn: | |
188 | self.releasefn() |
|
190 | self.releasefn() | |
189 | if self._parentheld: |
|
191 | if self._parentheld: | |
@@ -191,15 +193,12 b' class lock(object):' | |||||
191 | else: |
|
193 | else: | |
192 | lockname = '%s:%s' % (lock._host, self.pid) |
|
194 | lockname = '%s:%s' % (lock._host, self.pid) | |
193 | self._inherited = True |
|
195 | self._inherited = True | |
194 | return lockname |
|
196 | try: | |
195 |
|
197 | yield lockname | ||
196 | def reacquire(self): |
|
198 | finally: | |
197 |
if |
|
199 | if self.acquirefn: | |
198 | raise error.LockInheritanceContractViolation( |
|
200 | self.acquirefn() | |
199 | 'reacquire can only be called after prepinherit') |
|
201 | self._inherited = False | |
200 | if self.acquirefn: |
|
|||
201 | self.acquirefn() |
|
|||
202 | self._inherited = False |
|
|||
203 |
|
202 | |||
204 | def release(self): |
|
203 | def release(self): | |
205 | """release the lock and execute callback function if any |
|
204 | """release the lock and execute callback function if any |
@@ -158,23 +158,22 b' class testlock(unittest.TestCase):' | |||||
158 | parentstate.assertacquirecalled(True) |
|
158 | parentstate.assertacquirecalled(True) | |
159 |
|
159 | |||
160 | # set up lock inheritance |
|
160 | # set up lock inheritance | |
161 |
|
|
161 | with parentlock.inherit() as lockname: | |
162 | parentstate.assertreleasecalled(True) |
|
162 | parentstate.assertreleasecalled(True) | |
163 | parentstate.assertpostreleasecalled(False) |
|
163 | parentstate.assertpostreleasecalled(False) | |
164 | parentstate.assertlockexists(True) |
|
164 | parentstate.assertlockexists(True) | |
165 |
|
||||
166 | childstate = teststate(self, d, pidoffset=1) |
|
|||
167 | childlock = childstate.makelock(parentlock=lockname) |
|
|||
168 | childstate.assertacquirecalled(True) |
|
|||
169 |
|
165 | |||
170 | # release the child lock -- the lock file should still exist on disk |
|
166 | childstate = teststate(self, d, pidoffset=1) | |
171 | childlock.release() |
|
167 | childlock = childstate.makelock(parentlock=lockname) | |
172 |
childstate.assert |
|
168 | childstate.assertacquirecalled(True) | |
173 | childstate.assertpostreleasecalled(True) |
|
|||
174 | childstate.assertlockexists(True) |
|
|||
175 |
|
169 | |||
176 | parentstate.resetacquirefn() |
|
170 | childlock.release() | |
177 | parentlock.reacquire() |
|
171 | childstate.assertreleasecalled(True) | |
|
172 | childstate.assertpostreleasecalled(True) | |||
|
173 | childstate.assertlockexists(True) | |||
|
174 | ||||
|
175 | parentstate.resetacquirefn() | |||
|
176 | ||||
178 | parentstate.assertacquirecalled(True) |
|
177 | parentstate.assertacquirecalled(True) | |
179 |
|
178 | |||
180 | parentlock.release() |
|
179 | parentlock.release() | |
@@ -188,39 +187,39 b' class testlock(unittest.TestCase):' | |||||
188 | lock0 = state0.makelock() |
|
187 | lock0 = state0.makelock() | |
189 | state0.assertacquirecalled(True) |
|
188 | state0.assertacquirecalled(True) | |
190 |
|
189 | |||
191 | lock0name = lock0.prepinherit() |
|
190 | with lock0.inherit() as lock0name: | |
192 | state0.assertreleasecalled(True) |
|
191 | state0.assertreleasecalled(True) | |
193 | state0.assertpostreleasecalled(False) |
|
192 | state0.assertpostreleasecalled(False) | |
194 | state0.assertlockexists(True) |
|
193 | state0.assertlockexists(True) | |
195 |
|
194 | |||
196 | state1 = teststate(self, d, pidoffset=1) |
|
195 | state1 = teststate(self, d, pidoffset=1) | |
197 | lock1 = state1.makelock(parentlock=lock0name) |
|
196 | lock1 = state1.makelock(parentlock=lock0name) | |
198 | state1.assertacquirecalled(True) |
|
197 | state1.assertacquirecalled(True) | |
199 |
|
198 | |||
200 | # from within lock1, acquire another lock |
|
199 | # from within lock1, acquire another lock | |
201 | lock1name = lock1.prepinherit() |
|
200 | with lock1.inherit() as lock1name: | |
202 |
# since the file on disk is lock0's this should have the same |
|
201 | # since the file on disk is lock0's this should have the same | |
203 | self.assertEqual(lock0name, lock1name) |
|
202 | # name | |
|
203 | self.assertEqual(lock0name, lock1name) | |||
204 |
|
204 | |||
205 | state2 = teststate(self, d, pidoffset=2) |
|
205 | state2 = teststate(self, d, pidoffset=2) | |
206 | lock2 = state2.makelock(parentlock=lock1name) |
|
206 | lock2 = state2.makelock(parentlock=lock1name) | |
207 | state2.assertacquirecalled(True) |
|
207 | state2.assertacquirecalled(True) | |
208 |
|
208 | |||
209 | lock2.release() |
|
209 | lock2.release() | |
210 | state2.assertreleasecalled(True) |
|
210 | state2.assertreleasecalled(True) | |
211 | state2.assertpostreleasecalled(True) |
|
211 | state2.assertpostreleasecalled(True) | |
212 | state2.assertlockexists(True) |
|
212 | state2.assertlockexists(True) | |
213 |
|
213 | |||
214 | state1.resetacquirefn() |
|
214 | state1.resetacquirefn() | |
215 | lock1.reacquire() |
|
215 | ||
216 | state1.assertacquirecalled(True) |
|
216 | state1.assertacquirecalled(True) | |
217 |
|
217 | |||
218 | lock1.release() |
|
218 | lock1.release() | |
219 | state1.assertreleasecalled(True) |
|
219 | state1.assertreleasecalled(True) | |
220 | state1.assertpostreleasecalled(True) |
|
220 | state1.assertpostreleasecalled(True) | |
221 | state1.assertlockexists(True) |
|
221 | state1.assertlockexists(True) | |
222 |
|
222 | |||
223 | lock0.reacquire() |
|
|||
224 | lock0.release() |
|
223 | lock0.release() | |
225 |
|
224 | |||
226 | def testinheritlockfork(self): |
|
225 | def testinheritlockfork(self): | |
@@ -230,26 +229,25 b' class testlock(unittest.TestCase):' | |||||
230 | parentstate.assertacquirecalled(True) |
|
229 | parentstate.assertacquirecalled(True) | |
231 |
|
230 | |||
232 | # set up lock inheritance |
|
231 | # set up lock inheritance | |
233 |
|
|
232 | with parentlock.inherit() as lockname: | |
234 | childstate = teststate(self, d, pidoffset=1) |
|
233 | childstate = teststate(self, d, pidoffset=1) | |
235 | childlock = childstate.makelock(parentlock=lockname) |
|
234 | childlock = childstate.makelock(parentlock=lockname) | |
236 | childstate.assertacquirecalled(True) |
|
235 | childstate.assertacquirecalled(True) | |
237 |
|
236 | |||
238 | # fork the child lock |
|
237 | # fork the child lock | |
239 | forkchildlock = copy.deepcopy(childlock) |
|
238 | forkchildlock = copy.deepcopy(childlock) | |
240 | forkchildlock._pidoffset += 1 |
|
239 | forkchildlock._pidoffset += 1 | |
241 | forkchildlock.release() |
|
240 | forkchildlock.release() | |
242 | childstate.assertreleasecalled(False) |
|
241 | childstate.assertreleasecalled(False) | |
243 | childstate.assertpostreleasecalled(False) |
|
242 | childstate.assertpostreleasecalled(False) | |
244 | childstate.assertlockexists(True) |
|
243 | childstate.assertlockexists(True) | |
245 |
|
244 | |||
246 | # release the child lock |
|
245 | # release the child lock | |
247 | childlock.release() |
|
246 | childlock.release() | |
248 | childstate.assertreleasecalled(True) |
|
247 | childstate.assertreleasecalled(True) | |
249 | childstate.assertpostreleasecalled(True) |
|
248 | childstate.assertpostreleasecalled(True) | |
250 | childstate.assertlockexists(True) |
|
249 | childstate.assertlockexists(True) | |
251 |
|
250 | |||
252 | parentlock.reacquire() |
|
|||
253 | parentlock.release() |
|
251 | parentlock.release() | |
254 |
|
252 | |||
255 | if __name__ == '__main__': |
|
253 | if __name__ == '__main__': |
General Comments 0
You need to be logged in to leave comments.
Login now