fix(conftest): use synchronization locks for setup_database

We were running into data race issues where the `fn.is_file()`
check would occur twice before writing the file in the `else`
clause. For this reason, a new aurweb.lock.Lock class has been
added which doubles as a thread and process lock. We can use
this elsewhere in the future, but we are also able to use it
to solve this kind of data race issue.

That being said, we still need the lock file state to tell us
when the first caller acquired the lock.

Signed-off-by: Kevin Morris <kevr@0cost.org>
This commit is contained in:
Kevin Morris 2021-11-22 20:06:50 -08:00
parent 155aa47a1a
commit 4b0cb0721d
No known key found for this signature in database
GPG key ID: F7E46DED420788F3
3 changed files with 95 additions and 24 deletions

View file

@ -0,0 +1,32 @@
import hashlib
import os
from typing import Callable
from posix_ipc import O_CREAT, Semaphore
from aurweb import logging
logger = logging.get_logger(__name__)
def default_on_create(path):
logger.info(f"Filelock at {path} acquired.")
class FileLock:
def __init__(self, tmpdir, name: str):
self.root = tmpdir
self.path = str(self.root / name)
self._file = str(self.root / (f"{name}.1"))
def lock(self, on_create: Callable = default_on_create):
hash = hashlib.sha1(self.path.encode()).hexdigest()
with Semaphore(f"/{hash}-lock", flags=O_CREAT, initial_value=1):
retval = os.path.exists(self._file)
if not retval:
with open(self._file, "w") as f:
f.write("1")
on_create(self.path)
return retval