diff --git a/cuda_core/tests/test_program_cache_multiprocess.py b/cuda_core/tests/test_program_cache_multiprocess.py index f73256266da..329229425ef 100644 --- a/cuda_core/tests/test_program_cache_multiprocess.py +++ b/cuda_core/tests/test_program_cache_multiprocess.py @@ -123,70 +123,3 @@ def test_concurrent_reader_never_sees_torn_file(tmp_path): # mismatches. assert hits == 200 assert mismatches == 0 - - -def _worker_size_cap_writer(root: str, prefix: bytes, payload: bytes, count: int, max_size_bytes: int) -> None: - """Hammer a small-cap cache with churning writes so eviction fires often.""" - from cuda.core.utils import FileStreamProgramCache - - with FileStreamProgramCache(root, max_size_bytes=max_size_bytes) as cache: - for i in range(count): - cache[prefix + str(i).encode()] = payload - - -def _worker_size_cap_rewriter(root: str, key: bytes, payload: bytes, max_size_bytes: int, done_event) -> None: - """Repeatedly rewrite ``key`` with a fresh value until ``done_event`` fires.""" - from cuda.core.utils import FileStreamProgramCache - - with FileStreamProgramCache(root, max_size_bytes=max_size_bytes) as cache: - i = 0 - while not done_event.is_set(): - cache[key] = payload + str(i).encode() - i += 1 - - -def test_concurrent_eviction_does_not_delete_replaced_file(tmp_path): - """Eviction is stat-guarded: while one process is evicting an entry to - bring the cache under its size cap, another process may have already - ``os.replace``-d a fresh value into the same path. The evictor must - refuse to unlink in that case, otherwise the racing rewriter's - just-committed entry vanishes. - - The rewriter does NO post-race uncontested write -- the entry's - survival has to come from the in-race rewrites being preserved by - the stat-guarded eviction path.""" - from cuda.core.utils import FileStreamProgramCache - - root = str(tmp_path / "fc") - payload = b"X" * 2000 - cap = 5000 # fits 2 raw 2000B entries; the third write triggers eviction - - ctx = _mp.get_context("spawn") - done_event = ctx.Event() - rewriter = ctx.Process( - target=_worker_size_cap_rewriter, - args=(root, b"survivor", payload, cap, done_event), - ) - # Churning writer creates new keys faster than eviction can drain them, - # forcing _enforce_size_cap to consider 'survivor' for eviction many times. - churner = ctx.Process( - target=_worker_size_cap_writer, - args=(root, b"churn-", payload, 80, cap), - ) - rewriter.start() - churner.start() - churner.join(timeout=60) - done_event.set() - rewriter.join(timeout=60) - assert rewriter.exitcode == 0 - assert churner.exitcode == 0 - - # If eviction blindly unlinked replaced files, the rewriter's last - # in-race write would be gone -- there is no post-race write to mask - # the failure. The value must also start with ``payload`` (not a - # ``churn-`` value) because each rewriter iteration writes - # ``payload + str(i).encode()``. - with FileStreamProgramCache(root, max_size_bytes=cap) as cache: - got = cache.get(b"survivor") - assert got is not None, "rewriter's entry was evicted by racing churner" - assert got.startswith(payload), f"survivor value not from rewriter: {got[:32]!r}..."