I'm trying to implement thread- and multiprocess-safe disk cache for small application. It is only required to run on modern linux distributions, no compatibility with Windows or OS X is required.
Here is the code:
class LockedOpen(object):
READ = 0
WRITE = 1
def __init__(self, filename, mode=READ, block=True):
self._filename = filename
if mode == LockedOpen.READ:
self._open_mode = os.O_RDONLY
self._lock_op = fcntl.LOCK_SH
self._open_mode_str = 'rb'
else:
self._open_mode = os.O_WRONLY | os.O_CREAT | os.O_TRUNC
self._lock_op = fcntl.LOCK_EX
self._open_mode_str = 'wb'
if not block:
self._lock_op = self._lock_op | fcntl.LOCK_NB
def __enter__(self,):
self._fd = os.open(self._filename, self._open_mode)
fcntl.flock(self._fd, self._lock_op)
self._file_obj = os.fdopen(self._fd, self._open_mode_str)
return self._file_obj
def __exit__(self, exc_type, exc_val, exc_tb):
self._file_obj.flush()
os.fdatasync(self._fd)
fcntl.flock(self._fd, fcntl.LOCK_UN)
self._file_obj.close()
class DiskCache(object):
def __init__(self, dirname):
self._dir = dirname
def _filename_from_key(self, key):
return os.path.join(self._dir, key)
def put(self, key, value):
with LockedOpen(self._filename_from_key(key), LockedOpen.WRITE) as f:
f.write(value)
def get(self, key):
with LockedOpen(self._filename_from_key(key)) as f:
return f.read()
def delete(self, key):
os.unlink(self._filename_from_key(key))
The question is, am I doing this right? Are there any errors/caveats/implications with this code that I should know about? Any advice regarding performance is welcome as well.
Thanks~