Skip to content

Commit 9db367a

Browse files
radeusgdkodek16
authored andcommitted
Changed flock to active-waiting and increased the timeout. (#60)
* Changed flock to active-waiting and increased the timeout. * Added EWOULDBLOCK just to be sure. * Fixed tests? * Changed waiting for lock logic.
1 parent 4e15c8f commit 9db367a

File tree

2 files changed

+38
-3
lines changed

2 files changed

+38
-3
lines changed

filetracker/servers/run.py

+1
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,7 @@ def main(args=None):
149149
|worker_class = 'gevent'
150150
|raw_env = ['FILETRACKER_DIR={filetracker_dir}',
151151
| 'FILETRACKER_FALLBACK_URL={fallback_url}']
152+
|timeout = 5*60
152153
|
153154
|logconfig_dict = {logconfig_dict}
154155
|

filetracker/servers/storage.py

+37-3
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
import email.utils
3131
import errno
3232
import fcntl
33+
import gevent
3334
import gzip
3435
import logging
3536
import os
@@ -44,13 +45,24 @@
4445
from filetracker.utils import file_digest
4546

4647

48+
_LOCK_RETRIES = 20
49+
_LOCK_SLEEP_TIME_S = 1
50+
51+
4752
logger = logging.getLogger(__name__)
4853

4954

5055
class FiletrackerFileNotFoundError(Exception):
5156
pass
5257

5358

59+
class ConcurrentModificationError(Exception):
60+
"""Raised after acquiring lock failed multiple times."""
61+
def __init__(self, lock_name):
62+
message = 'Failed to acquire lock: {}'.format(lock_name)
63+
super(ConcurrentModificationError, self).__init__(self, message)
64+
65+
5466
class FileStorage(object):
5567
"""Manages the whole file storage."""
5668

@@ -422,10 +434,32 @@ def _exclusive_lock(path):
422434
fd = os.open(path, os.O_WRONLY | os.O_CREAT, 0o600)
423435

424436
try:
425-
fcntl.flock(fd, fcntl.LOCK_EX)
426-
yield
437+
retries_left = _LOCK_RETRIES
438+
success = False
439+
440+
while retries_left > 0:
441+
# try to acquire the lock in a loop
442+
# because gevent doesn't treat flock as IO,
443+
# so waiting here without yielding would get the worker killed
444+
try:
445+
fcntl.flock(fd, fcntl.LOCK_EX | fcntl.LOCK_NB)
446+
success = True
447+
break
448+
except IOError as e:
449+
if e.errno in [errno.EAGAIN, errno.EWOULDBLOCK]:
450+
# This yields execution to other green threads.
451+
gevent.sleep(_LOCK_SLEEP_TIME_S)
452+
retries_left -= 1
453+
else:
454+
raise
455+
456+
if success:
457+
yield
458+
else:
459+
raise ConcurrentModificationError(path)
427460
finally:
428-
fcntl.flock(fd, fcntl.LOCK_UN)
461+
if success:
462+
fcntl.flock(fd, fcntl.LOCK_UN)
429463
os.close(fd)
430464

431465

0 commit comments

Comments
 (0)