Revision aa74b828

b/lib/utils.py
1259 1259
      self.fd.close()
1260 1260
      self.fd = None
1261 1261

  
1262
  def _flock(self, flag, blocking, errmsg):
1262
  def _flock(self, flag, blocking, timeout, errmsg):
1263
    """Wrapper for fcntl.flock.
1264

  
1265
    @type flag: int
1266
    @param flag: Operation flag
1267
    @type blocking: bool
1268
    @param blocking: Whether the operation should be done in blocking mode.
1269
    @type timeout: None or float
1270
    @param timeout: For how long the operation should be retried (implies
1271
                    non-blocking mode).
1272
    @type errmsg: string
1273
    @param errmsg: Error message in case operation fails.
1274

  
1275
    """
1263 1276
    assert self.fd, "Lock was closed"
1277
    assert timeout is None or timeout >= 0, \
1278
      "If specified, timeout must be positive"
1264 1279

  
1265
    if not blocking:
1280
    if timeout is not None:
1266 1281
      flag |= fcntl.LOCK_NB
1282
      timeout_end = time.time() + timeout
1267 1283

  
1268
    try:
1269
      fcntl.flock(self.fd, flag)
1270
    except IOError, err:
1271
      if err.errno in (errno.EAGAIN, ):
1272
        raise errors.LockError(errmsg)
1273
      else:
1274
        logging.exception("fcntl.flock failed")
1275
        raise
1276

  
1277
  def Exclusive(self, blocking=False):
1284
    # Blocking doesn't have effect with timeout
1285
    elif not blocking:
1286
      flag |= fcntl.LOCK_NB
1287
      timeout_end = None
1288

  
1289
    retry = True
1290
    while retry:
1291
      try:
1292
        fcntl.flock(self.fd, flag)
1293
        retry = False
1294
      except IOError, err:
1295
        if err.errno in (errno.EAGAIN, ):
1296
          if timeout_end is not None and time.time() < timeout_end:
1297
            # Wait before trying again
1298
            time.sleep(max(0.1, min(1.0, timeout)))
1299
          else:
1300
            raise errors.LockError(errmsg)
1301
        else:
1302
          logging.exception("fcntl.flock failed")
1303
          raise
1304

  
1305
  def Exclusive(self, blocking=False, timeout=None):
1278 1306
    """Locks the file in exclusive mode.
1279 1307

  
1280 1308
    """
1281
    self._flock(fcntl.LOCK_EX, blocking,
1309
    self._flock(fcntl.LOCK_EX, blocking, timeout,
1282 1310
                "Failed to lock %s in exclusive mode" % self.filename)
1283 1311

  
1284
  def Shared(self, blocking=False):
1312
  def Shared(self, blocking=False, timeout=None):
1285 1313
    """Locks the file in shared mode.
1286 1314

  
1287 1315
    """
1288
    self._flock(fcntl.LOCK_SH, blocking,
1316
    self._flock(fcntl.LOCK_SH, blocking, timeout,
1289 1317
                "Failed to lock %s in shared mode" % self.filename)
1290 1318

  
1291
  def Unlock(self, blocking=True):
1319
  def Unlock(self, blocking=True, timeout=None):
1292 1320
    """Unlocks the file.
1293 1321

  
1294 1322
    According to "man flock", unlocking can also be a nonblocking operation:
......
1296 1324
    operations"
1297 1325

  
1298 1326
    """
1299
    self._flock(fcntl.LOCK_UN, blocking,
1327
    self._flock(fcntl.LOCK_UN, blocking, timeout,
1300 1328
                "Failed to unlock %s" % self.filename)
1301 1329

  
1302 1330

  

Also available in: Unified diff