Chromium Code Reviews| Index: git_cache.py |
| diff --git a/git_cache.py b/git_cache.py |
| index 9f835b5ffc144d8c6753c70585c09cea2250002b..1665156928c5955f8255f292c98acc3e434642d9 100755 |
| --- a/git_cache.py |
| +++ b/git_cache.py |
| @@ -44,8 +44,9 @@ class RefsHeadsFailedToFetch(Exception): |
| class Lockfile(object): |
| """Class to represent a cross-platform process-specific lockfile.""" |
| - def __init__(self, path): |
| + def __init__(self, path, timeout=0): |
| self.path = os.path.abspath(path) |
| + self.timeout = timeout |
| self.lockfile = self.path + ".lock" |
| self.pid = os.getpid() |
| @@ -91,16 +92,24 @@ class Lockfile(object): |
| def lock(self): |
| """Acquire the lock. |
| - Note: This is a NON-BLOCKING FAIL-FAST operation. |
| - Do. Or do not. There is no try. |
| + This will block with a deadline of self.timeout seconds. |
| + If self.timeout is zero, a NON-BLOCKING FAIL-FAST operation. |
| """ |
| - try: |
| - self._make_lockfile() |
| - except OSError as e: |
| - if e.errno == errno.EEXIST: |
| - raise LockError("%s is already locked" % self.path) |
| - else: |
| - raise LockError("Failed to create %s (err %s)" % (self.path, e.errno)) |
| + elapsed = 0 |
| + while True: |
| + try: |
| + self._make_lockfile() |
| + return |
| + except OSError as e: |
| + if elapsed < self.timeout: |
| + sleep_time = min(3, self.timeout - elapsed) |
| + elapsed += sleep_time |
|
tandrii(chromium)
2016/02/02 22:01:00
maybe also print here that it's waiting on a lock?
szager1
2016/02/02 22:33:11
Done.
|
| + time.sleep(sleep_time) |
| + continue |
| + if e.errno == errno.EEXIST: |
| + raise LockError("%s is already locked" % self.path) |
| + else: |
| + raise LockError("Failed to create %s (err %s)" % (self.path, e.errno)) |
| def unlock(self): |
| """Release the lock.""" |
| @@ -401,13 +410,13 @@ class Mirror(object): |
| logging.warn('Fetch of %s failed' % spec) |
| def populate(self, depth=None, shallow=False, bootstrap=False, |
| - verbose=False, ignore_lock=False): |
| + verbose=False, ignore_lock=False, lock_timeout=0): |
| assert self.GetCachePath() |
| if shallow and not depth: |
| depth = 10000 |
| gclient_utils.safe_makedirs(self.GetCachePath()) |
| - lockfile = Lockfile(self.mirror_path) |
| + lockfile = Lockfile(self.mirror_path, lock_timeout) |
| if not ignore_lock: |
| lockfile.lock() |
| @@ -582,6 +591,7 @@ def CMDpopulate(parser, args): |
| 'shallow': options.shallow, |
| 'bootstrap': not options.no_bootstrap, |
| 'ignore_lock': options.ignore_locks, |
| + 'lock_timeout': options.timeout, |
| } |
| if options.depth: |
| kwargs['depth'] = options.depth |
| @@ -625,7 +635,8 @@ def CMDfetch(parser, args): |
| git_dir = os.path.abspath(git_dir) |
| if git_dir.startswith(cachepath): |
| mirror = Mirror.FromPath(git_dir) |
| - mirror.populate(bootstrap=not options.no_bootstrap) |
| + mirror.populate( |
| + bootstrap=not options.no_bootstrap, lock_timeout=options.timeout) |
| return 0 |
| for remote in remotes: |
| remote_url = subprocess.check_output( |
| @@ -634,7 +645,8 @@ def CMDfetch(parser, args): |
| mirror = Mirror.FromPath(remote_url) |
| mirror.print = lambda *args: None |
| print('Updating git cache...') |
| - mirror.populate(bootstrap=not options.no_bootstrap) |
| + mirror.populate( |
| + bootstrap=not options.no_bootstrap, lock_timeout=options.timeout) |
| subprocess.check_call([Mirror.git_exe, 'fetch', remote]) |
| return 0 |
| @@ -683,6 +695,8 @@ class OptionParser(optparse.OptionParser): |
| help='Increase verbosity (can be passed multiple times)') |
| self.add_option('-q', '--quiet', action='store_true', |
| help='Suppress all extraneous output') |
| + self.add_option('--timeout', type='int', default=0, |
| + help='Timeout for acquiring cache lock, in seconds') |
| def parse_args(self, args=None, values=None): |
| options, args = optparse.OptionParser.parse_args(self, args, values) |