# HG changeset patch # User Boris Feld # Date 1512005789 18000 # Node ID 1b758105b5c73634f203ac31f8e1b70a79cf8796 # Parent d210723b73e503f14d9c72b9310b95a7de5ed48f lock: add a trylock method handling the timeout and messaging logic We are about to make the messages around lock more flexible. We move all the currently logic into a function in the lock module. We'll update the message scheme in the next changeset. diff -r d210723b73e5 -r 1b758105b5c7 mercurial/localrepo.py --- a/mercurial/localrepo.py Wed Nov 29 21:00:02 2017 -0500 +++ b/mercurial/localrepo.py Wed Nov 29 20:36:29 2017 -0500 @@ -1592,29 +1592,16 @@ # determine whether it can be inherited if parentenvvar is not None: parentlock = encoding.environ.get(parentenvvar) - try: - l = lockmod.lock(vfs, lockname, 0, releasefn=releasefn, - acquirefn=acquirefn, desc=desc, - inheritchecker=inheritchecker, - parentlock=parentlock) - except error.LockHeld as inst: - if not wait: - raise - # show more details for new-style locks - if ':' in inst.locker: - host, pid = inst.locker.split(":", 1) - self.ui.warn( - _("waiting for lock on %s held by process %r " - "on host %r\n") % (desc, pid, host)) - else: - self.ui.warn(_("waiting for lock on %s held by %r\n") % - (desc, inst.locker)) - # default to 600 seconds timeout - l = lockmod.lock(vfs, lockname, - self.ui.configint("ui", "timeout"), - releasefn=releasefn, acquirefn=acquirefn, - desc=desc) - self.ui.warn(_("got lock after %s seconds\n") % l.delay) + + timeout = 0 + if wait: + timeout = self.ui.configint("ui", "timeout") + + l = lockmod.trylock(self.ui, vfs, lockname, timeout, + releasefn=releasefn, + acquirefn=acquirefn, desc=desc, + inheritchecker=inheritchecker, + parentlock=parentlock) return l def _afterlock(self, callback): diff -r d210723b73e5 -r 1b758105b5c7 mercurial/lock.py --- a/mercurial/lock.py Wed Nov 29 21:00:02 2017 -0500 +++ b/mercurial/lock.py Wed Nov 29 20:36:29 2017 -0500 @@ -14,6 +14,8 @@ import time import warnings +from .i18n import _ + from . import ( encoding, error, @@ -39,6 +41,50 @@ raise return result +def trylock(ui, vfs, lockname, timeout, *args, **kwargs): + """return an acquired lock or raise an a LockHeld exception + + This function is responsible to issue warnings about the held lock while + trying to acquires it.""" + + def printwarning(printer, locker): + """issue the usual "waiting on lock" message through any channel""" + # show more details for new-style locks + if ':' in locker: + host, pid = locker.split(":", 1) + msg = _("waiting for lock on %s held by process %r " + "on host %r\n") % (l.desc, pid, host) + else: + msg = _("waiting for lock on %s held by %r\n") % (l.desc, locker) + printer(msg) + + l = lock(vfs, lockname, 0, *args, dolock=False, **kwargs) + + warningidx = 0 + if not timeout: + warningidx = -1 + + delay = 0 + while True: + try: + l._trylock() + break + except error.LockHeld as inst: + if delay == warningidx: + printwarning(ui.warn, inst.locker) + if timeout <= delay: + raise error.LockHeld(errno.ETIMEDOUT, inst.filename, + l.desc, inst.locker) + time.sleep(1) + delay += 1 + + l.delay = delay + if l.delay: + ui.warn(_("got lock after %s seconds\n") % l.delay) + if l.acquirefn: + l.acquirefn() + return l + class lock(object): '''An advisory lock held by one process to control access to a set of files. Non-cooperating processes or incorrectly written scripts @@ -60,7 +106,8 @@ _host = None def __init__(self, vfs, file, timeout=-1, releasefn=None, acquirefn=None, - desc=None, inheritchecker=None, parentlock=None): + desc=None, inheritchecker=None, parentlock=None, + dolock=True): self.vfs = vfs self.f = file self.held = 0 @@ -74,9 +121,10 @@ self._inherited = False self.postrelease = [] self.pid = self._getpid() - self.delay = self.lock() - if self.acquirefn: - self.acquirefn() + if dolock: + self.delay = self.lock() + if self.acquirefn: + self.acquirefn() def __enter__(self): return self