##// END OF EJS Templates
locking: remove support for inheriting locks in subprocess...
Martin von Zweigbergk -
r46092:9b16bb3b default
parent child Browse files
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 if not self._parentheld:
382 try:
429 try:
383 self.vfs.unlink(self.f)
430 self.vfs.unlink(self.f)
384 except OSError:
431 except OSError:
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 if not self._parentheld:
388 for callback in self.postrelease:
436 for callback in self.postrelease:
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