Revision cc4c9b91

b/lib/utils.py
2486 2486
    assert self.fd, "Lock was closed"
2487 2487
    assert timeout is None or timeout >= 0, \
2488 2488
      "If specified, timeout must be positive"
2489
    assert not (flag & fcntl.LOCK_NB), "LOCK_NB must not be set"
2489 2490

  
2490
    if timeout is not None:
2491
    # When a timeout is used, LOCK_NB must always be set
2492
    if not (timeout is None and blocking):
2491 2493
      flag |= fcntl.LOCK_NB
2492
      timeout_end = time.time() + timeout
2493 2494

  
2494
    # Blocking doesn't have effect with timeout
2495
    elif not blocking:
2496
      flag |= fcntl.LOCK_NB
2497
      timeout_end = None
2495
    if timeout is None:
2496
      self._Lock(self.fd, flag, timeout)
2497
    else:
2498
      try:
2499
        Retry(self._Lock, (0.1, 1.2, 1.0), timeout,
2500
              args=(self.fd, flag, timeout))
2501
      except RetryTimeout:
2502
        raise errors.LockError(errmsg)
2498 2503

  
2499
    # TODO: Convert to utils.Retry
2504
  @staticmethod
2505
  def _Lock(fd, flag, timeout):
2506
    try:
2507
      fcntl.flock(fd, flag)
2508
    except IOError, err:
2509
      if timeout is not None and err.errno == errno.EAGAIN:
2510
        raise RetryAgain()
2500 2511

  
2501
    retry = True
2502
    while retry:
2503
      try:
2504
        fcntl.flock(self.fd, flag)
2505
        retry = False
2506
      except IOError, err:
2507
        if err.errno in (errno.EAGAIN, ):
2508
          if timeout_end is not None and time.time() < timeout_end:
2509
            # Wait before trying again
2510
            time.sleep(max(0.1, min(1.0, timeout)))
2511
          else:
2512
            raise errors.LockError(errmsg)
2513
        else:
2514
          logging.exception("fcntl.flock failed")
2515
          raise
2512
      logging.exception("fcntl.flock failed")
2513
      raise
2516 2514

  
2517 2515
  def Exclusive(self, blocking=False, timeout=None):
2518 2516
    """Locks the file in exclusive mode.

Also available in: Unified diff