Only one lock file per process (lockf() works now)

lockf() is more portable than flock()
This commit is contained in:
Unrud 2016-05-22 09:47:36 +02:00
parent eb9218354c
commit 49bc0728e3

View File

@ -518,6 +518,7 @@ class Collection(BaseCollection):
return "" return ""
_lock = threading.Condition() _lock = threading.Condition()
_lock_file = None
_readers = 0 _readers = 0
_writer = False _writer = False
@ -542,40 +543,38 @@ class Collection(BaseCollection):
cls._lock.notify() cls._lock.notify()
else: else:
cls._writer = True cls._writer = True
folder = os.path.expanduser( if not cls._lock_file:
cls.configuration.get("storage", "filesystem_folder")) folder = os.path.expanduser(
if not os.path.exists(folder): cls.configuration.get("storage", "filesystem_folder"))
os.makedirs(folder, exist_ok=True) if not os.path.exists(folder):
lock_path = os.path.join(folder, "Radicale.lock") os.makedirs(folder, exist_ok=True)
lock_file = open(lock_path, "w+") lock_path = os.path.join(folder, "Radicale.lock")
# set access rights to a necessary minimum to prevent locking by cls._lock_file = open(lock_path, "w+")
# arbitrary users # set access rights to a necessary minimum to prevent locking
try: # by arbitrary users
os.chmod(lock_path, stat.S_IWUSR | stat.S_IRUSR) try:
except OSError: os.chmod(lock_path, stat.S_IWUSR | stat.S_IRUSR)
cls.logger.debug("Failed to set permissions on lock file") except OSError:
if os.name == "nt": cls.logger.debug("Failed to set permissions on lock file")
handle = msvcrt.get_osfhandle(lock_file.fileno()) if os.name == "nt":
flags = LOCKFILE_EXCLUSIVE_LOCK if mode == "w" else 0 handle = msvcrt.get_osfhandle(cls._lock_file.fileno())
overlapped = Overlapped() flags = LOCKFILE_EXCLUSIVE_LOCK if mode == "w" else 0
if not lock_file_ex(handle, flags, 0, 1, 0, overlapped): overlapped = Overlapped()
cls.logger.debug("Locking not supported") if not lock_file_ex(handle, flags, 0, 1, 0, overlapped):
elif os.name == "posix": cls.logger.debug("Locking not supported")
operation = fcntl.LOCK_EX if mode == "w" else fcntl.LOCK_SH elif os.name == "posix":
# According to documentation flock() is emulated with fcntl() on _cmd = fcntl.LOCK_EX if mode == "w" else fcntl.LOCK_SH
# some platforms. fcntl() locks are not associated with an open try:
# file descriptor. The same file can be locked multiple times fcntl.lockf(cls._lock_file.fileno(), _cmd)
# within the same process and if any fd of the file is closed, except OSError:
# all locks are released. cls.logger.debug("Locking not supported")
# flock() does not work on NFS shares.
try:
fcntl.flock(lock_file.fileno(), operation)
except OSError:
cls.logger.debug("Locking not supported")
yield yield
with cls._lock: with cls._lock:
if mode == "r": if mode == "r":
cls._readers -= 1 cls._readers -= 1
else: else:
cls._writer = False cls._writer = False
if cls._readers == 0:
cls._lock_file.close()
cls._lock_file = None
cls._lock.notify() cls._lock.notify()