util/fscache: add trace hooks

Add trace-hooks to the FsCache._atomic_open() helper, including a
primitive trace-infrastructure. They allow interrupting cache operation
and running arbitrary code.

The trace-hooks will be used by the test-suite to trigger the races we
want to protect against. During runtime, the traces should not be used
and thus will always be `None`.

This is a very primitive way to hook into the runtime execution and test
the atomicity of the operations. However, it is simple enough for our
tests and avoids pulling in huge tracing suites.

Signed-off-by: David Rheinsberg <david.rheinsberg@gmail.com>
This commit is contained in:
David Rheinsberg 2022-12-20 09:51:43 +01:00
parent 290efe50fe
commit 51d0f60843

View file

@ -211,6 +211,7 @@ class FsCache(contextlib.AbstractContextManager, os.PathLike):
# constant properties
_appid: str
_tracers: Dict[str, Any]
_path_cache: Any
# context-manager properties
@ -240,6 +241,7 @@ class FsCache(contextlib.AbstractContextManager, os.PathLike):
"""
self._appid = appid
self._tracers = {}
self._path_cache = os.fspath(path_cache)
self._active = False
@ -248,6 +250,26 @@ class FsCache(contextlib.AbstractContextManager, os.PathLike):
self._info = FsCacheInfo()
self._info_maximum_size = 0
def _trace(self, trace: str):
"""Trace execution
Execute registered trace-hooks for the given trace string. This allows
tests to register callbacks that are executed at runtime at a specific
location in the code. During normal operation, no such hooks should be
used.
The trace-hooks are used to trigger race-conditions during tests and
verify they are handled gracefully.
Parameters:
-----------
trace
The trace-hook to run.
"""
if trace in self._tracers:
self._tracers[trace]()
@staticmethod
def _calculate_size(path_target: str) -> int:
"""Calculate total size of a directory tree
@ -347,7 +369,9 @@ class FsCache(contextlib.AbstractContextManager, os.PathLike):
if write:
flags = flags | os.O_RDWR
lock = linux.fcntl.F_WRLCK
self._trace("_atomic_open:open")
fd = os.open(path, flags, 0o644)
self._trace("_atomic_open:lock")
linux.fcntl_flock(fd, lock, wait=wait)
# The file might have been replaced between opening it and