Show More
@@ -2678,22 +2678,8 b' class localrepository(object):' | |||||
2678 | ce.refresh() |
|
2678 | ce.refresh() | |
2679 |
|
2679 | |||
2680 | def _lock( |
|
2680 | def _lock( | |
2681 | self, |
|
2681 | self, vfs, lockname, wait, releasefn, acquirefn, desc, | |
2682 | vfs, |
|
|||
2683 | lockname, |
|
|||
2684 | wait, |
|
|||
2685 | releasefn, |
|
|||
2686 | acquirefn, |
|
|||
2687 | desc, |
|
|||
2688 | inheritchecker=None, |
|
|||
2689 | parentenvvar=None, |
|
|||
2690 | ): |
|
2682 | ): | |
2691 | parentlock = None |
|
|||
2692 | # the contents of parentenvvar are used by the underlying lock to |
|
|||
2693 | # determine whether it can be inherited |
|
|||
2694 | if parentenvvar is not None: |
|
|||
2695 | parentlock = encoding.environ.get(parentenvvar) |
|
|||
2696 |
|
||||
2697 | timeout = 0 |
|
2683 | timeout = 0 | |
2698 | warntimeout = 0 |
|
2684 | warntimeout = 0 | |
2699 | if wait: |
|
2685 | if wait: | |
@@ -2711,8 +2697,6 b' class localrepository(object):' | |||||
2711 | releasefn=releasefn, |
|
2697 | releasefn=releasefn, | |
2712 | acquirefn=acquirefn, |
|
2698 | acquirefn=acquirefn, | |
2713 | desc=desc, |
|
2699 | desc=desc, | |
2714 | inheritchecker=inheritchecker, |
|
|||
2715 | parentlock=parentlock, |
|
|||
2716 | signalsafe=signalsafe, |
|
2700 | signalsafe=signalsafe, | |
2717 | ) |
|
2701 | ) | |
2718 | return l |
|
2702 | return l | |
@@ -2753,12 +2737,6 b' class localrepository(object):' | |||||
2753 | self._lockref = weakref.ref(l) |
|
2737 | self._lockref = weakref.ref(l) | |
2754 | return l |
|
2738 | return l | |
2755 |
|
2739 | |||
2756 | def _wlockchecktransaction(self): |
|
|||
2757 | if self.currenttransaction() is not None: |
|
|||
2758 | raise error.LockInheritanceContractViolation( |
|
|||
2759 | b'wlock cannot be inherited in the middle of a transaction' |
|
|||
2760 | ) |
|
|||
2761 |
|
||||
2762 | def wlock(self, wait=True): |
|
2740 | def wlock(self, wait=True): | |
2763 | '''Lock the non-store parts of the repository (everything under |
|
2741 | '''Lock the non-store parts of the repository (everything under | |
2764 | .hg except .hg/store) and return a weak reference to the lock. |
|
2742 | .hg except .hg/store) and return a weak reference to the lock. | |
@@ -2796,8 +2774,6 b' class localrepository(object):' | |||||
2796 | unlock, |
|
2774 | unlock, | |
2797 | self.invalidatedirstate, |
|
2775 | self.invalidatedirstate, | |
2798 | _(b'working directory of %s') % self.origroot, |
|
2776 | _(b'working directory of %s') % self.origroot, | |
2799 | inheritchecker=self._wlockchecktransaction, |
|
|||
2800 | parentenvvar=b'HG_WLOCK_LOCKER', |
|
|||
2801 | ) |
|
2777 | ) | |
2802 | self._wlockref = weakref.ref(l) |
|
2778 | self._wlockref = weakref.ref(l) | |
2803 | return l |
|
2779 | return l |
@@ -202,8 +202,6 b' class lock(object):' | |||||
202 | releasefn=None, |
|
202 | releasefn=None, | |
203 | acquirefn=None, |
|
203 | acquirefn=None, | |
204 | desc=None, |
|
204 | desc=None, | |
205 | inheritchecker=None, |
|
|||
206 | parentlock=None, |
|
|||
207 | signalsafe=True, |
|
205 | signalsafe=True, | |
208 | dolock=True, |
|
206 | dolock=True, | |
209 | ): |
|
207 | ): | |
@@ -214,10 +212,6 b' class lock(object):' | |||||
214 | self.releasefn = releasefn |
|
212 | self.releasefn = releasefn | |
215 | self.acquirefn = acquirefn |
|
213 | self.acquirefn = acquirefn | |
216 | self.desc = desc |
|
214 | self.desc = desc | |
217 | self._inheritchecker = inheritchecker |
|
|||
218 | self.parentlock = parentlock |
|
|||
219 | self._parentheld = False |
|
|||
220 | self._inherited = False |
|
|||
221 | if signalsafe: |
|
215 | if signalsafe: | |
222 | self._maybedelayedinterrupt = _delayedinterrupt |
|
216 | self._maybedelayedinterrupt = _delayedinterrupt | |
223 | else: |
|
217 | else: | |
@@ -290,14 +284,6 b' class lock(object):' | |||||
290 | if locker is None: |
|
284 | if locker is None: | |
291 | continue |
|
285 | continue | |
292 |
|
286 | |||
293 | # special case where a parent process holds the lock -- this |
|
|||
294 | # is different from the pid being different because we do |
|
|||
295 | # want the unlock and postrelease functions to be called, |
|
|||
296 | # but the lockfile to not be removed. |
|
|||
297 | if locker == self.parentlock: |
|
|||
298 | self._parentheld = True |
|
|||
299 | self.held = 1 |
|
|||
300 | return |
|
|||
301 | locker = self._testlock(locker) |
|
287 | locker = self._testlock(locker) | |
302 | if locker is not None: |
|
288 | if locker is not None: | |
303 | raise error.LockHeld( |
|
289 | raise error.LockHeld( | |
@@ -377,38 +363,6 b' class lock(object):' | |||||
377 | locker = self._readlock() |
|
363 | locker = self._readlock() | |
378 | return self._testlock(locker) |
|
364 | return self._testlock(locker) | |
379 |
|
365 | |||
380 | @contextlib.contextmanager |
|
|||
381 | def inherit(self): |
|
|||
382 | """context for the lock to be inherited by a Mercurial subprocess. |
|
|||
383 |
|
||||
384 | Yields a string that will be recognized by the lock in the subprocess. |
|
|||
385 | Communicating this string to the subprocess needs to be done separately |
|
|||
386 | -- typically by an environment variable. |
|
|||
387 | """ |
|
|||
388 | if not self.held: |
|
|||
389 | raise error.LockInheritanceContractViolation( |
|
|||
390 | b'inherit can only be called while lock is held' |
|
|||
391 | ) |
|
|||
392 | if self._inherited: |
|
|||
393 | raise error.LockInheritanceContractViolation( |
|
|||
394 | b'inherit cannot be called while lock is already inherited' |
|
|||
395 | ) |
|
|||
396 | if self._inheritchecker is not None: |
|
|||
397 | self._inheritchecker() |
|
|||
398 | if self.releasefn: |
|
|||
399 | self.releasefn() |
|
|||
400 | if self._parentheld: |
|
|||
401 | lockname = self.parentlock |
|
|||
402 | else: |
|
|||
403 | lockname = b'%s:%d' % (lock._host, self.pid) |
|
|||
404 | self._inherited = True |
|
|||
405 | try: |
|
|||
406 | yield lockname |
|
|||
407 | finally: |
|
|||
408 | if self.acquirefn: |
|
|||
409 | self.acquirefn() |
|
|||
410 | self._inherited = False |
|
|||
411 |
|
||||
412 | def release(self, success=True): |
|
366 | def release(self, success=True): | |
413 | """release the lock and execute callback function if any |
|
367 | """release the lock and execute callback function if any | |
414 |
|
368 | |||
@@ -425,18 +379,16 b' class lock(object):' | |||||
425 | if self.releasefn: |
|
379 | if self.releasefn: | |
426 | self.releasefn() |
|
380 | self.releasefn() | |
427 | finally: |
|
381 | finally: | |
428 |
|
|
382 | try: | |
429 | try: |
|
383 | self.vfs.unlink(self.f) | |
430 | self.vfs.unlink(self.f) |
|
384 | except OSError: | |
431 |
|
|
385 | pass | |
432 | pass |
|
|||
433 | # The postrelease functions typically assume the lock is not held |
|
386 | # The postrelease functions typically assume the lock is not held | |
434 | # at all. |
|
387 | # at all. | |
435 |
|
|
388 | for callback in self.postrelease: | |
436 |
|
|
389 | callback(success) | |
437 | callback(success) |
|
390 | # Prevent double usage and help clear cycles. | |
438 | # Prevent double usage and help clear cycles. |
|
391 | self.postrelease = None | |
439 | self.postrelease = None |
|
|||
440 |
|
392 | |||
441 |
|
393 | |||
442 | def release(*locks): |
|
394 | def release(*locks): |
@@ -1737,29 +1737,6 b' def extdatasource(repo, source):' | |||||
1737 | return data |
|
1737 | return data | |
1738 |
|
1738 | |||
1739 |
|
1739 | |||
1740 | def _locksub(repo, lock, envvar, cmd, environ=None, *args, **kwargs): |
|
|||
1741 | if lock is None: |
|
|||
1742 | raise error.LockInheritanceContractViolation( |
|
|||
1743 | b'lock can only be inherited while held' |
|
|||
1744 | ) |
|
|||
1745 | if environ is None: |
|
|||
1746 | environ = {} |
|
|||
1747 | with lock.inherit() as locker: |
|
|||
1748 | environ[envvar] = locker |
|
|||
1749 | return repo.ui.system(cmd, environ=environ, *args, **kwargs) |
|
|||
1750 |
|
||||
1751 |
|
||||
1752 | def wlocksub(repo, cmd, *args, **kwargs): |
|
|||
1753 | """run cmd as a subprocess that allows inheriting repo's wlock |
|
|||
1754 |
|
||||
1755 | This can only be called while the wlock is held. This takes all the |
|
|||
1756 | arguments that ui.system does, and returns the exit code of the |
|
|||
1757 | subprocess.""" |
|
|||
1758 | return _locksub( |
|
|||
1759 | repo, repo.currentwlock(), b'HG_WLOCK_LOCKER', cmd, *args, **kwargs |
|
|||
1760 | ) |
|
|||
1761 |
|
||||
1762 |
|
||||
1763 | class progress(object): |
|
1740 | class progress(object): | |
1764 | def __init__(self, ui, updatebar, topic, unit=b"", total=None): |
|
1741 | def __init__(self, ui, updatebar, topic, unit=b"", total=None): | |
1765 | self.ui = ui |
|
1742 | self.ui = ui |
@@ -169,121 +169,6 b' class testlock(unittest.TestCase):' | |||||
169 | state.assertpostreleasecalled(True) |
|
169 | state.assertpostreleasecalled(True) | |
170 | state.assertlockexists(False) |
|
170 | state.assertlockexists(False) | |
171 |
|
171 | |||
172 | def testinheritlock(self): |
|
|||
173 | d = tempfile.mkdtemp(dir=encoding.getcwd()) |
|
|||
174 | parentstate = teststate(self, d) |
|
|||
175 | parentlock = parentstate.makelock() |
|
|||
176 | parentstate.assertacquirecalled(True) |
|
|||
177 |
|
||||
178 | # set up lock inheritance |
|
|||
179 | with parentlock.inherit() as lockname: |
|
|||
180 | parentstate.assertreleasecalled(True) |
|
|||
181 | parentstate.assertpostreleasecalled(False) |
|
|||
182 | parentstate.assertlockexists(True) |
|
|||
183 |
|
||||
184 | childstate = teststate(self, d, pidoffset=1) |
|
|||
185 | childlock = childstate.makelock(parentlock=lockname) |
|
|||
186 | childstate.assertacquirecalled(True) |
|
|||
187 |
|
||||
188 | childlock.release() |
|
|||
189 | childstate.assertreleasecalled(True) |
|
|||
190 | childstate.assertpostreleasecalled(False) |
|
|||
191 | childstate.assertlockexists(True) |
|
|||
192 |
|
||||
193 | parentstate.resetacquirefn() |
|
|||
194 |
|
||||
195 | parentstate.assertacquirecalled(True) |
|
|||
196 |
|
||||
197 | parentlock.release() |
|
|||
198 | parentstate.assertreleasecalled(True) |
|
|||
199 | parentstate.assertpostreleasecalled(True) |
|
|||
200 | parentstate.assertlockexists(False) |
|
|||
201 |
|
||||
202 | def testmultilock(self): |
|
|||
203 | d = tempfile.mkdtemp(dir=encoding.getcwd()) |
|
|||
204 | state0 = teststate(self, d) |
|
|||
205 | lock0 = state0.makelock() |
|
|||
206 | state0.assertacquirecalled(True) |
|
|||
207 |
|
||||
208 | with lock0.inherit() as lock0name: |
|
|||
209 | state0.assertreleasecalled(True) |
|
|||
210 | state0.assertpostreleasecalled(False) |
|
|||
211 | state0.assertlockexists(True) |
|
|||
212 |
|
||||
213 | state1 = teststate(self, d, pidoffset=1) |
|
|||
214 | lock1 = state1.makelock(parentlock=lock0name) |
|
|||
215 | state1.assertacquirecalled(True) |
|
|||
216 |
|
||||
217 | # from within lock1, acquire another lock |
|
|||
218 | with lock1.inherit() as lock1name: |
|
|||
219 | # since the file on disk is lock0's this should have the same |
|
|||
220 | # name |
|
|||
221 | self.assertEqual(lock0name, lock1name) |
|
|||
222 |
|
||||
223 | state2 = teststate(self, d, pidoffset=2) |
|
|||
224 | lock2 = state2.makelock(parentlock=lock1name) |
|
|||
225 | state2.assertacquirecalled(True) |
|
|||
226 |
|
||||
227 | lock2.release() |
|
|||
228 | state2.assertreleasecalled(True) |
|
|||
229 | state2.assertpostreleasecalled(False) |
|
|||
230 | state2.assertlockexists(True) |
|
|||
231 |
|
||||
232 | state1.resetacquirefn() |
|
|||
233 |
|
||||
234 | state1.assertacquirecalled(True) |
|
|||
235 |
|
||||
236 | lock1.release() |
|
|||
237 | state1.assertreleasecalled(True) |
|
|||
238 | state1.assertpostreleasecalled(False) |
|
|||
239 | state1.assertlockexists(True) |
|
|||
240 |
|
||||
241 | lock0.release() |
|
|||
242 |
|
||||
243 | def testinheritlockfork(self): |
|
|||
244 | d = tempfile.mkdtemp(dir=encoding.getcwd()) |
|
|||
245 | parentstate = teststate(self, d) |
|
|||
246 | parentlock = parentstate.makelock() |
|
|||
247 | parentstate.assertacquirecalled(True) |
|
|||
248 |
|
||||
249 | # set up lock inheritance |
|
|||
250 | with parentlock.inherit() as lockname: |
|
|||
251 | childstate = teststate(self, d, pidoffset=1) |
|
|||
252 | childlock = childstate.makelock(parentlock=lockname) |
|
|||
253 | childstate.assertacquirecalled(True) |
|
|||
254 |
|
||||
255 | # fork the child lock |
|
|||
256 | forkchildlock = copy.copy(childlock) |
|
|||
257 | forkchildlock._pidoffset += 1 |
|
|||
258 | forkchildlock.release() |
|
|||
259 | childstate.assertreleasecalled(False) |
|
|||
260 | childstate.assertpostreleasecalled(False) |
|
|||
261 | childstate.assertlockexists(True) |
|
|||
262 |
|
||||
263 | # release the child lock |
|
|||
264 | childlock.release() |
|
|||
265 | childstate.assertreleasecalled(True) |
|
|||
266 | childstate.assertpostreleasecalled(False) |
|
|||
267 | childstate.assertlockexists(True) |
|
|||
268 |
|
||||
269 | parentlock.release() |
|
|||
270 |
|
||||
271 | def testinheritcheck(self): |
|
|||
272 | d = tempfile.mkdtemp(dir=encoding.getcwd()) |
|
|||
273 | state = teststate(self, d) |
|
|||
274 |
|
||||
275 | def check(): |
|
|||
276 | raise error.LockInheritanceContractViolation('check failed') |
|
|||
277 |
|
||||
278 | lock = state.makelock(inheritchecker=check) |
|
|||
279 | state.assertacquirecalled(True) |
|
|||
280 |
|
||||
281 | with self.assertRaises(error.LockInheritanceContractViolation): |
|
|||
282 | with lock.inherit(): |
|
|||
283 | pass |
|
|||
284 |
|
||||
285 | lock.release() |
|
|||
286 |
|
||||
287 | def testfrequentlockunlock(self): |
|
172 | def testfrequentlockunlock(self): | |
288 | """This tests whether lock acquisition fails as expected, even if |
|
173 | """This tests whether lock acquisition fails as expected, even if | |
289 | (1) lock can't be acquired (makelock fails by EEXIST), and |
|
174 | (1) lock can't be acquired (makelock fails by EEXIST), and |
General Comments 0
You need to be logged in to leave comments.
Login now