Revision aa74b828 lib/utils.py
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